trueicon 0.1.0 → 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/README.md CHANGED
@@ -1,6 +1,11 @@
1
1
  # TrueIcon
2
2
 
3
- TrueIcon is an [MCP](https://modelcontextprotocol.io) server that gives AI coding assistants exact, version-correct icon references. Your assistant searches the icon packages your project actually uses (`lucide-react`, `react-icons`, `@heroicons/react`) and gets back real icon names, import paths and a ready-to-paste `import` line.
3
+ [![npm](https://img.shields.io/npm/v/trueicon?style=flat-square)](https://www.npmjs.com/package/trueicon)
4
+ [![Install in VS Code](https://img.shields.io/badge/VS_Code-Install_Server-0098FF?style=flat-square&logo=visualstudiocode&logoColor=white)](https://insiders.vscode.dev/redirect/mcp/install?name=trueicon&config=%7B%22command%22%3A%22npx%22%2C%22args%22%3A%5B%22-y%22%2C%22trueicon%22%5D%2C%22env%22%3A%7B%22TRUEICON_PROJECT_DIR%22%3A%22%24%7BworkspaceFolder%7D%22%7D%7D)
5
+ [![Install in VS Code Insiders](https://img.shields.io/badge/VS_Code_Insiders-Install_Server-24bfa5?style=flat-square&logo=visualstudiocode&logoColor=white)](https://insiders.vscode.dev/redirect/mcp/install?name=trueicon&config=%7B%22command%22%3A%22npx%22%2C%22args%22%3A%5B%22-y%22%2C%22trueicon%22%5D%2C%22env%22%3A%7B%22TRUEICON_PROJECT_DIR%22%3A%22%24%7BworkspaceFolder%7D%22%7D%7D&quality=insiders)
6
+ [![Install in Cursor](https://cursor.com/deeplink/mcp-install-dark.svg)](https://cursor.com/en/install-mcp?name=trueicon&config=eyJjb21tYW5kIjoibnB4IiwiYXJncyI6WyIteSIsInRydWVpY29uIl0sImVudiI6eyJUUlVFSUNPTl9QUk9KRUNUX0RJUiI6IiR7d29ya3NwYWNlRm9sZGVyfSJ9fQ%3D%3D)
7
+
8
+ TrueIcon is an [MCP](https://modelcontextprotocol.io) server that gives AI coding assistants exact, version-correct icon references. Your assistant searches the icon packages your project actually uses (`lucide-react`, `react-icons`, `@heroicons/react`, `@phosphor-icons/react`, `@tabler/icons-react`, `iconoir-react`, `@fluentui/react-icons`, `@carbon/icons-react`, `@ant-design/icons`) and gets back real icon names, import paths and a ready-to-paste `import` line.
4
9
 
5
10
  ## Why
6
11
 
@@ -12,13 +17,19 @@ AI assistants often guess icon names. The guess can be an icon that never existe
12
17
 
13
18
  ## Supported providers
14
19
 
15
- | Provider id | npm package | Icon naming |
16
- | ------------- | ------------------ | ---------------------------------------------------------------- |
17
- | `lucide` | `lucide-react` | Lucide's file names, e.g. `trash-2` → `Trash2` |
18
- | `heroicons` | `@heroicons/react` | `<icon>-<size>-<style>`, e.g. `trash-24-outline` → `TrashIcon` |
19
- | `react-icons` | `react-icons` | `<set>-<icon>`, e.g. `fa6-beer-mug-empty` → `FaBeerMugEmpty` |
20
+ | Provider id | npm package | Icon naming |
21
+ | ------------- | ----------------------- | -------------------------------------------------------------------------------------------------------- |
22
+ | `lucide` | `lucide-react` | Lucide's file names, e.g. `trash-2` → `Trash2` |
23
+ | `heroicons` | `@heroicons/react` | `<icon>-<size>-<style>`, e.g. `trash-24-outline` → `TrashIcon` |
24
+ | `react-icons` | `react-icons` | `<set>-<icon>`, e.g. `fa6-beer-mug-empty` → `FaBeerMugEmpty` |
25
+ | `phosphor` | `@phosphor-icons/react` | `<icon>` for the regular weight, `<icon>-<weight>` otherwise, e.g. `trash-bold` → `TrashIcon` with `weight="bold"` |
26
+ | `tabler` | `@tabler/icons-react` | Tabler's icon names, e.g. `trash` → `IconTrash`, `trash-filled` → `IconTrashFilled` |
27
+ | `iconoir` | `iconoir-react` | `<icon>` for regular, `<icon>-solid` for solid, e.g. `trash-solid` → `TrashSolid` |
28
+ | `fluentui` | `@fluentui/react-icons` | `<icon>-<style>` with style `regular`, `filled` or `color`, e.g. `delete-regular` → `DeleteRegular`. Only the scalable (1em) icons are indexed, not the size-specific variants |
29
+ | `carbon` | `@carbon/icons-react` | Carbon's export names in kebab case, e.g. `trash-can` → `TrashCan`. Variants add `-filled`, `-alt` or `-color`, e.g. `accessibility-filled` → `AccessibilityFilled` |
30
+ | `antdesign` | `@ant-design/icons` | `<icon>-<theme>` with theme `outlined`, `filled` or `two-tone`, e.g. `delete-outlined` → `DeleteOutlined` |
20
31
 
21
- Tools accept either the provider id or the npm package name (`"lucide"` or `"lucide-react"`). Usage snippets are for React.
32
+ Tools accept either the provider id or the npm package name (`"lucide"` or `"lucide-react"`). Usage snippets are for React. Phosphor weights all share one component, so pass the record's `style` as the `weight` prop (e.g. `<TrashIcon weight="bold" />`); the usage snippet only shows the import.
22
33
 
23
34
  ## Install
24
35
 
@@ -33,7 +44,7 @@ npm i -g trueicon
33
44
  trueicon
34
45
  ```
35
46
 
36
- `trueicon` is a stdio MCP server. Your MCP client starts it; running it by hand only prints `trueicon: v0.1.0 running on stdio` to stderr and waits for JSON-RPC on stdin.
47
+ `trueicon` is a stdio MCP server. Your MCP client starts it; running it by hand only prints `trueicon: v0.2.0 running on stdio` to stderr and waits for JSON-RPC on stdin.
37
48
 
38
49
  ## Quick start
39
50
 
@@ -68,7 +79,7 @@ TrueIcon looks for `.iconmcp.json` in the project directory. That is `$TRUEICON_
68
79
  | Field | Type | Required | Meaning |
69
80
  | ----------------------- | ------ | -------- | ---------------------------------------------------------------------------------------- |
70
81
  | `providers` | array | yes | Icon packages the project uses. `search_icons` searches all of them by default. |
71
- | `providers[].package` | string | yes | npm package name: `lucide-react`, `react-icons` or `@heroicons/react`. |
82
+ | `providers[].package` | string | yes | npm package name: `lucide-react`, `react-icons`, `@heroicons/react`, `@phosphor-icons/react`, `@tabler/icons-react`, `iconoir-react`, `@fluentui/react-icons`, `@carbon/icons-react` or `@ant-design/icons`. |
72
83
  | `providers[].version` | string | no | Exact version or npm range. If omitted, it is read from `package.json` (see below). |
73
84
 
74
85
  - If the file is missing, no providers are configured. `search_icons` then only works when you pass `provider` explicitly, and `get_icon` still works.
@@ -148,6 +159,28 @@ Claude Desktop doesn't start servers in your project directory, so set `TRUEICON
148
159
 
149
160
  Restart Claude Desktop after editing the file.
150
161
 
162
+ ## Using it in VS Code and Cursor
163
+
164
+ Use the install badges at the top of this README. They add TrueIcon with `TRUEICON_PROJECT_DIR` set to `${workspaceFolder}`, so it searches the project you have open.
165
+
166
+ To add it by hand in VS Code, create `.vscode/mcp.json` in your project:
167
+
168
+ ```json
169
+ {
170
+ "servers": {
171
+ "trueicon": {
172
+ "command": "npx",
173
+ "args": ["-y", "trueicon"],
174
+ "env": {
175
+ "TRUEICON_PROJECT_DIR": "${workspaceFolder}"
176
+ }
177
+ }
178
+ }
179
+ }
180
+ ```
181
+
182
+ In Cursor, use the same entry under `"mcpServers"` in `.cursor/mcp.json`.
183
+
151
184
  ## Tools
152
185
 
153
186
  Every tool returns a single JSON text block. On failure, the block is `{"error": "..."}` and the MCP result is flagged with `isError: true`.
@@ -161,7 +194,7 @@ Searches the index and returns ranked matches with import statements.
161
194
  | `query` | string | yes | What the icon should depict, e.g. `"trash"` |
162
195
  | `provider` | string | no | Provider id or package. Default: every provider in `.iconmcp.json` |
163
196
  | `version` | string | no | Version or range. Default: resolved as described in [Versions](#versions) |
164
- | `style` | string | no | Exact style filter: `"outline"` or `"solid"` (lucide icons are all `outline`) |
197
+ | `style` | string | no | Exact style filter, e.g. `"outline"`, `"solid"`, `"filled"` (tabler), `"regular"` (fluentui), `"two-tone"` (antdesign) or a phosphor weight such as `"bold"`. Lucide icons are all `outline`; base carbon icons have no style |
165
198
  | `set` | string | no | Exact set filter, e.g. `"fa6"` or `"md"` for react-icons |
166
199
  | `limit` | integer | no | Maximum results, 1 to 50, default 10 |
167
200
 
@@ -194,7 +227,7 @@ How search works:
194
227
  - `provider`, `style` and `set` are exact, case-insensitive filters. They are applied before ranking.
195
228
  - Ranking uses [Fuse.js](https://www.fusejs.io/) fuzzy matching over the icon name, import name, keywords and tags. Small typos are tolerated: `"detele"` finds `Delete`.
196
229
  - `score` runs from `0` (perfect) to `1`, so lower is better. Results from several providers are merged and sorted by score.
197
- - Short keyword queries (`"trash"`, `"settings"`, `"beer"`) work best. The query is matched as one string, so a multi-word phrase such as `"trash can"` may return fewer results than its main keyword alone.
230
+ - Multi-word queries are tokenized: each word is matched on its own, only icons that match every word are kept, and they are ranked by their average score. So `"trash can"` finds `trash-can` icons. Short keyword queries (`"trash"`, `"settings"`, `"beer"`) still cast the widest net.
198
231
  - If one provider fails, for example because its version can't be resolved or the download fails, its results are skipped and a `warnings` array explains why. The other providers still return results.
199
232
 
200
233
  ### `list_providers`
@@ -210,7 +243,13 @@ Takes no arguments. Returns the providers configured in `.iconmcp.json` with the
210
243
  "registry": [
211
244
  { "id": "react-icons", "package": "react-icons", "description": "Aggregated icon sets (Font Awesome, Material, Feather, and more) as React components" },
212
245
  { "id": "lucide", "package": "lucide-react", "description": "Lucide icons as React components" },
213
- { "id": "heroicons", "package": "@heroicons/react", "description": "Heroicons by the Tailwind CSS team as React components" }
246
+ { "id": "heroicons", "package": "@heroicons/react", "description": "Heroicons by the Tailwind CSS team as React components" },
247
+ { "id": "phosphor", "package": "@phosphor-icons/react", "description": "Phosphor icons in six weights (thin, light, regular, bold, fill, duotone) as React components" },
248
+ { "id": "tabler", "package": "@tabler/icons-react", "description": "Tabler icons (outline and filled) as React components" },
249
+ { "id": "iconoir", "package": "iconoir-react", "description": "Iconoir icons (regular and solid) as React components" },
250
+ { "id": "fluentui", "package": "@fluentui/react-icons", "description": "Microsoft Fluent UI System icons (regular, filled and color) as React components" },
251
+ { "id": "carbon", "package": "@carbon/icons-react", "description": "IBM Carbon Design System icons as React components" },
252
+ { "id": "antdesign", "package": "@ant-design/icons", "description": "Ant Design icons (outlined, filled and two-tone) as React components" }
214
253
  ]
215
254
  }
216
255
  ```
@@ -321,9 +360,9 @@ CI runs lint, typecheck and tests on Node 20 and 22 for every push and pull requ
321
360
 
322
361
  1. **Register it** in `src/providers/registry.ts` with a stable `id`, the npm `package` and a short `description`.
323
362
  2. **Write an adapter** in `src/providers/adapters/<provider>.ts` that exports `parseIcons(packageDir: string): RawIcon[]` (see `src/providers/adapter.ts`). It gets the extracted package directory and returns one `RawIcon` per icon:
324
- - `name`: kebab-case and **unique within the package**, because it becomes part of the record id. Use `toKebabCase` from `adapter.ts`. If the package has variants with clashing component names, add the variant to the name, as the heroicons and react-icons adapters do.
363
+ - `name`: kebab-case and **unique within the package**, because it becomes part of the record id. Use `toKebabCase` from `adapter.ts`. If the package has variants with clashing component names, add the variant to the name, as the heroicons, react-icons, phosphor and iconoir adapters do.
325
364
  - `importName` and `importPath`: the exact export and module specifier a user would import.
326
- - `svg`: the inner SVG markup. `LiteralCursor` (`src/providers/jsLiteral.ts`) parses JS object and array literals without executing code. `toSvgAttrs` and `renderSvg` (`src/providers/svg.ts`) turn React props into SVG markup.
365
+ - `svg`: the inner SVG markup. `LiteralCursor` (`src/providers/jsLiteral.ts`) parses JS object and array literals without executing code. `toSvgAttrs` and `renderSvg` (`src/providers/svg.ts`) turn React props into SVG markup, and `parseCreateElement` reads compiled `createElement(...)` trees.
327
366
  - Optional `style`, `set`, `categories` and `tags`.
328
367
  - Put a comment at the top of the adapter describing the package's file layout, as the existing adapters do.
329
368
  3. **Wire it up** in `src/providers/adapters/index.ts` by adding it to `ADAPTERS` under the provider id.
@@ -0,0 +1,3 @@
1
+ import { type RawIcon } from "../adapter.js";
2
+ export declare function previewSvg(src: string): string;
3
+ export declare function parseIcons(packageDir: string): RawIcon[];
@@ -0,0 +1,60 @@
1
+ import { readdirSync, readFileSync } from "node:fs";
2
+ import { join } from "node:path";
3
+ import { toKebabCase } from "../adapter.js";
4
+ /*
5
+ * @ant-design/icons layout: lib/icons/<Name><Theme>.js, one CommonJS module per icon, with Theme
6
+ * one of Filled, Outlined or TwoTone (DeleteOutlined.js, DeleteTwoTone.js). The artwork itself
7
+ * lives in @ant-design/icons-svg as an abstract node tree, but every icon module carries a
8
+ * generated preview comment with the full SVG:
9
+ *
10
+ * /**![delete](data:image/svg+xml;base64,PHN2ZyB3aWR0aD0i...) *\/
11
+ *
12
+ * The preview is decoded and the root <svg> element stripped. It hardcodes the default preview
13
+ * colors (the twotone fills, for example) where the component uses currentColor and a
14
+ * configurable twotone color. lib/icons/index.js is a barrel and is skipped. Ant Design ships
15
+ * no categories.
16
+ */
17
+ const ICONS_DIR = join("lib", "icons");
18
+ const ICON_FILE = /^\w+(Filled|Outlined|TwoTone)\.js$/;
19
+ const PREVIEW = /\/\*\*!\[[^\]]*\]\(data:image\/svg\+xml;base64,([A-Za-z0-9+/=]+)\)\s*\*\//;
20
+ const SVG_ROOT = /^\s*<svg\b[^>]*>([\s\S]*)<\/svg>\s*$/;
21
+ // Returns the inner markup of the base64 SVG preview comment in an icon module.
22
+ export function previewSvg(src) {
23
+ const preview = PREVIEW.exec(src);
24
+ if (!preview)
25
+ throw new Error("SVG preview comment not found");
26
+ const svg = Buffer.from(preview[1], "base64").toString("utf8");
27
+ const root = SVG_ROOT.exec(svg);
28
+ if (!root)
29
+ throw new Error("SVG preview has no root <svg> element");
30
+ return root[1].trim();
31
+ }
32
+ export function parseIcons(packageDir) {
33
+ const dir = join(packageDir, ICONS_DIR);
34
+ const icons = [];
35
+ for (const file of readdirSync(dir).sort()) {
36
+ const theme = ICON_FILE.exec(file)?.[1];
37
+ if (!theme)
38
+ continue;
39
+ const importName = file.slice(0, -".js".length);
40
+ let svg;
41
+ try {
42
+ svg = previewSvg(readFileSync(join(dir, file), "utf8"));
43
+ }
44
+ catch (err) {
45
+ throw new Error(`${file}: ${err.message}`, { cause: err });
46
+ }
47
+ icons.push({
48
+ name: toKebabCase(importName),
49
+ importName,
50
+ importPath: "@ant-design/icons",
51
+ style: toKebabCase(theme),
52
+ set: "antdesign",
53
+ categories: [],
54
+ tags: [],
55
+ svg,
56
+ });
57
+ }
58
+ return icons;
59
+ }
60
+ //# sourceMappingURL=antdesign.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"antdesign.js","sourceRoot":"","sources":["../../../src/providers/adapters/antdesign.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AACpD,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,WAAW,EAAgB,MAAM,eAAe,CAAC;AAE1D;;;;;;;;;;;;GAYG;AAEH,MAAM,SAAS,GAAG,IAAI,CAAC,KAAK,EAAE,OAAO,CAAC,CAAC;AACvC,MAAM,SAAS,GAAG,oCAAoC,CAAC;AACvD,MAAM,OAAO,GAAG,2EAA2E,CAAC;AAC5F,MAAM,QAAQ,GAAG,sCAAsC,CAAC;AAExD,gFAAgF;AAChF,MAAM,UAAU,UAAU,CAAC,GAAW;IACpC,MAAM,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IAClC,IAAI,CAAC,OAAO;QAAE,MAAM,IAAI,KAAK,CAAC,+BAA+B,CAAC,CAAC;IAC/D,MAAM,GAAG,GAAG,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,CAAE,EAAE,QAAQ,CAAC,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC;IAChE,MAAM,IAAI,GAAG,QAAQ,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IAChC,IAAI,CAAC,IAAI;QAAE,MAAM,IAAI,KAAK,CAAC,uCAAuC,CAAC,CAAC;IACpE,OAAO,IAAI,CAAC,CAAC,CAAE,CAAC,IAAI,EAAE,CAAC;AACzB,CAAC;AAED,MAAM,UAAU,UAAU,CAAC,UAAkB;IAC3C,MAAM,GAAG,GAAG,IAAI,CAAC,UAAU,EAAE,SAAS,CAAC,CAAC;IACxC,MAAM,KAAK,GAAc,EAAE,CAAC;IAC5B,KAAK,MAAM,IAAI,IAAI,WAAW,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC;QAC3C,MAAM,KAAK,GAAG,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;QACxC,IAAI,CAAC,KAAK;YAAE,SAAS;QACrB,MAAM,UAAU,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC;QAChD,IAAI,GAAW,CAAC;QAChB,IAAI,CAAC;YACH,GAAG,GAAG,UAAU,CAAC,YAAY,CAAC,IAAI,CAAC,GAAG,EAAE,IAAI,CAAC,EAAE,MAAM,CAAC,CAAC,CAAC;QAC1D,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,MAAM,IAAI,KAAK,CAAC,GAAG,IAAI,KAAM,GAAa,CAAC,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,GAAG,EAAE,CAAC,CAAC;QACxE,CAAC;QACD,KAAK,CAAC,IAAI,CAAC;YACT,IAAI,EAAE,WAAW,CAAC,UAAU,CAAC;YAC7B,UAAU;YACV,UAAU,EAAE,mBAAmB;YAC/B,KAAK,EAAE,WAAW,CAAC,KAAK,CAAC;YACzB,GAAG,EAAE,WAAW;YAChB,UAAU,EAAE,EAAE;YACd,IAAI,EAAE,EAAE;YACR,GAAG;SACJ,CAAC,CAAC;IACL,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC"}
@@ -0,0 +1,10 @@
1
+ import { type RawIcon } from "../adapter.js";
2
+ import { LiteralCursor } from "../jsLiteral.js";
3
+ import { type SvgNode } from "../svg.js";
4
+ export declare function parseJsxElement(cursor: LiteralCursor): SvgNode;
5
+ export declare function parseJsxElements(src: string): SvgNode[];
6
+ export declare function parseBucket(src: string): {
7
+ importName: string;
8
+ nodes: SvgNode[];
9
+ }[];
10
+ export declare function parseIcons(packageDir: string): RawIcon[];
@@ -0,0 +1,129 @@
1
+ import { readdirSync, readFileSync } from "node:fs";
2
+ import { join } from "node:path";
3
+ import { toKebabCase } from "../adapter.js";
4
+ import { LiteralCursor } from "../jsLiteral.js";
5
+ import { renderSvg, toSvgAttrs } from "../svg.js";
6
+ /*
7
+ * @carbon/icons-react layout: the package barrel (es/index.js) re-exports every icon from
8
+ * es/generated/bucket-<n>.js, each holding ~125 icons:
9
+ *
10
+ * const Accessibility = /*#__PURE__*\/ React.forwardRef(function Accessibility({ children, size = 16, ...rest }, ref) {
11
+ * return React.createElement(Icon, { width: size, ..., ...rest },
12
+ * /* @__PURE__ *\/ jsx("path", { d: "..." }), /* @__PURE__ *\/ jsx("path", { d: "..." }), children);
13
+ * });
14
+ * ...
15
+ * export { Accessibility, ..., Object$1 as Object, _4K };
16
+ *
17
+ * The buckets are read instead of the per-icon es/<Name>.js modules because they carry the
18
+ * barrel export names: es/Q/H.js and es/watson-health/*.js export local names ("H") that the
19
+ * barrel publishes as "QH" and "WatsonHealth...".
20
+ *
21
+ * A few icons nest elements: jsx("switch", { children: jsxs("g", { children: [jsx(...), ...] }) }).
22
+ * Variants are separate exports suffixed Filled, Alt or Color; they get that suffix as their
23
+ * style, while base icons have no style. Carbon ships no categories.
24
+ */
25
+ const BUCKETS_DIR = join("es", "generated");
26
+ const ICON_DEF = /const ([\w$]+) = \/\*#__PURE__\*\/ React\.forwardRef\(/g;
27
+ const EXPORTS = /export\s*\{([^}]*)\}/;
28
+ const JSX_CALL = /(?<![\w$])(jsx|jsxs)\s*\(/g;
29
+ const STYLE_SUFFIX = /(Filled|Alt|Color)$/;
30
+ // Parses a compiled `jsx("tag", { ...attrs, children })` call, recursing into `children`.
31
+ export function parseJsxElement(cursor) {
32
+ const fn = cursor.identifier();
33
+ if (fn !== "jsx" && fn !== "jsxs")
34
+ cursor.fail(`expected jsx call, got ${fn}`);
35
+ cursor.expect("(");
36
+ const tag = cursor.string();
37
+ cursor.expect(",");
38
+ const attr = {};
39
+ const child = [];
40
+ cursor.expect("{");
41
+ while (!cursor.eat("}")) {
42
+ const ch = cursor.peek();
43
+ const key = ch === '"' || ch === "'" ? cursor.string() : cursor.identifier();
44
+ cursor.expect(":");
45
+ if (key === "children") {
46
+ if (cursor.eat("[")) {
47
+ while (!cursor.eat("]")) {
48
+ child.push(parseJsxElement(cursor));
49
+ if (!cursor.eat(",") && cursor.peek() !== "]")
50
+ cursor.fail('expected "," or "]"');
51
+ }
52
+ }
53
+ else {
54
+ child.push(parseJsxElement(cursor));
55
+ }
56
+ }
57
+ else {
58
+ Object.assign(attr, toSvgAttrs({ [key]: cursor.value() }));
59
+ }
60
+ if (!cursor.eat(",") && cursor.peek() !== "}")
61
+ cursor.fail('expected "," or "}"');
62
+ }
63
+ cursor.expect(")");
64
+ return { tag, attr, child };
65
+ }
66
+ // Parses every top-level jsx call in `src`, skipping calls nested inside one already parsed.
67
+ export function parseJsxElements(src) {
68
+ const nodes = [];
69
+ let consumedEnd = 0;
70
+ for (const match of src.matchAll(JSX_CALL)) {
71
+ if (match.index < consumedEnd)
72
+ continue;
73
+ const cursor = new LiteralCursor(src, match.index);
74
+ nodes.push(parseJsxElement(cursor));
75
+ consumedEnd = cursor.pos;
76
+ }
77
+ return nodes;
78
+ }
79
+ // Maps local binding names to exported names from the bucket's `export { a, b$1 as b }` clause.
80
+ function exportNames(src) {
81
+ const clause = EXPORTS.exec(src);
82
+ if (!clause)
83
+ throw new Error("export clause not found");
84
+ const names = new Map();
85
+ for (const spec of clause[1].split(",").map((s) => s.trim()).filter(Boolean)) {
86
+ const [local, exported = local] = spec.split(/\s+as\s+/);
87
+ names.set(local, exported);
88
+ }
89
+ return names;
90
+ }
91
+ export function parseBucket(src) {
92
+ const exported = exportNames(src);
93
+ const defs = [...src.matchAll(ICON_DEF)];
94
+ return defs.map((def, i) => {
95
+ const importName = exported.get(def[1]);
96
+ if (!importName)
97
+ throw new Error(`icon ${def[1]} is not exported`);
98
+ const body = src.slice(def.index, defs[i + 1]?.index ?? src.length);
99
+ return { importName, nodes: parseJsxElements(body) };
100
+ });
101
+ }
102
+ // "Airport_01" -> "airport-01", "_4K" -> "4-k" (a leading underscore only makes a valid identifier).
103
+ function iconName(identifier) {
104
+ return toKebabCase(identifier.replace(/^_/, "")).replace(/_/g, "-");
105
+ }
106
+ export function parseIcons(packageDir) {
107
+ const dir = join(packageDir, BUCKETS_DIR);
108
+ const icons = [];
109
+ const files = readdirSync(dir).filter((f) => /^bucket-\d+\.js$/.test(f));
110
+ for (const file of files.sort()) {
111
+ for (const { importName, nodes } of parseBucket(readFileSync(join(dir, file), "utf8"))) {
112
+ const suffix = STYLE_SUFFIX.exec(importName)?.[1];
113
+ const style = suffix && suffix !== importName ? toKebabCase(suffix) : undefined;
114
+ const base = style ? importName.slice(0, -suffix.length) : importName;
115
+ icons.push({
116
+ name: style ? `${iconName(base)}-${style}` : iconName(base),
117
+ importName,
118
+ importPath: "@carbon/icons-react",
119
+ style,
120
+ set: "carbon",
121
+ categories: [],
122
+ tags: [],
123
+ svg: renderSvg(nodes),
124
+ });
125
+ }
126
+ }
127
+ return icons;
128
+ }
129
+ //# sourceMappingURL=carbon.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"carbon.js","sourceRoot":"","sources":["../../../src/providers/adapters/carbon.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,7 @@
1
+ import { type RawIcon } from "../adapter.js";
2
+ import { type SvgNode } from "../svg.js";
3
+ export declare function parseChunk(src: string): {
4
+ importName: string;
5
+ nodes: SvgNode[];
6
+ }[];
7
+ export declare function parseIcons(packageDir: string): RawIcon[];
@@ -0,0 +1,71 @@
1
+ import { readdirSync, readFileSync } from "node:fs";
2
+ import { join } from "node:path";
3
+ import { toKebabCase } from "../adapter.js";
4
+ import { LiteralCursor } from "../jsLiteral.js";
5
+ import { renderSvg, toSvgAttrs } from "../svg.js";
6
+ /*
7
+ * @fluentui/react-icons layout: lib/icons/chunk-<n>.js, many icons per chunk, one per line:
8
+ *
9
+ * export const BackpackFilled = ( /*#__PURE__*\/createFluentIcon('BackpackFilled', "1em", ["M8 8.7c0-...", ...]));
10
+ * export const CalendarColor = ( /*#__PURE__*\/createFluentIcon('CalendarColor', "1em", [["path", { "d": "..." }], ["g", {...}, [...]]], { color: true }));
11
+ *
12
+ * Mono-color icons pass an array of path `d` strings; color icons pass [tag, attrs, ...children]
13
+ * node tuples (which include their gradient/filter defs). An optional options object may follow.
14
+ * Every export name ends in its style: Filled, Regular or Color.
15
+ *
16
+ * lib/sizedIcons/ holds size-specific variants (Backpack12Filled, Backpack16Filled, ...) of the
17
+ * same artwork, about 20k near-duplicates; it is skipped and only the scalable 1em icons are
18
+ * indexed. Fluent ships no categories.
19
+ */
20
+ const ICONS_DIR = join("lib", "icons");
21
+ const ICON_EXPORT = /export const (\w+) = \(\s*\/\*#__PURE__\*\/\s*createFluentIcon\(/g;
22
+ const STYLE_SUFFIX = /(Filled|Regular|Color)$/;
23
+ function toNode(value, cursor) {
24
+ if (typeof value === "string")
25
+ return { tag: "path", attr: { d: value }, child: [] };
26
+ if (!Array.isArray(value) || typeof value[0] !== "string")
27
+ cursor.fail("expected path data or [tag, attrs]");
28
+ const [tag, attrs, ...children] = value;
29
+ return { tag, attr: toSvgAttrs(attrs), child: children.map((child) => toNode(child, cursor)) };
30
+ }
31
+ export function parseChunk(src) {
32
+ const icons = [];
33
+ for (const match of src.matchAll(ICON_EXPORT)) {
34
+ const importName = match[1];
35
+ const cursor = new LiteralCursor(src, match.index + match[0].length);
36
+ if (cursor.string() !== importName)
37
+ cursor.fail(`display name does not match export ${importName}`);
38
+ cursor.expect(",");
39
+ cursor.string();
40
+ cursor.expect(",");
41
+ const nodes = cursor.array().map((value) => toNode(value, cursor));
42
+ if (cursor.eat(","))
43
+ cursor.object();
44
+ cursor.expect(")");
45
+ icons.push({ importName, nodes });
46
+ }
47
+ return icons;
48
+ }
49
+ export function parseIcons(packageDir) {
50
+ const dir = join(packageDir, ICONS_DIR);
51
+ const icons = [];
52
+ for (const file of readdirSync(dir).filter((f) => /^chunk-\d+\.js$/.test(f)).sort()) {
53
+ for (const { importName, nodes } of parseChunk(readFileSync(join(dir, file), "utf8"))) {
54
+ const style = STYLE_SUFFIX.exec(importName)?.[1];
55
+ if (!style)
56
+ throw new Error(`${file}: ${importName} has no Filled/Regular/Color suffix`);
57
+ icons.push({
58
+ name: toKebabCase(importName),
59
+ importName,
60
+ importPath: "@fluentui/react-icons",
61
+ style: style.toLowerCase(),
62
+ set: "fluentui",
63
+ categories: [],
64
+ tags: [],
65
+ svg: renderSvg(nodes),
66
+ });
67
+ }
68
+ }
69
+ return icons;
70
+ }
71
+ //# sourceMappingURL=fluentui.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fluentui.js","sourceRoot":"","sources":["../../../src/providers/adapters/fluentui.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,4 @@
1
+ import { type RawIcon } from "../adapter.js";
2
+ import { type SvgNode } from "../svg.js";
3
+ export declare function parseIconFile(src: string): SvgNode[];
4
+ export declare function parseIcons(packageDir: string): RawIcon[];
@@ -0,0 +1,58 @@
1
+ import { existsSync, readdirSync, readFileSync } from "node:fs";
2
+ import { join } from "node:path";
3
+ import { toKebabCase } from "../adapter.js";
4
+ import { LiteralCursor } from "../jsLiteral.js";
5
+ import { parseCreateElement, renderSvg } from "../svg.js";
6
+ /*
7
+ * iconoir-react layout: dist/esm/regular/<Name>.mjs and dist/esm/solid/<Name>.mjs, one minified
8
+ * component per file whose render returns
9
+ *
10
+ * n.createElement("svg", t({width: "1.5em", viewBox: "0 0 24 24", ...}, p),
11
+ * n.createElement("path", {d: "...", stroke: "currentColor", strokeLinecap: "round"}), ...)
12
+ *
13
+ * where `t(..., p)` merges the default attributes with context and props. That root call holds
14
+ * non-literals (`ref: o`), so it is skipped; the children after it are the icon's inner SVG.
15
+ * The package root re-exports regular icons as "<Name>" and solid ones as "<Name>Solid", so
16
+ * solid icons are named "<name>-solid" to stay unique. The index.mjs barrels are skipped.
17
+ * Iconoir ships no categories or tags.
18
+ */
19
+ const VARIANTS = [
20
+ { dir: "regular", suffix: "" },
21
+ { dir: "solid", suffix: "Solid" },
22
+ ];
23
+ const SVG_CALL = /\w+\.createElement\(\s*"svg"\s*,\s*\w+\(\s*\{[^}]*\}\s*,\s*\w+\s*\)/;
24
+ export function parseIconFile(src) {
25
+ const call = SVG_CALL.exec(src);
26
+ if (!call)
27
+ throw new Error("svg createElement call not found");
28
+ const cursor = new LiteralCursor(src, call.index + call[0].length);
29
+ const nodes = [];
30
+ while (cursor.eat(","))
31
+ nodes.push(parseCreateElement(cursor));
32
+ cursor.expect(")");
33
+ return nodes;
34
+ }
35
+ export function parseIcons(packageDir) {
36
+ const icons = [];
37
+ for (const { dir, suffix } of VARIANTS) {
38
+ const variantDir = join(packageDir, "dist", "esm", dir);
39
+ if (!existsSync(variantDir))
40
+ continue;
41
+ for (const file of readdirSync(variantDir).filter((f) => /^[A-Z]\w*\.mjs$/.test(f)).sort()) {
42
+ const component = file.slice(0, -".mjs".length);
43
+ const importName = component + suffix;
44
+ icons.push({
45
+ name: toKebabCase(importName),
46
+ importName,
47
+ importPath: "iconoir-react",
48
+ style: dir,
49
+ set: "iconoir",
50
+ categories: [],
51
+ tags: [],
52
+ svg: renderSvg(parseIconFile(readFileSync(join(variantDir, file), "utf8"))),
53
+ });
54
+ }
55
+ }
56
+ return icons;
57
+ }
58
+ //# sourceMappingURL=iconoir.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"iconoir.js","sourceRoot":"","sources":["../../../src/providers/adapters/iconoir.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AAChE,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,WAAW,EAAgB,MAAM,eAAe,CAAC;AAC1D,OAAO,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAChD,OAAO,EAAE,kBAAkB,EAAE,SAAS,EAAgB,MAAM,WAAW,CAAC;AAExE;;;;;;;;;;;;GAYG;AAEH,MAAM,QAAQ,GAAG;IACf,EAAE,GAAG,EAAE,SAAS,EAAE,MAAM,EAAE,EAAE,EAAE;IAC9B,EAAE,GAAG,EAAE,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE;CAClC,CAAC;AACF,MAAM,QAAQ,GAAG,qEAAqE,CAAC;AAEvF,MAAM,UAAU,aAAa,CAAC,GAAW;IACvC,MAAM,IAAI,GAAG,QAAQ,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IAChC,IAAI,CAAC,IAAI;QAAE,MAAM,IAAI,KAAK,CAAC,kCAAkC,CAAC,CAAC;IAC/D,MAAM,MAAM,GAAG,IAAI,aAAa,CAAC,GAAG,EAAE,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC;IACnE,MAAM,KAAK,GAAc,EAAE,CAAC;IAC5B,OAAO,MAAM,CAAC,GAAG,CAAC,GAAG,CAAC;QAAE,KAAK,CAAC,IAAI,CAAC,kBAAkB,CAAC,MAAM,CAAC,CAAC,CAAC;IAC/D,MAAM,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;IACnB,OAAO,KAAK,CAAC;AACf,CAAC;AAED,MAAM,UAAU,UAAU,CAAC,UAAkB;IAC3C,MAAM,KAAK,GAAc,EAAE,CAAC;IAC5B,KAAK,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,IAAI,QAAQ,EAAE,CAAC;QACvC,MAAM,UAAU,GAAG,IAAI,CAAC,UAAU,EAAE,MAAM,EAAE,KAAK,EAAE,GAAG,CAAC,CAAC;QACxD,IAAI,CAAC,UAAU,CAAC,UAAU,CAAC;YAAE,SAAS;QACtC,KAAK,MAAM,IAAI,IAAI,WAAW,CAAC,UAAU,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,iBAAiB,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC;YAC3F,MAAM,SAAS,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;YAChD,MAAM,UAAU,GAAG,SAAS,GAAG,MAAM,CAAC;YACtC,KAAK,CAAC,IAAI,CAAC;gBACT,IAAI,EAAE,WAAW,CAAC,UAAU,CAAC;gBAC7B,UAAU;gBACV,UAAU,EAAE,eAAe;gBAC3B,KAAK,EAAE,GAAG;gBACV,GAAG,EAAE,SAAS;gBACd,UAAU,EAAE,EAAE;gBACd,IAAI,EAAE,EAAE;gBACR,GAAG,EAAE,SAAS,CAAC,aAAa,CAAC,YAAY,CAAC,IAAI,CAAC,UAAU,EAAE,IAAI,CAAC,EAAE,MAAM,CAAC,CAAC,CAAC;aAC5E,CAAC,CAAC;QACL,CAAC;IACH,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC"}
@@ -1,10 +1,22 @@
1
+ import { parseIcons as parseAntDesign } from "./antdesign.js";
2
+ import { parseIcons as parseCarbon } from "./carbon.js";
3
+ import { parseIcons as parseFluentUi } from "./fluentui.js";
1
4
  import { parseIcons as parseHeroicons } from "./heroicons.js";
5
+ import { parseIcons as parseIconoir } from "./iconoir.js";
2
6
  import { parseIcons as parseLucide } from "./lucide.js";
7
+ import { parseIcons as parsePhosphor } from "./phosphor.js";
3
8
  import { parseIcons as parseReactIcons } from "./react-icons.js";
9
+ import { parseIcons as parseTabler } from "./tabler.js";
4
10
  // Adapter per provider id (see ../registry.ts).
5
11
  export const ADAPTERS = {
6
12
  "react-icons": parseReactIcons,
7
13
  lucide: parseLucide,
8
14
  heroicons: parseHeroicons,
15
+ phosphor: parsePhosphor,
16
+ tabler: parseTabler,
17
+ iconoir: parseIconoir,
18
+ fluentui: parseFluentUi,
19
+ carbon: parseCarbon,
20
+ antdesign: parseAntDesign,
9
21
  };
10
22
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/providers/adapters/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,UAAU,IAAI,cAAc,EAAE,MAAM,gBAAgB,CAAC;AAC9D,OAAO,EAAE,UAAU,IAAI,WAAW,EAAE,MAAM,aAAa,CAAC;AACxD,OAAO,EAAE,UAAU,IAAI,eAAe,EAAE,MAAM,kBAAkB,CAAC;AAEjE,gDAAgD;AAChD,MAAM,CAAC,MAAM,QAAQ,GAAyC;IAC5D,aAAa,EAAE,eAAe;IAC9B,MAAM,EAAE,WAAW;IACnB,SAAS,EAAE,cAAc;CAC1B,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/providers/adapters/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,UAAU,IAAI,cAAc,EAAE,MAAM,gBAAgB,CAAC;AAC9D,OAAO,EAAE,UAAU,IAAI,WAAW,EAAE,MAAM,aAAa,CAAC;AACxD,OAAO,EAAE,UAAU,IAAI,aAAa,EAAE,MAAM,eAAe,CAAC;AAC5D,OAAO,EAAE,UAAU,IAAI,cAAc,EAAE,MAAM,gBAAgB,CAAC;AAC9D,OAAO,EAAE,UAAU,IAAI,YAAY,EAAE,MAAM,cAAc,CAAC;AAC1D,OAAO,EAAE,UAAU,IAAI,WAAW,EAAE,MAAM,aAAa,CAAC;AACxD,OAAO,EAAE,UAAU,IAAI,aAAa,EAAE,MAAM,eAAe,CAAC;AAC5D,OAAO,EAAE,UAAU,IAAI,eAAe,EAAE,MAAM,kBAAkB,CAAC;AACjE,OAAO,EAAE,UAAU,IAAI,WAAW,EAAE,MAAM,aAAa,CAAC;AAExD,gDAAgD;AAChD,MAAM,CAAC,MAAM,QAAQ,GAAyC;IAC5D,aAAa,EAAE,eAAe;IAC9B,MAAM,EAAE,WAAW;IACnB,SAAS,EAAE,cAAc;IACzB,QAAQ,EAAE,aAAa;IACvB,MAAM,EAAE,WAAW;IACnB,OAAO,EAAE,YAAY;IACrB,QAAQ,EAAE,aAAa;IACvB,MAAM,EAAE,WAAW;IACnB,SAAS,EAAE,cAAc;CAC1B,CAAC"}
@@ -0,0 +1,4 @@
1
+ import { type RawIcon } from "../adapter.js";
2
+ import { type SvgNode } from "../svg.js";
3
+ export declare function parseWeights(src: string): [weight: string, nodes: SvgNode[]][];
4
+ export declare function parseIcons(packageDir: string): RawIcon[];
@@ -0,0 +1,78 @@
1
+ import { readdirSync, readFileSync } from "node:fs";
2
+ import { join } from "node:path";
3
+ import { toKebabCase } from "../adapter.js";
4
+ import { LiteralCursor } from "../jsLiteral.js";
5
+ import { parseCreateElement, renderSvg } from "../svg.js";
6
+ /*
7
+ * @phosphor-icons/react layout: one component module per icon in dist/csr/<Name>.es.js, which
8
+ * exports "<Name>Icon" (plus a deprecated "<Name>" and sometimes alias names such as
9
+ * "FolderNotchIcon" from Folder.es.js), and its SVG per weight in dist/defs/<Name>.es.js:
10
+ *
11
+ * const a = new Map([
12
+ * ["bold", e.createElement(e.Fragment, null, e.createElement("path", { d: "..." }), ...)],
13
+ * ["duotone", ...], ["fill", ...], ["light", ...], ["regular", ...], ["thin", ...]
14
+ * ]);
15
+ *
16
+ * All weights share one component and are picked with its `weight` prop, so each weight is
17
+ * indexed as its own record with `style` set to the weight. The default weight keeps the plain
18
+ * name ("acorn") and the others get a suffix ("acorn-bold"), so the default sorts first.
19
+ * Alias export names are added to the tags. Phosphor ships no categories.
20
+ */
21
+ const CSR_DIR = join("dist", "csr");
22
+ const DEFS_DIR = join("dist", "defs");
23
+ const DEFAULT_WEIGHT = "regular";
24
+ const WEIGHT_MAP = /new Map\(\s*/;
25
+ const ICON_EXPORT = /\bas (\w+)Icon\b/g;
26
+ export function parseWeights(src) {
27
+ const map = WEIGHT_MAP.exec(src);
28
+ if (!map)
29
+ throw new Error("weights Map not found");
30
+ const cursor = new LiteralCursor(src, map.index + map[0].length);
31
+ const weights = [];
32
+ cursor.expect("[");
33
+ while (cursor.eat("[")) {
34
+ const weight = cursor.string();
35
+ cursor.expect(",");
36
+ // The Fragment wrapper: <ns>.createElement(<ns>.Fragment, null, ...children).
37
+ cursor.identifier();
38
+ cursor.expect(".createElement(");
39
+ cursor.identifier();
40
+ cursor.expect(".Fragment,");
41
+ cursor.expect("null");
42
+ const nodes = [];
43
+ while (cursor.eat(","))
44
+ nodes.push(parseCreateElement(cursor));
45
+ cursor.expect(")");
46
+ cursor.expect("]");
47
+ weights.push([weight, nodes]);
48
+ cursor.eat(",");
49
+ }
50
+ cursor.expect("]");
51
+ return weights;
52
+ }
53
+ export function parseIcons(packageDir) {
54
+ const icons = [];
55
+ const files = readdirSync(join(packageDir, CSR_DIR)).filter((f) => f.endsWith(".es.js"));
56
+ for (const file of files.sort()) {
57
+ const component = file.slice(0, -".es.js".length);
58
+ const importName = `${component}Icon`;
59
+ const src = readFileSync(join(packageDir, CSR_DIR, file), "utf8");
60
+ const aliases = [...src.matchAll(ICON_EXPORT)].map((m) => m[1]).filter((name) => name !== component);
61
+ const base = toKebabCase(component);
62
+ const weights = parseWeights(readFileSync(join(packageDir, DEFS_DIR, file), "utf8"));
63
+ for (const [weight, nodes] of weights) {
64
+ icons.push({
65
+ name: weight === DEFAULT_WEIGHT ? base : `${base}-${weight}`,
66
+ importName,
67
+ importPath: "@phosphor-icons/react",
68
+ style: weight,
69
+ set: "phosphor",
70
+ categories: [],
71
+ tags: aliases.map(toKebabCase),
72
+ svg: renderSvg(nodes),
73
+ });
74
+ }
75
+ }
76
+ return icons;
77
+ }
78
+ //# sourceMappingURL=phosphor.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"phosphor.js","sourceRoot":"","sources":["../../../src/providers/adapters/phosphor.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,8 @@
1
+ import { type RawIcon } from "../adapter.js";
2
+ import { type SvgNode } from "../svg.js";
3
+ export declare function parseIconFile(src: string): {
4
+ name: string;
5
+ style: string;
6
+ nodes: SvgNode[];
7
+ };
8
+ export declare function parseIcons(packageDir: string): RawIcon[];
@@ -0,0 +1,77 @@
1
+ import { existsSync, readdirSync, readFileSync } from "node:fs";
2
+ import { join } from "node:path";
3
+ import { toKebabCase } from "../adapter.js";
4
+ import { LiteralCursor } from "../jsLiteral.js";
5
+ import { renderSvg, toSvgAttrs } from "../svg.js";
6
+ /*
7
+ * @tabler/icons-react layout: dist/esm/icons/Icon<Name>.mjs, one ESM module per icon:
8
+ *
9
+ * const __iconNode = [["path", { "d": "M4 7l16 0", "key": "svg-0" }], ...];
10
+ * const IconTrash = createReactComponent("outline", "trash", "Trash", __iconNode);
11
+ * export { __iconNode, IconTrash as default };
12
+ *
13
+ * createReactComponent's arguments give the style ("outline" or "filled") and the kebab icon
14
+ * name, which already carries the variant ("trash" vs "trash-filled"), so names are unique.
15
+ * The package barrel (dist/esm/tabler-icons-react.mjs) re-exports some icons under old names
16
+ * (`export { default as Icon123, default as IconNumber123 } from './icons/IconNumber123.mjs'`);
17
+ * those are added to the target icon's tags. dist/esm/icons/index.mjs is a barrel and is
18
+ * skipped. Tabler ships no categories.
19
+ */
20
+ const ICONS_DIR = join("dist", "esm", "icons");
21
+ const BARREL = join("dist", "esm", "tabler-icons-react.mjs");
22
+ const ICON_NODE = /const __iconNode = /;
23
+ const CREATE_CALL = /createReactComponent\(\s*/;
24
+ const BARREL_EXPORT = /export\s*\{([^}]*)\}\s*from\s*['"]\.\/icons\/(\w+)\.mjs['"]/g;
25
+ function parseNodes(cursor) {
26
+ return cursor.array().map((node) => {
27
+ if (!Array.isArray(node) || typeof node[0] !== "string")
28
+ cursor.fail("expected [tag, attrs]");
29
+ return { tag: node[0], attr: toSvgAttrs(node[1]), child: [] };
30
+ });
31
+ }
32
+ // Maps icon module name (IconNumber123) to its alias names in the barrel (["123"]).
33
+ function barrelAliases(packageDir) {
34
+ const aliases = new Map();
35
+ const file = join(packageDir, BARREL);
36
+ if (!existsSync(file))
37
+ return aliases;
38
+ for (const match of readFileSync(file, "utf8").matchAll(BARREL_EXPORT)) {
39
+ const target = match[2];
40
+ const names = [...match[1].matchAll(/default as (\w+)/g)].map((m) => m[1]).filter((n) => n !== target);
41
+ if (names.length > 0)
42
+ aliases.set(target, names.map((n) => toKebabCase(n.replace(/^Icon/, ""))));
43
+ }
44
+ return aliases;
45
+ }
46
+ export function parseIconFile(src) {
47
+ const iconNode = ICON_NODE.exec(src);
48
+ const call = CREATE_CALL.exec(src);
49
+ if (!iconNode || !call)
50
+ throw new Error("createReactComponent call not found");
51
+ const nodes = parseNodes(new LiteralCursor(src, iconNode.index + iconNode[0].length));
52
+ const cursor = new LiteralCursor(src, call.index + call[0].length);
53
+ const style = cursor.string();
54
+ cursor.expect(",");
55
+ return { name: cursor.string(), style, nodes };
56
+ }
57
+ export function parseIcons(packageDir) {
58
+ const dir = join(packageDir, ICONS_DIR);
59
+ const aliases = barrelAliases(packageDir);
60
+ const icons = [];
61
+ for (const file of readdirSync(dir).filter((f) => /^Icon\w+\.mjs$/.test(f)).sort()) {
62
+ const importName = file.slice(0, -".mjs".length);
63
+ const { name, style, nodes } = parseIconFile(readFileSync(join(dir, file), "utf8"));
64
+ icons.push({
65
+ name,
66
+ importName,
67
+ importPath: "@tabler/icons-react",
68
+ style,
69
+ set: "tabler",
70
+ categories: [],
71
+ tags: aliases.get(importName) ?? [],
72
+ svg: renderSvg(nodes),
73
+ });
74
+ }
75
+ return icons;
76
+ }
77
+ //# sourceMappingURL=tabler.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tabler.js","sourceRoot":"","sources":["../../../src/providers/adapters/tabler.ts"],"names":[],"mappings":"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"}
@@ -1,4 +1,4 @@
1
- // Icon providers supported in v1.
1
+ // Supported icon providers.
2
2
  export const PROVIDERS = [
3
3
  {
4
4
  id: "react-icons",
@@ -15,6 +15,36 @@ export const PROVIDERS = [
15
15
  package: "@heroicons/react",
16
16
  description: "Heroicons by the Tailwind CSS team as React components",
17
17
  },
18
+ {
19
+ id: "phosphor",
20
+ package: "@phosphor-icons/react",
21
+ description: "Phosphor icons in six weights (thin, light, regular, bold, fill, duotone) as React components",
22
+ },
23
+ {
24
+ id: "tabler",
25
+ package: "@tabler/icons-react",
26
+ description: "Tabler icons (outline and filled) as React components",
27
+ },
28
+ {
29
+ id: "iconoir",
30
+ package: "iconoir-react",
31
+ description: "Iconoir icons (regular and solid) as React components",
32
+ },
33
+ {
34
+ id: "fluentui",
35
+ package: "@fluentui/react-icons",
36
+ description: "Microsoft Fluent UI System icons (regular, filled and color) as React components",
37
+ },
38
+ {
39
+ id: "carbon",
40
+ package: "@carbon/icons-react",
41
+ description: "IBM Carbon Design System icons as React components",
42
+ },
43
+ {
44
+ id: "antdesign",
45
+ package: "@ant-design/icons",
46
+ description: "Ant Design icons (outlined, filled and two-tone) as React components",
47
+ },
18
48
  ];
19
49
  // Finds a provider by its id or by its npm package name.
20
50
  export function getProvider(idOrPackage) {
@@ -1 +1 @@
1
- {"version":3,"file":"registry.js","sourceRoot":"","sources":["../../src/providers/registry.ts"],"names":[],"mappings":"AAQA,kCAAkC;AAClC,MAAM,CAAC,MAAM,SAAS,GAAwB;IAC5C;QACE,EAAE,EAAE,aAAa;QACjB,OAAO,EAAE,aAAa;QACtB,WAAW,EAAE,sFAAsF;KACpG;IACD;QACE,EAAE,EAAE,QAAQ;QACZ,OAAO,EAAE,cAAc;QACvB,WAAW,EAAE,kCAAkC;KAChD;IACD;QACE,EAAE,EAAE,WAAW;QACf,OAAO,EAAE,kBAAkB;QAC3B,WAAW,EAAE,wDAAwD;KACtE;CACF,CAAC;AAEF,yDAAyD;AACzD,MAAM,UAAU,WAAW,CAAC,WAAmB;IAC7C,OAAO,SAAS,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,WAAW,IAAI,CAAC,CAAC,OAAO,KAAK,WAAW,CAAC,CAAC;AAClF,CAAC"}
1
+ {"version":3,"file":"registry.js","sourceRoot":"","sources":["../../src/providers/registry.ts"],"names":[],"mappings":"AAQA,4BAA4B;AAC5B,MAAM,CAAC,MAAM,SAAS,GAAwB;IAC5C;QACE,EAAE,EAAE,aAAa;QACjB,OAAO,EAAE,aAAa;QACtB,WAAW,EAAE,sFAAsF;KACpG;IACD;QACE,EAAE,EAAE,QAAQ;QACZ,OAAO,EAAE,cAAc;QACvB,WAAW,EAAE,kCAAkC;KAChD;IACD;QACE,EAAE,EAAE,WAAW;QACf,OAAO,EAAE,kBAAkB;QAC3B,WAAW,EAAE,wDAAwD;KACtE;IACD;QACE,EAAE,EAAE,UAAU;QACd,OAAO,EAAE,uBAAuB;QAChC,WAAW,EAAE,+FAA+F;KAC7G;IACD;QACE,EAAE,EAAE,QAAQ;QACZ,OAAO,EAAE,qBAAqB;QAC9B,WAAW,EAAE,uDAAuD;KACrE;IACD;QACE,EAAE,EAAE,SAAS;QACb,OAAO,EAAE,eAAe;QACxB,WAAW,EAAE,uDAAuD;KACrE;IACD;QACE,EAAE,EAAE,UAAU;QACd,OAAO,EAAE,uBAAuB;QAChC,WAAW,EAAE,kFAAkF;KAChG;IACD;QACE,EAAE,EAAE,QAAQ;QACZ,OAAO,EAAE,qBAAqB;QAC9B,WAAW,EAAE,oDAAoD;KAClE;IACD;QACE,EAAE,EAAE,WAAW;QACf,OAAO,EAAE,mBAAmB;QAC5B,WAAW,EAAE,sEAAsE;KACpF;CACF,CAAC;AAEF,yDAAyD;AACzD,MAAM,UAAU,WAAW,CAAC,WAAmB;IAC7C,OAAO,SAAS,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,WAAW,IAAI,CAAC,CAAC,OAAO,KAAK,WAAW,CAAC,CAAC;AAClF,CAAC"}
@@ -1,4 +1,4 @@
1
- import type { JsValue } from "./jsLiteral.js";
1
+ import type { JsValue, LiteralCursor } from "./jsLiteral.js";
2
2
  export interface SvgNode {
3
3
  tag: string;
4
4
  attr: Record<string, string | number>;
@@ -7,3 +7,4 @@ export interface SvgNode {
7
7
  export declare function svgAttrName(reactName: string): string;
8
8
  export declare function renderSvg(nodes: readonly SvgNode[]): string;
9
9
  export declare function toSvgAttrs(value: JsValue | undefined): Record<string, string | number>;
10
+ export declare function parseCreateElement(cursor: LiteralCursor): SvgNode;
@@ -49,6 +49,8 @@ const CASE_SENSITIVE_ATTRS = new Set([
49
49
  "calcMode",
50
50
  "keyTimes",
51
51
  "keySplines",
52
+ "requiredExtensions",
53
+ "systemLanguage",
52
54
  ]);
53
55
  const SPECIAL_ATTRS = {
54
56
  className: "class",
@@ -94,4 +96,18 @@ export function toSvgAttrs(value) {
94
96
  }
95
97
  return attrs;
96
98
  }
99
+ // Parses a compiled `<ns>.createElement("tag", {attrs} | null, ...children)` call (any namespace
100
+ // identifier, e.g. "React" or a minified "e"), recursing into element children.
101
+ export function parseCreateElement(cursor) {
102
+ cursor.identifier();
103
+ cursor.expect(".createElement(");
104
+ const tag = cursor.string();
105
+ cursor.expect(",");
106
+ const attr = toSvgAttrs(cursor.value());
107
+ const child = [];
108
+ while (cursor.eat(","))
109
+ child.push(parseCreateElement(cursor));
110
+ cursor.expect(")");
111
+ return { tag, attr, child };
112
+ }
97
113
  //# sourceMappingURL=svg.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"svg.js","sourceRoot":"","sources":["../../src/providers/svg.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"svg.js","sourceRoot":"","sources":["../../src/providers/svg.ts"],"names":[],"mappings":"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"}
@@ -22,5 +22,9 @@ export interface SearchResult {
22
22
  export declare function loadIndex(cacheDir: string): Promise<LoadedIndex>;
23
23
  /** True when an index was built with different synonyms or an older index format. */
24
24
  export declare function indexNeedsRebuild(meta: IndexMeta, synonyms: Synonyms): boolean;
25
- /** Filters records by provider/style/set exactly, then ranks them against the query with Fuse.js. */
25
+ /**
26
+ * Filters records by provider/style/set exactly, then ranks them against the query with Fuse.js.
27
+ * Multi-word queries are searched token by token: only records matching every token are kept,
28
+ * ranked by their mean per-token score.
29
+ */
26
30
  export declare function searchIcons(records: readonly IconRecord[], query: string, options?: SearchOptions): SearchResult[];
@@ -30,16 +30,30 @@ const FUSE_OPTIONS = {
30
30
  function matches(value, filter) {
31
31
  return filter === undefined || value?.toLowerCase() === filter.toLowerCase();
32
32
  }
33
- /** Filters records by provider/style/set exactly, then ranks them against the query with Fuse.js. */
33
+ /**
34
+ * Filters records by provider/style/set exactly, then ranks them against the query with Fuse.js.
35
+ * Multi-word queries are searched token by token: only records matching every token are kept,
36
+ * ranked by their mean per-token score.
37
+ */
34
38
  export function searchIcons(records, query, options = {}) {
35
- const trimmed = query.trim();
36
- if (!trimmed)
39
+ const tokens = query.trim().split(/\s+/).filter(Boolean);
40
+ if (tokens.length === 0)
37
41
  return [];
38
42
  const { provider, style, set, limit } = options;
39
43
  const filtered = records.filter((r) => matches(r.provider, provider) && matches(r.style, style) && matches(r.set, set));
40
- const results = new Fuse(filtered, FUSE_OPTIONS)
41
- .search(trimmed)
42
- .map((result) => ({ record: result.item, score: result.score ?? 0 }));
44
+ const fuse = new Fuse(filtered, FUSE_OPTIONS);
45
+ const perToken = tokens.map((token) => new Map(fuse.search(token).map((result) => [result.item, result.score ?? 0])));
46
+ const [first, ...rest] = perToken;
47
+ // Iterate in the first token's ranked order so ties keep Fuse's ordering (sort is stable).
48
+ const results = [];
49
+ for (const [record, score] of first) {
50
+ const others = rest.map((scores) => scores.get(record));
51
+ if (others.some((s) => s === undefined))
52
+ continue;
53
+ const total = others.reduce((sum, s) => sum + s, score);
54
+ results.push({ record, score: total / tokens.length });
55
+ }
56
+ results.sort((a, b) => a.score - b.score);
43
57
  return limit === undefined ? results : results.slice(0, Math.max(0, limit));
44
58
  }
45
59
  //# sourceMappingURL=search.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"search.js","sourceRoot":"","sources":["../../src/search/search.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"search.js","sourceRoot":"","sources":["../../src/search/search.ts"],"names":[],"mappings":"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"}
package/dist/server.d.ts CHANGED
@@ -1,4 +1,4 @@
1
1
  import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
2
2
  export declare const SERVER_NAME = "trueicon";
3
- export declare const SERVER_VERSION = "0.1.0";
3
+ export declare const SERVER_VERSION = "0.2.0";
4
4
  export declare function createServer(): McpServer;
package/dist/server.js CHANGED
@@ -4,7 +4,7 @@ import { registerListProvidersTool } from "./tools/listProviders.js";
4
4
  import { registerPingTool } from "./tools/ping.js";
5
5
  import { registerSearchIconsTool } from "./tools/searchIcons.js";
6
6
  export const SERVER_NAME = "trueicon";
7
- export const SERVER_VERSION = "0.1.0";
7
+ export const SERVER_VERSION = "0.2.0";
8
8
  // Builds the MCP server with all tools registered. Transport wiring lives in index.ts.
9
9
  export function createServer() {
10
10
  const server = new McpServer({ name: SERVER_NAME, version: SERVER_VERSION });
package/package.json CHANGED
@@ -1,9 +1,33 @@
1
1
  {
2
2
  "name": "trueicon",
3
- "version": "0.1.0",
3
+ "mcpName": "io.github.manikumarkv/trueicon",
4
+ "version": "0.2.0",
4
5
  "description": "MCP server that lets AI coding assistants search the icon packages actually installed in your project.",
5
6
  "license": "MIT",
6
7
  "author": "manikumarkv",
8
+ "repository": {
9
+ "type": "git",
10
+ "url": "git+https://github.com/manikumarkv/trueicon.git"
11
+ },
12
+ "homepage": "https://github.com/manikumarkv/trueicon#readme",
13
+ "bugs": {
14
+ "url": "https://github.com/manikumarkv/trueicon/issues"
15
+ },
16
+ "keywords": [
17
+ "mcp",
18
+ "mcp-server",
19
+ "model-context-protocol",
20
+ "icons",
21
+ "lucide",
22
+ "heroicons",
23
+ "react-icons",
24
+ "phosphor",
25
+ "tabler",
26
+ "iconoir",
27
+ "fluentui",
28
+ "carbon",
29
+ "ant-design"
30
+ ],
7
31
  "type": "module",
8
32
  "bin": {
9
33
  "trueicon": "dist/index.js"