extract.ts 2.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384
  1. #!/usr/bin/env node
  2. /** biome-ignore-all lint/suspicious/noConsole: script output */
  3. /**
  4. * Extracts a minimal emoji native lookup from @emoji-mart/data.
  5. *
  6. * Emojis are ordered by category so that CodeMirror autocomplete suggests
  7. * common emojis (people, nature, …) before flags and symbols.
  8. *
  9. * Run via the package build script (from the monorepo root):
  10. * turbo run build --filter @growi/emoji-mart-data
  11. *
  12. * Or directly (from packages/emoji-mart-data/):
  13. * node bin/extract.ts
  14. *
  15. * Output: dist/index.js, dist/index.d.ts
  16. * Re-run whenever @emoji-mart/data is upgraded.
  17. */
  18. import { mkdirSync, readFileSync, writeFileSync } from 'node:fs';
  19. import { resolve } from 'node:path';
  20. type EmojiEntry = { skins: { native: string }[] };
  21. type EmojiData = {
  22. categories: { id: string; emojis: string[] }[];
  23. emojis: Record<string, EmojiEntry>;
  24. };
  25. type NativeLookup = Record<string, { skins: [{ native: string }] }>;
  26. const EMOJI_CATEGORIES = [
  27. 'people',
  28. 'nature',
  29. 'foods',
  30. 'activity',
  31. 'places',
  32. 'objects',
  33. 'symbols',
  34. 'flags',
  35. ] as const;
  36. const inputPath = resolve(
  37. import.meta.dirname,
  38. '../node_modules/@emoji-mart/data/sets/15/native.json',
  39. );
  40. const raw: EmojiData = JSON.parse(readFileSync(inputPath, 'utf8'));
  41. // Build lookup in category order so consumers get UX-friendly suggestion order.
  42. const lookup: NativeLookup = {};
  43. for (const catId of EMOJI_CATEGORIES) {
  44. const cat = raw.categories.find((c) => c.id === catId);
  45. if (!cat) continue;
  46. for (const name of cat.emojis) {
  47. const native = raw.emojis[name]?.skins?.[0]?.native;
  48. if (native) lookup[name] = { skins: [{ native }] };
  49. }
  50. }
  51. const distDir = resolve(import.meta.dirname, '../dist');
  52. mkdirSync(distDir, { recursive: true });
  53. // Emit as an ES module so TypeScript resolves index.d.ts for types
  54. // instead of inferring a 1870-key literal type from the raw JSON.
  55. const jsPath = resolve(distDir, 'index.js');
  56. writeFileSync(
  57. jsPath,
  58. `// Generated — do not edit. Run \`node bin/extract.ts\` to regenerate.\nexport default ${JSON.stringify(lookup)};\n`,
  59. 'utf8',
  60. );
  61. console.log(`Wrote ${Object.keys(lookup).length} entries to ${jsPath}`);
  62. const dtsPath = resolve(distDir, 'index.d.ts');
  63. writeFileSync(
  64. dtsPath,
  65. [
  66. 'export type NativeLookup = Record<string, { skins: [{ native: string }] }>;',
  67. 'declare const _default: NativeLookup;',
  68. 'export default _default;',
  69. '',
  70. ].join('\n'),
  71. 'utf8',
  72. );
  73. console.log(`Wrote ${dtsPath}`);