@astryxdesign/cli 0.7.11 → 0.7.12-canary.ccb4a6d

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.
Files changed (68) hide show
  1. package/api/build/kit/rank.mjs +21 -4
  2. package/api/build/kit/words.d.mts +1 -0
  3. package/api/build/kit/words.mjs +1 -1
  4. package/api/icon/_adapter.d.mts +3 -2
  5. package/api/icon/_adapter.mjs +8 -2
  6. package/api/icon/_authoring.d.mts +1 -0
  7. package/api/icon/_authoring.mjs +586 -66
  8. package/api/icon/_default-look.d.mts +155 -0
  9. package/api/icon/_default-look.mjs +474 -0
  10. package/api/icon/_records.d.mts +1 -1
  11. package/api/icon/_records.mjs +1 -0
  12. package/api/icon/add/add.mjs +224 -38
  13. package/api/icon/icon.type.d.mts +22 -2
  14. package/api/icon/icon.type.mjs +6 -2
  15. package/api/icon/iconAdd.doc.mjs +2 -2
  16. package/api/icon/iconNewDefinition.doc.mjs +3 -2
  17. package/api/icon/iconNewSet.doc.mjs +4 -4
  18. package/api/icon/search/search.mjs +10 -9
  19. package/api/integration/add-helpers.d.mts +11 -1
  20. package/api/integration/add-helpers.mjs +5 -2
  21. package/api/integration/authoring-checks.d.mts +0 -2
  22. package/api/integration/authoring-checks.mjs +1 -6
  23. package/api/logger.mjs +2 -1
  24. package/api/swizzle/_adapter.d.mts +1 -0
  25. package/api/swizzle/_adapter.mjs +4 -1
  26. package/api/swizzle/_moduleGraph.d.mts +171 -0
  27. package/api/swizzle/_moduleGraph.mjs +795 -0
  28. package/api/swizzle/copy/copy.d.mts +2 -43
  29. package/api/swizzle/copy/copy.mjs +195 -314
  30. package/api/swizzle/swizzle.d.mts +0 -2
  31. package/api/swizzle/swizzle.doc.mjs +9 -4
  32. package/api/swizzle/swizzle.mjs +3 -7
  33. package/api/swizzle/swizzle.type.d.mts +2 -1
  34. package/api/swizzle/swizzle.type.mjs +3 -2
  35. package/assets/discover/official-packages.json +20 -0
  36. package/assets/docs/tree/icon-sets.doc.mjs +11 -5
  37. package/assets/templates/blocks/components/Table/TableRowIndexTable.doc.mjs +1 -1
  38. package/assets/templates/blocks/components/Table/TableRowIndexTable.tsx +2 -2
  39. package/assets/templates/pages/course-detail/page.tsx +699 -0
  40. package/assets/templates/pages/course-detail/template.doc.mjs +37 -0
  41. package/assets/templates/pages/file-explorer/page.tsx +103 -79
  42. package/assets/templates/pages/table-grouped/page.tsx +160 -232
  43. package/assets/templates/pages/table-grouped/template.doc.mjs +0 -2
  44. package/assets/templates/pages/theme-showcase/page.tsx +724 -792
  45. package/assets/templates/pages/theme-showcase/template.doc.mjs +4 -5
  46. package/authoring/doctypes/template/type.ts +1 -0
  47. package/clients/cli/commands/experimental/icon.mjs +31 -10
  48. package/clients/cli/commands/experimental-icon-add.doc.mjs +1 -1
  49. package/clients/cli/commands/experimental-icon-new-definition.doc.mjs +2 -1
  50. package/clients/cli/commands/experimental-icon-new-set.doc.mjs +2 -2
  51. package/clients/cli/commands/swizzle.doc.mjs +8 -3
  52. package/clients/cli/commands/swizzle.mjs +21 -9
  53. package/foundation/discovery/component-loader.d.mts +1 -1
  54. package/foundation/discovery/doc-types.mjs +9 -2
  55. package/foundation/discovery/icon-ranking.d.mts +27 -3
  56. package/foundation/discovery/icon-ranking.mjs +125 -8
  57. package/foundation/discovery/icon-set-checks.mjs +44 -35
  58. package/foundation/discovery/icon-set-discovery.d.mts +13 -0
  59. package/foundation/discovery/icon-set-discovery.mjs +25 -0
  60. package/foundation/discovery/icon-set-writer.d.mts +238 -16
  61. package/foundation/discovery/icon-set-writer.mjs +676 -79
  62. package/foundation/discovery/module-exports.d.mts +3 -2
  63. package/foundation/discovery/module-exports.mjs +167 -37
  64. package/foundation/fs/paths.d.mts +2 -1
  65. package/foundation/fs/paths.mjs +3 -4
  66. package/foundation/text/shell-arg.d.mts +14 -0
  67. package/foundation/text/shell-arg.mjs +17 -0
  68. package/package.json +6 -6
@@ -44,8 +44,9 @@ import * as path from 'node:path';
44
44
  import {findInstalledPackage} from '../fs/paths.mjs';
45
45
  import {satisfiesRange} from '../env/semver.mjs';
46
46
  import {
47
- NOTICE_FILE_RE,
48
47
  discoverIconSetDirectory,
48
+ hasLicenseNotice,
49
+ licenseNoticeFix,
49
50
  resolveIconModule,
50
51
  splitSpecifier,
51
52
  } from './icon-set-discovery.mjs';
@@ -57,6 +58,7 @@ import {
57
58
  otherNamesOf,
58
59
  generatedTypesText,
59
60
  readGeneratedStatements,
61
+ generatedTypesMatch,
60
62
  } from './icon-set-writer.mjs';
61
63
  import {
62
64
  exportValueKind,
@@ -67,6 +69,7 @@ import {
67
69
  } from './module-exports.mjs';
68
70
  import {astryxIconDefinitions} from './icon-definition-discovery.mjs';
69
71
  import {rankIcons} from './icon-ranking.mjs';
72
+ import {shellArg} from '../text/shell-arg.mjs';
70
73
  import {
71
74
  issueError,
72
75
  issueWarning,
@@ -276,16 +279,17 @@ function checkContract(set, packageName, pkg, unchecked) {
276
279
  const actual = fs.existsSync(typesFile)
277
280
  ? fs.readFileSync(typesFile, 'utf-8')
278
281
  : null;
279
- // The header comment is the writer's, and changes between releases;
280
- // the declarations are what must match.
281
- const code = (/** @type {string} */ text) =>
282
- text
283
- .split('\n')
284
- .filter(line => !line.startsWith('//'))
285
- .join('\n');
282
+ // The declarations must match, statement by statement, however a
283
+ // formatter left the file; the header comment is the writer's and
284
+ // changes between releases.
286
285
  if (
287
286
  expected != null &&
288
- (actual == null || code(actual) !== code(expected))
287
+ (actual == null ||
288
+ !generatedTypesMatch(
289
+ actual,
290
+ expected,
291
+ /** @type {string} */ (typesRel),
292
+ ))
289
293
  ) {
290
294
  issues.push(
291
295
  issueError(
@@ -359,12 +363,12 @@ function checkDefinitions(set) {
359
363
  if (mapped.has(doc.name) || !doc.builtIn) continue;
360
364
  const suggestion = suggestIcon(set, doc);
361
365
  const hint = suggestion
362
- ? ` Suggested: astryx experimental icon map ${doc.name} ${suggestion.icon}.`
366
+ ? ` Suggested: astryx experimental icon map ${doc.name} ${suggestion.icon} --set ${set.name}.`
363
367
  : '';
364
368
  issues.push(
365
369
  issueError(
366
370
  ICON_BUILTIN_DEFINITION_MISSING,
367
- `${label} maps no icon to the built-in icon definition "${doc.name}" (${doc.description} Words: ${doc.words.join(', ')}.). Every set maps every built-in definition: run \`astryx experimental icon map ${doc.name} <icon id>\` with the icon that draws it${findHint(set, doc)}.${hint}`,
371
+ `${label} maps no icon to the built-in icon definition "${doc.name}" (${doc.description} Words: ${doc.words.join(', ')}.). Every set maps every built-in definition: run \`astryx experimental icon map ${doc.name} <icon id> --set ${set.name}\` with the icon that draws it${findHint(set, doc)}.${hint}`,
368
372
  ),
369
373
  );
370
374
  }
@@ -382,7 +386,7 @@ function checkDefinitions(set) {
382
386
  issues.push(
383
387
  issueWarning(
384
388
  ICON_DEFINITION_UNUSED,
385
- `${label} declares the icon definition "${doc.name}", but "map" names no icon for it. Map it with \`astryx experimental icon map ${doc.name} <icon id>\`, or remove definitions/${doc.name}.doc.mjs.${suggestion ? ` Suggested: astryx experimental icon map ${doc.name} ${suggestion.icon}.` : ''}`,
389
+ `${label} declares the icon definition "${doc.name}", but "map" names no icon for it. Map it with \`astryx experimental icon map ${doc.name} <icon id> --set ${set.name}\`, or remove definitions/${doc.name}.doc.mjs.${suggestion ? ` Suggested: astryx experimental icon map ${doc.name} ${suggestion.icon} --set ${set.name}.` : ''}`,
386
390
  ),
387
391
  );
388
392
  }
@@ -538,13 +542,7 @@ export function suggestedIcons(set, doc) {
538
542
  ...nameWords,
539
543
  ...wordIds.flatMap(id => id.split('-')).map(stem),
540
544
  ]);
541
- const icons = set.data.icons.map(icon => ({
542
- id: icon.id,
543
- words: icon.id.split('-').map(stem),
544
- raw: icon.id.split('-'),
545
- // The library's other names for it, the same ones `map` accepts.
546
- other: otherNamesOf(icon),
547
- }));
545
+ const icons = suggestionIndex(set.data.icons);
548
546
  /** How many of the definition's words an id has: more is a better fit. */
549
547
  const fit = (/** @type {string[]} */ words) =>
550
548
  words.filter(word => meaning.has(word)).length;
@@ -636,6 +634,29 @@ export function suggestedIcons(set, doc) {
636
634
  return found.slice(0, SUGGESTIONS_PER_DEFINITION);
637
635
  }
638
636
 
637
+ /**
638
+ * Each icon as the suggestion rules read it: its id's words as written and
639
+ * in singular form, and the library's other names for it (the same ones
640
+ * `map` accepts). Built once per list of icons, so suggesting for every
641
+ * definition of a large library reads each icon once.
642
+ * @type {WeakMap<object, Array<{id: string, words: string[], raw: string[], other: string[]}>>}
643
+ */
644
+ const suggestionIndexes = new WeakMap();
645
+
646
+ /** @param {Array<{id: string, words?: string[]}>} list */
647
+ function suggestionIndex(list) {
648
+ const cached = suggestionIndexes.get(list);
649
+ if (cached) return cached;
650
+ const index = list.map(icon => ({
651
+ id: icon.id,
652
+ words: icon.id.split('-').map(stem),
653
+ raw: icon.id.split('-'),
654
+ other: otherNamesOf(icon),
655
+ }));
656
+ suggestionIndexes.set(list, index);
657
+ return index;
658
+ }
659
+
639
660
  /**
640
661
  * A word in its singular form, so a plural meets its singular and nothing
641
662
  * else: `languages` meets `language`, `arrows` meets `arrow`. Only a
@@ -934,10 +955,10 @@ function findHint(set, doc) {
934
955
  each => each.score >= FIND_FLOOR,
935
956
  );
936
957
  if (found.length > 0) {
937
- return ` (icons matching "${query}": \`astryx experimental icon ${query} --set ${set.name}\`)`;
958
+ return ` (icons matching "${query}": \`astryx experimental icon ${shellArg(query)} --set ${set.name}\`)`;
938
959
  }
939
960
  }
940
- return ' (no icon in the set has its name or words: pick the library icon that draws it; if the library has none, map the closest, or add your own artwork with `astryx experimental icon add <Name> --from ./src/icons/<name>.js --definition <definition>`)';
961
+ return ` (no icon in the set has its name or words: pick the library icon that draws it; if the library has none, map the closest, or add your own artwork with \`astryx experimental icon add <Name> --from ./src/icons/<name>.js --definition ${doc.name} --set ${set.name}\`)`;
941
962
  }
942
963
 
943
964
  /**
@@ -983,14 +1004,11 @@ function checkUpstream(set, packageDir, pkg) {
983
1004
  ),
984
1005
  );
985
1006
  }
986
- const rootNotices = safeList(packageDir).filter(name =>
987
- NOTICE_FILE_RE.test(name),
988
- );
989
- if (set.notices.length === 0 && rootNotices.length === 0) {
1007
+ if (!hasLicenseNotice(set.dir) && !hasLicenseNotice(packageDir)) {
990
1008
  issues.push(
991
1009
  issueWarning(
992
1010
  ICON_LICENSE_NOTICE_MISSING,
993
- `${label} is generated from ${source.package} but ships no license notice. Copy the library's LICENSE (and NOTICE, if any) into the set directory or the package root.`,
1011
+ `${label} is generated from ${source.package}@${source.version} but ships no license notice. ${licenseNoticeFix(path.relative(packageDir, set.dir).split(path.sep).join('/'), `${source.package}@${source.version}`)} If the library ships a LICENSE or NOTICE file, copy that file there instead.`,
994
1012
  ),
995
1013
  );
996
1014
  }
@@ -1006,12 +1024,3 @@ function safeSatisfies(version, range) {
1006
1024
  return true;
1007
1025
  }
1008
1026
  }
1009
-
1010
- /** @param {string} dir */
1011
- function safeList(dir) {
1012
- try {
1013
- return fs.readdirSync(dir);
1014
- } catch {
1015
- return [];
1016
- }
1017
- }
@@ -1,6 +1,19 @@
1
1
  // @generated by scripts/sync-api-types.mjs from the JSDoc in foundation/**/*.mjs.
2
2
  // DO NOT EDIT — run `pnpm sync:api-types` to regenerate.
3
3
 
4
+ /**
5
+ * What to add when a set wraps a library and has no license notice: a
6
+ * NOTICE file in the set directory, with the file names that count. The
7
+ * CLI never writes it, because the license text is the author's to state.
8
+ * @param {string} setDir the set directory, from the package root
9
+ * @param {string} library the library as `name@version`
10
+ */
11
+ export function licenseNoticeFix(setDir: string, library: string): string;
12
+ /**
13
+ * Whether a directory has a license or notice file ({@link NOTICE_FILE_RE}).
14
+ * @param {string} dir
15
+ */
16
+ export function hasLicenseNotice(dir: string): boolean;
4
17
  /**
5
18
  * One installed icon set: its descriptor, its data, and where it came from.
6
19
  * @typedef {object} DiscoveredIconSet
@@ -43,6 +43,31 @@ const SET_NAME_RE = /^[a-z][a-z0-9]*(?:-[a-z0-9]+)*$/u;
43
43
  /** A license or notice file a set ships beside its data (FR15). */
44
44
  export const NOTICE_FILE_RE = /^(?:licen[cs]e|notice|copying)(?:[.-].*)?$/iu;
45
45
 
46
+ /**
47
+ * What to add when a set wraps a library and has no license notice: a
48
+ * NOTICE file in the set directory, with the file names that count. The
49
+ * CLI never writes it, because the license text is the author's to state.
50
+ * @param {string} setDir the set directory, from the package root
51
+ * @param {string} library the library as `name@version`
52
+ */
53
+ export function licenseNoticeFix(setDir, library) {
54
+ return `Add a NOTICE (or LICENSE) file to ${setDir} that names ${library} and its license: \`${setDir}/NOTICE\`. A file named LICENSE, LICENCE, NOTICE, or COPYING, in any case and with an optional suffix such as NOTICE.md or LICENSE-MIT, counts in the set directory or the package root.`;
55
+ }
56
+
57
+ /**
58
+ * Whether a directory has a license or notice file ({@link NOTICE_FILE_RE}).
59
+ * @param {string} dir
60
+ */
61
+ export function hasLicenseNotice(dir) {
62
+ try {
63
+ return fs
64
+ .readdirSync(dir, {withFileTypes: true})
65
+ .some(file => file.isFile() && NOTICE_FILE_RE.test(file.name));
66
+ } catch {
67
+ return false;
68
+ }
69
+ }
70
+
46
71
  /**
47
72
  * One installed icon set: its descriptor, its data, and where it came from.
48
73
  * @typedef {object} DiscoveredIconSet
@@ -166,29 +166,158 @@ export function modulePrefix(file: string, options?: {
166
166
  adapter?: boolean;
167
167
  exclude?: string[];
168
168
  }): string[];
169
+ /**
170
+ * How a module names its icons: the library prefix every icon export shares
171
+ * ({@link modulePrefix}) and the look words its names end in
172
+ * ({@link lookPositions}), read from its icon exports once. A large module
173
+ * reports its reading, as {@link libraryIcons} does.
174
+ * @param {string} file
175
+ * @param {{adapter?: boolean, module?: string, progress?: (line: string) => void}} [options]
176
+ * `module`: the module as the author named it, for progress; `progress`:
177
+ * hears the reading of a large module
178
+ * @returns {{prefix: string[], positions: Array<Set<string>>}}
179
+ */
180
+ export function moduleNaming(file: string, options?: {
181
+ adapter?: boolean;
182
+ module?: string;
183
+ progress?: (line: string) => void;
184
+ }): {
185
+ prefix: string[];
186
+ positions: Array<Set<string>>;
187
+ };
188
+ /**
189
+ * An export's id and set name ({@link iconNaming}) without the look words
190
+ * its library's names end in ({@link lookPositions}):
191
+ * `XOutline24WGHT500Icon` is `x`, `XIcon`.
192
+ * @param {string} name
193
+ * @param {{prefix: string[], positions: Array<Set<string>>}} naming
194
+ * @returns {{id: string, name: string}}
195
+ */
196
+ export function iconNamingWithoutLook(name: string, { prefix, positions }: {
197
+ prefix: string[];
198
+ positions: Array<Set<string>>;
199
+ }): {
200
+ id: string;
201
+ name: string;
202
+ };
203
+ /**
204
+ * The trailing words a library encodes its looks with: a style, a size, a
205
+ * weight (`XOutline24WGHT500Icon` is `x` in the `outline`, `24`, `wght500`
206
+ * look). A trailing position is a look position when, across at least
207
+ * {@link LOOK_MIN_ICONS} icons, at most {@link LOOK_MAX_VALUES} words fill
208
+ * it, each on at least 5% of the icons and together on at least 90%, and
209
+ * those words name a look ({@link namesLook}); the positions are read from
210
+ * the end while they hold. Glyph names never meet that bar (`trash-2` and
211
+ * `clock-10` are a few icons each, and `up` and `down` are directions), so
212
+ * a library that encodes no looks has none. Reads each id once per
213
+ * position and keeps only counts.
214
+ * @param {string[]} ids every icon's id
215
+ * @returns {Array<Set<string>>} the look positions, the last word first
216
+ */
217
+ export function lookPositions(ids: string[]): Array<Set<string>>;
218
+ /**
219
+ * An id's glyph words and its look words, by {@link lookPositions}:
220
+ * `x-outline-24-wght500` is `x` with `[wght500, 24, outline]`, null where
221
+ * the id has no look word.
222
+ * @param {string[]} words
223
+ * @param {Array<Set<string>>} positions
224
+ * @returns {{base: string[], look: Array<string | null>}}
225
+ */
226
+ export function splitLook(words: string[], positions: Array<Set<string>>): {
227
+ base: string[];
228
+ look: Array<string | null>;
229
+ };
230
+ /**
231
+ * The word each look position prefers: a word of `prefer` it has (the set's
232
+ * default variant), else a usual default style word, else the middle of a
233
+ * series of numbered words (`wght300` … `wght700` gives `wght500`), else
234
+ * its first word in order.
235
+ * @param {Array<Set<string>>} positions
236
+ * @param {string[]} [prefer]
237
+ * @returns {string[]}
238
+ */
239
+ export function preferredLook(positions: Array<Set<string>>, prefer?: string[]): string[];
240
+ /**
241
+ * One icon a library gives.
242
+ * @typedef {object} LibraryIcon
243
+ * @property {string} export the library export it reads
244
+ * @property {string} id
245
+ * @property {string} name the name the set exports it as
246
+ * @property {boolean} adapt
247
+ * @property {string[]} aliases the ids of the other names the library
248
+ * exports the icon as, leaving out the library's own name (`lucide-trash`)
249
+ * @property {Array<string | null>} [look] in a library that encodes looks:
250
+ * this export's look words by position, the last word first
251
+ * @property {string[]} [looks] in a library that encodes looks: every
252
+ * export that draws the glyph, this one included
253
+ */
254
+ /**
255
+ * The words a library's looks are named by, and the look a set takes from
256
+ * it: what {@link libraryIcons} found, for the receipt.
257
+ * @typedef {object} LibraryLookSummary
258
+ * @property {string[][]} positions each position's words, sorted, the last
259
+ * word of a name first
260
+ * @property {string[]} preferred the word taken in each position
261
+ * @property {number} exports how many exports draw the icons
262
+ */
169
263
  /**
170
264
  * Every icon a whole library exports, for wrapping it at once: one entry per
171
265
  * component (and, with an adapter, per data export), read by its `…Icon`
172
266
  * export when it has one (an alias of the same value is recorded once), with
173
267
  * its id and the name the set exports it as from the name, the library
174
268
  * prefix left out ({@link libraryPrefix}).
269
+ *
270
+ * A library that encodes looks in its export names ({@link lookPositions})
271
+ * gives one icon per glyph: the look {@link preferredLook} prefers, its id
272
+ * and name without the look words (`XOutline24WGHT500Icon` is `x`,
273
+ * `XIcon`), and its `looks`, every export that draws the glyph.
175
274
  * @param {string} file
176
- * @param {{adapter?: boolean, exclude?: string[]}} [options] `adapter`:
177
- * whether the set declares one; `exclude`: export names that are not icons
178
- * @returns {Array<{export: string, id: string, name: string, adapt: boolean, aliases: string[]}>}
179
- * `aliases`: the ids of the other names the library exports the icon as,
180
- * leaving out the library's own name (`lucide-trash`)
275
+ * @param {{adapter?: boolean, exclude?: string[], prefer?: string[] | ((positions: Array<Set<string>>) => string[]), module?: string, progress?: (line: string) => void, summary?: (summary: LibraryLookSummary) => void}} [options]
276
+ * `adapter`: whether the set declares one; `exclude`: export names that
277
+ * are not icons; `prefer`: look words to prefer (the set's default
278
+ * variant), or a function that gives them from the library's look
279
+ * positions before any glyph is picked; `module`: the module as the author named it, for progress;
280
+ * `progress`: hears the reading of a large module;
281
+ * `summary`: hears the looks found, when the library has any
282
+ * @returns {LibraryIcon[]}
181
283
  */
182
284
  export function libraryIcons(file: string, options?: {
183
285
  adapter?: boolean;
184
286
  exclude?: string[];
185
- }): Array<{
186
- export: string;
187
- id: string;
188
- name: string;
189
- adapt: boolean;
190
- aliases: string[];
191
- }>;
287
+ prefer?: string[] | ((positions: Array<Set<string>>) => string[]);
288
+ module?: string;
289
+ progress?: (line: string) => void;
290
+ summary?: (summary: LibraryLookSummary) => void;
291
+ }): LibraryIcon[];
292
+ /**
293
+ * The library's icons grouped by glyph when its export names encode looks
294
+ * ({@link libraryIcons}), with the look positions and the words preferred.
295
+ * Without look positions the icons are returned as they are.
296
+ * @param {LibraryIcon[]} all every icon, one per export
297
+ * @param {string[]} [prefer]
298
+ * @returns {{icons: LibraryIcon[], positions: Array<Set<string>>, preferred: string[]}}
299
+ */
300
+ export function libraryLooks(all: LibraryIcon[], prefer?: string[]): {
301
+ icons: LibraryIcon[];
302
+ positions: Array<Set<string>>;
303
+ preferred: string[];
304
+ };
305
+ /**
306
+ * Every icon a library exports, one per export: {@link libraryIcons} before
307
+ * looks are grouped. A large module reports its reading, as
308
+ * {@link libraryIcons} does.
309
+ * @param {string} file
310
+ * @param {{adapter?: boolean, exclude?: string[], module?: string, progress?: (line: string) => void}} [options]
311
+ * `module`: the module as the author named it, for progress; `progress`:
312
+ * hears the reading of a large module
313
+ * @returns {LibraryIcon[]}
314
+ */
315
+ export function everyLibraryIcon(file: string, options?: {
316
+ adapter?: boolean;
317
+ exclude?: string[];
318
+ module?: string;
319
+ progress?: (line: string) => void;
320
+ }): LibraryIcon[];
192
321
  /**
193
322
  * The source of one icon definition file, typed IconDefinitionDoc.
194
323
  * @param {{name: string, description: string, words: string[]}} doc
@@ -199,13 +328,20 @@ export function iconDefinitionSource(doc: {
199
328
  words: string[];
200
329
  }): string;
201
330
  /**
202
- * Check a new icon definition for a set: a camelCase name no Astryx
203
- * definition has, a description, and at least one lower-case word.
331
+ * A new definition's name as written in a command: camelCase as given, or
332
+ * kebab-case as the docs list definitions (`ai-helper` is `aiHelper`).
333
+ * @param {string} name
334
+ */
335
+ export function definitionNameFromInput(name: string): string;
336
+ /**
337
+ * Check a new icon definition for a set: a camelCase name (or its kebab-case
338
+ * form, {@link definitionNameFromInput}) no Astryx definition has, a
339
+ * description, and at least one lower-case word.
204
340
  * @param {DiscoveredIconSet} set
205
- * @param {{name: string, description?: string, words?: string[]}} doc
341
+ * @param {{name: string, description?: string, words?: string[]}} given
206
342
  * @returns {{name: string, description: string, words: string[]}}
207
343
  */
208
- export function checkNewDefinition(set: DiscoveredIconSet, doc: {
344
+ export function checkNewDefinition(set: DiscoveredIconSet, given: {
209
345
  name: string;
210
346
  description?: string;
211
347
  words?: string[];
@@ -232,6 +368,15 @@ export function writeDefinitionFile(set: DiscoveredIconSet, doc: {
232
368
  description: string;
233
369
  words: string[];
234
370
  }): () => void;
371
+ /**
372
+ * Whether a generated declaration file declares what its generated module
373
+ * gives, statement by statement however a formatter left either file
374
+ * ({@link generatedStatements}); the header comment is ignored.
375
+ * @param {string} actual the declaration file as it is
376
+ * @param {string} expected {@link generatedTypesText} for the module
377
+ * @param {string} label the declaration file's path, for a parse error
378
+ */
379
+ export function generatedTypesMatch(actual: string, expected: string, label: string): boolean;
235
380
  /**
236
381
  * The generated icons module of a set, from the package root: `generated`
237
382
  * in its data file, else `<set directory>/<set>.generated.js`.
@@ -316,6 +461,34 @@ export function sameIconModule(a: string, b: string): boolean;
316
461
  * @param {string} specifier
317
462
  */
318
463
  export function iconModulePackage(specifier: string): string;
464
+ /**
465
+ * The set's exports that read one file of a package, where a refresh from
466
+ * that package's root can read them from the root instead. An export moves
467
+ * when the root exports the same icon: an export that resolves to the same
468
+ * file and binding. When the subpath export cannot be resolved, a root
469
+ * export of the same name counts. Each maps to the root's
470
+ * export and the module it reads now. Empty unless `root` is a package
471
+ * root, not a subpath or a ./ path.
472
+ * @param {Map<string, {module: string, source: string}>} origins the
473
+ * set's exports ({@link generatedOrigins})
474
+ * @param {{file: string, module: string}} root the refreshed module
475
+ * @param {string[]} rootExports the root's icon exports
476
+ * @param {{packageDir: string, pkg: Record<string, any>}} where
477
+ * @returns {Map<string, {source: string, from: string}>}
478
+ */
479
+ export function packageRootMoves(origins: Map<string, {
480
+ module: string;
481
+ source: string;
482
+ }>, root: {
483
+ file: string;
484
+ module: string;
485
+ }, rootExports: string[], where: {
486
+ packageDir: string;
487
+ pkg: Record<string, any>;
488
+ }): Map<string, {
489
+ source: string;
490
+ from: string;
491
+ }>;
319
492
  /**
320
493
  * Write the set's generated module and its declaration file
321
494
  * ({@link generatedModuleText}). Returns whether either changed, and a
@@ -469,6 +642,55 @@ export class IconSetAuthoringError extends Error {
469
642
  }
470
643
  /** The theme map the generated module writes. */
471
644
  export const THEME_MAP_NAME: "themeIcons";
645
+ /**
646
+ * One icon a library gives.
647
+ */
648
+ export type LibraryIcon = {
649
+ /**
650
+ * the library export it reads
651
+ */
652
+ export: string;
653
+ id: string;
654
+ /**
655
+ * the name the set exports it as
656
+ */
657
+ name: string;
658
+ adapt: boolean;
659
+ /**
660
+ * the ids of the other names the library
661
+ * exports the icon as, leaving out the library's own name (`lucide-trash`)
662
+ */
663
+ aliases: string[];
664
+ /**
665
+ * in a library that encodes looks:
666
+ * this export's look words by position, the last word first
667
+ */
668
+ look?: (string | null)[] | undefined;
669
+ /**
670
+ * in a library that encodes looks: every
671
+ * export that draws the glyph, this one included
672
+ */
673
+ looks?: string[] | undefined;
674
+ };
675
+ /**
676
+ * The words a library's looks are named by, and the look a set takes from
677
+ * it: what {@link libraryIcons} found, for the receipt.
678
+ */
679
+ export type LibraryLookSummary = {
680
+ /**
681
+ * each position's words, sorted, the last
682
+ * word of a name first
683
+ */
684
+ positions: string[][];
685
+ /**
686
+ * the word taken in each position
687
+ */
688
+ preferred: string[];
689
+ /**
690
+ * how many exports draw the icons
691
+ */
692
+ exports: number;
693
+ };
472
694
  export type DiscoveredIconSet = import("./icon-set-discovery.mjs").DiscoveredIconSet;
473
695
  export type IconSetData = import("../../authoring/doctypes/icon-set/type").IconSetData;
474
696
  /**