eslint-plugin-markdown-preferences 0.12.0 → 0.14.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/lib/index.js CHANGED
@@ -1,4 +1,6 @@
1
1
  import { __export } from "./chunk-Cl8Af3a2.js";
2
+ import stringWidth from "string-width";
3
+ import emojiRegex from "emoji-regex-xs";
2
4
  import path from "node:path";
3
5
  import markdown from "@eslint/markdown";
4
6
 
@@ -25,6 +27,437 @@ function createRule(ruleName, rule) {
25
27
  };
26
28
  }
27
29
 
30
+ //#endregion
31
+ //#region src/utils/atx-heading.ts
32
+ /**
33
+ * Parse the closing sequence of an ATX heading.
34
+ */
35
+ function parseATXHeadingClosingSequence(sourceCode, node) {
36
+ const loc = sourceCode.getLoc(node);
37
+ if (loc.start.line !== loc.end.line) return null;
38
+ const range = sourceCode.getRange(node);
39
+ const parsed = parseATXHeadingClosingSequenceFromText(sourceCode.text.slice(...range));
40
+ if (parsed == null) return { closingSequence: null };
41
+ const rawAfter = {
42
+ text: parsed.rawAfter,
43
+ range: [range[1] - parsed.rawAfter.length, range[1]],
44
+ loc: {
45
+ start: {
46
+ line: loc.end.line,
47
+ column: loc.end.column - parsed.rawAfter.length
48
+ },
49
+ end: {
50
+ line: loc.end.line,
51
+ column: loc.end.column
52
+ }
53
+ }
54
+ };
55
+ const closingSequence = {
56
+ text: parsed.closingSequence,
57
+ range: [rawAfter.range[0] - parsed.closingSequence.length, rawAfter.range[0]],
58
+ loc: {
59
+ start: {
60
+ line: rawAfter.loc.start.line,
61
+ column: rawAfter.loc.start.column - parsed.closingSequence.length
62
+ },
63
+ end: rawAfter.loc.start
64
+ }
65
+ };
66
+ const rawBefore = {
67
+ text: parsed.rawBefore,
68
+ range: [closingSequence.range[0] - parsed.rawBefore.length, closingSequence.range[0]],
69
+ loc: {
70
+ start: {
71
+ line: closingSequence.loc.start.line,
72
+ column: closingSequence.loc.start.column - parsed.rawBefore.length
73
+ },
74
+ end: closingSequence.loc.start
75
+ }
76
+ };
77
+ return {
78
+ rawBefore,
79
+ closingSequence,
80
+ rawAfter
81
+ };
82
+ }
83
+ /**
84
+ * Parse the closing sequence from a text string.
85
+ */
86
+ function parseATXHeadingClosingSequenceFromText(text) {
87
+ const trimmedEndOffset = skipEndWhitespace(text.length - 1) + 1;
88
+ if (trimmedEndOffset <= 0 || text[trimmedEndOffset - 1] !== "#") return null;
89
+ let closingSequenceBeforeOffset = trimmedEndOffset - 2;
90
+ while (closingSequenceBeforeOffset >= 0 && text[closingSequenceBeforeOffset] === "#") closingSequenceBeforeOffset--;
91
+ const beforeOffset = skipEndWhitespace(closingSequenceBeforeOffset);
92
+ if (beforeOffset === closingSequenceBeforeOffset || beforeOffset < 0) return null;
93
+ return {
94
+ rawBefore: text.slice(beforeOffset + 1, closingSequenceBeforeOffset + 1),
95
+ closingSequence: text.slice(closingSequenceBeforeOffset + 1, trimmedEndOffset),
96
+ rawAfter: text.slice(trimmedEndOffset)
97
+ };
98
+ /**
99
+ * Skip whitespace characters at the end of the text.
100
+ */
101
+ function skipEndWhitespace(index) {
102
+ let result = index;
103
+ let c;
104
+ while (result >= 0 && (c = text[result]) && (c === " " || c === " ")) result--;
105
+ return result;
106
+ }
107
+ }
108
+
109
+ //#endregion
110
+ //#region src/utils/lines.ts
111
+ const cache = /* @__PURE__ */ new WeakMap();
112
+ var ParsedLines = class {
113
+ lines;
114
+ constructor(codeText) {
115
+ let offset = 0;
116
+ this.lines = codeText.split(/(?<=\n)/u).map((lineText, index) => {
117
+ const start = offset;
118
+ offset += lineText.length;
119
+ const range = [start, offset];
120
+ let text = lineText;
121
+ let linebreak = "";
122
+ if (text.at(-1) === "\n") {
123
+ text = text.slice(0, -1);
124
+ linebreak = "\n";
125
+ }
126
+ if (text.at(-1) === "\r") {
127
+ text = text.slice(0, -1);
128
+ linebreak = `\r${linebreak}`;
129
+ }
130
+ return {
131
+ text,
132
+ range,
133
+ line: index + 1,
134
+ linebreak
135
+ };
136
+ });
137
+ }
138
+ [Symbol.iterator]() {
139
+ return this.lines[Symbol.iterator]();
140
+ }
141
+ get length() {
142
+ return this.lines.length;
143
+ }
144
+ get(lineNumber) {
145
+ return this.lines[lineNumber - 1];
146
+ }
147
+ };
148
+ /**
149
+ * Parse the lines of the source code.
150
+ * @param sourceCode source code to parse
151
+ * @returns parsed lines
152
+ */
153
+ function parseLines(sourceCode) {
154
+ const cached = cache.get(sourceCode);
155
+ if (cached) return cached;
156
+ const parsedLines = new ParsedLines(sourceCode.text);
157
+ cache.set(sourceCode, parsedLines);
158
+ return parsedLines;
159
+ }
160
+
161
+ //#endregion
162
+ //#region src/rules/atx-headings-closing-sequence-length.ts
163
+ let segmenter;
164
+ var atx_headings_closing_sequence_length_default = createRule("atx-headings-closing-sequence-length", {
165
+ meta: {
166
+ type: "layout",
167
+ docs: {
168
+ description: "enforce consistent length for the closing sequence (trailing #s) in ATX headings.",
169
+ categories: [],
170
+ listCategory: "Stylistic"
171
+ },
172
+ fixable: "code",
173
+ hasSuggestions: false,
174
+ schema: [{
175
+ type: "object",
176
+ properties: {
177
+ mode: { enum: [
178
+ "match-opening",
179
+ "length",
180
+ "consistent",
181
+ "consistent-line-length",
182
+ "fixed-line-length"
183
+ ] },
184
+ length: {
185
+ type: "integer",
186
+ minimum: 1
187
+ }
188
+ },
189
+ additionalProperties: false
190
+ }],
191
+ messages: { wrongClosingLength: "The closing sequence length should be {{expected}} (was {{actual}})." }
192
+ },
193
+ create(context) {
194
+ const sourceCode = context.sourceCode;
195
+ const option = Object.assign({ mode: "match-opening" }, context.options[0] || {});
196
+ /**
197
+ * Verify the closing sequence length of an ATX heading.
198
+ */
199
+ function verifyATXHeadingClosingSequenceLength(node, getExpected) {
200
+ const parsed = parseATXHeadingClosingSequence(sourceCode, node);
201
+ if (!parsed || parsed.closingSequence == null) return;
202
+ const actualLength = parsed.closingSequence.text.length;
203
+ const expectedLength = getExpected(node, parsed);
204
+ if (expectedLength === actualLength) return;
205
+ context.report({
206
+ node,
207
+ loc: parsed.closingSequence.loc,
208
+ messageId: "wrongClosingLength",
209
+ data: {
210
+ expected: String(expectedLength),
211
+ actual: String(actualLength)
212
+ },
213
+ fix: (fixer) => {
214
+ return fixer.replaceTextRange(parsed.closingSequence.range, "#".repeat(expectedLength));
215
+ }
216
+ });
217
+ }
218
+ return option.mode === "match-opening" ? (() => {
219
+ const getExpected = (node) => node.depth;
220
+ return { heading(node) {
221
+ verifyATXHeadingClosingSequenceLength(node, getExpected);
222
+ } };
223
+ })() : option.mode === "length" ? (() => {
224
+ const expected = option.length || 2;
225
+ const getExpected = () => expected;
226
+ return { heading(node) {
227
+ verifyATXHeadingClosingSequenceLength(node, getExpected);
228
+ } };
229
+ })() : option.mode === "fixed-line-length" ? (() => {
230
+ const totalLength = option.length || 80;
231
+ const lines = parseLines(sourceCode);
232
+ const getExpected = (_node, parsed) => {
233
+ return totalLength - getContentLength(lines, parsed);
234
+ };
235
+ return { heading(node) {
236
+ verifyATXHeadingClosingSequenceLength(node, getExpected);
237
+ } };
238
+ })() : option.mode === "consistent" ? (() => {
239
+ let getExpected = null;
240
+ return { heading(node) {
241
+ if (getExpected == null) {
242
+ const parsed = parseATXHeadingClosingSequence(sourceCode, node);
243
+ if (!parsed || parsed.closingSequence == null) return;
244
+ const expected = parsed.closingSequence.text.length;
245
+ getExpected = () => expected;
246
+ } else verifyATXHeadingClosingSequenceLength(node, getExpected);
247
+ } };
248
+ })() : option.mode === "consistent-line-length" ? (() => {
249
+ const lines = parseLines(sourceCode);
250
+ const headings = [];
251
+ return {
252
+ heading(node) {
253
+ const parsed = parseATXHeadingClosingSequence(sourceCode, node);
254
+ if (!parsed || !parsed.closingSequence) return;
255
+ headings.push({
256
+ node,
257
+ parsed
258
+ });
259
+ },
260
+ "root:exit"() {
261
+ let mostLongContentHeading = null;
262
+ for (const heading of headings) {
263
+ const contentLength = getContentLength(lines, heading.parsed);
264
+ if (mostLongContentHeading == null || contentLength > mostLongContentHeading.contentLength) {
265
+ const lineLength = getLineLength(lines, heading.parsed);
266
+ mostLongContentHeading = {
267
+ ...heading,
268
+ contentLength,
269
+ lineLength
270
+ };
271
+ }
272
+ }
273
+ if (!mostLongContentHeading) return;
274
+ let minLineLength = mostLongContentHeading.lineLength;
275
+ for (const heading of headings) {
276
+ const lineLength = getLineLength(lines, heading.parsed);
277
+ if (mostLongContentHeading.contentLength < lineLength && lineLength < minLineLength) minLineLength = Math.min(minLineLength, lineLength);
278
+ }
279
+ const getExpected = (_node, parsed) => {
280
+ return minLineLength - getContentLength(lines, parsed);
281
+ };
282
+ for (const { node } of headings) verifyATXHeadingClosingSequenceLength(node, getExpected);
283
+ }
284
+ };
285
+ })() : {};
286
+ /**
287
+ * Get the content length of the heading.
288
+ */
289
+ function getContentLength(lines, parsed) {
290
+ const line = lines.get(parsed.closingSequence.loc.start.line);
291
+ const beforeClosing = sourceCode.text.slice(line.range[0], parsed.closingSequence.range[0]);
292
+ return getTextWidth(beforeClosing);
293
+ }
294
+ /**
295
+ * Get the line length of the heading.
296
+ */
297
+ function getLineLength(lines, parsed) {
298
+ const line = lines.get(parsed.closingSequence.loc.start.line);
299
+ const lineText = sourceCode.text.slice(line.range[0], parsed.closingSequence.range[1]);
300
+ return getTextWidth(lineText);
301
+ }
302
+ }
303
+ });
304
+ /**
305
+ * Get the width of a text string.
306
+ */
307
+ function getTextWidth(text) {
308
+ if (!text.includes(" ")) return stringWidth(text);
309
+ if (!segmenter) segmenter = new Intl.Segmenter("en");
310
+ let width = 0;
311
+ for (const { segment: c } of segmenter.segment(text)) if (c === " ") width += 4 - width % 4;
312
+ else width += stringWidth(c);
313
+ return width;
314
+ }
315
+
316
+ //#endregion
317
+ //#region src/rules/atx-headings-closing-sequence.ts
318
+ var atx_headings_closing_sequence_default = createRule("atx-headings-closing-sequence", {
319
+ meta: {
320
+ type: "layout",
321
+ docs: {
322
+ description: "enforce consistent use of closing sequence in ATX headings.",
323
+ categories: [],
324
+ listCategory: "Stylistic"
325
+ },
326
+ fixable: "code",
327
+ hasSuggestions: false,
328
+ schema: [{
329
+ type: "object",
330
+ properties: { closingSequence: { enum: ["always", "never"] } },
331
+ additionalProperties: false
332
+ }],
333
+ messages: {
334
+ requireClosing: "ATX heading should have a closing sequence (e.g. '### heading ###').",
335
+ forbidClosing: "ATX heading should not have a closing sequence."
336
+ }
337
+ },
338
+ create(context) {
339
+ const sourceCode = context.sourceCode;
340
+ let closingSequence = "never";
341
+ const opt = context.options[0];
342
+ if (opt && typeof opt === "object" && typeof opt.closingSequence === "string") {
343
+ if (opt.closingSequence === "always" || opt.closingSequence === "never") closingSequence = opt.closingSequence;
344
+ }
345
+ return { heading(node) {
346
+ const parsed = parseATXHeadingClosingSequence(sourceCode, node);
347
+ if (!parsed) return;
348
+ if (closingSequence === "always") {
349
+ if (parsed.closingSequence) return;
350
+ context.report({
351
+ node,
352
+ messageId: "requireClosing",
353
+ fix(fixer) {
354
+ const insert = ` ${"#".repeat(node.depth)} `;
355
+ return fixer.insertTextAfter(node, insert);
356
+ }
357
+ });
358
+ } else if (closingSequence === "never") {
359
+ if (parsed.closingSequence == null) return;
360
+ context.report({
361
+ node,
362
+ loc: {
363
+ start: parsed.rawBefore.loc.start,
364
+ end: parsed.closingSequence.loc.end
365
+ },
366
+ messageId: "forbidClosing",
367
+ *fix(fixer) {
368
+ const removeRange = [parsed.rawBefore.range[0], parsed.closingSequence.range[1]];
369
+ const newHeadingText = sourceCode.text.slice(sourceCode.getRange(node)[0], removeRange[0]);
370
+ const newHeadingParsed = parseATXHeadingClosingSequenceFromText(newHeadingText);
371
+ if (newHeadingParsed) {
372
+ const escapeIndex = removeRange[0] - newHeadingParsed.rawAfter.length - 1;
373
+ yield fixer.insertTextBeforeRange([escapeIndex, escapeIndex], "\\");
374
+ }
375
+ yield fixer.removeRange(removeRange);
376
+ }
377
+ });
378
+ }
379
+ } };
380
+ }
381
+ });
382
+
383
+ //#endregion
384
+ //#region src/utils/ast.ts
385
+ /**
386
+ * Get the kind of code block.
387
+ */
388
+ function getCodeBlockKind(sourceCode, node) {
389
+ const text = sourceCode.getText(node);
390
+ return text.startsWith("```") ? "backtick-fenced" : text.startsWith("~~~") ? "tilde-fenced" : "indented";
391
+ }
392
+ /**
393
+ * Get the kind of link.
394
+ */
395
+ function getLinkKind(sourceCode, node) {
396
+ const text = sourceCode.getText(node);
397
+ return text.startsWith("[") ? "inline" : text.startsWith("<") && text.endsWith(">") ? "autolink" : "gfm-autolink";
398
+ }
399
+ /**
400
+ * Get the marker of a list item.
401
+ */
402
+ function getListItemMarker(sourceCode, node) {
403
+ const item = node.type === "list" ? node.children[0] || node : node;
404
+ const text = sourceCode.getText(item);
405
+ if (text.startsWith("-")) return {
406
+ kind: "-",
407
+ raw: "-"
408
+ };
409
+ if (text.startsWith("*")) return {
410
+ kind: "*",
411
+ raw: "*"
412
+ };
413
+ if (text.startsWith("+")) return {
414
+ kind: "+",
415
+ raw: "+"
416
+ };
417
+ const matchDot = /^(\d+)\./.exec(text);
418
+ if (matchDot) return {
419
+ kind: ".",
420
+ raw: matchDot[0],
421
+ sequence: Number(matchDot[1])
422
+ };
423
+ const matchParen = /^(\d+)\)/.exec(text);
424
+ return {
425
+ kind: ")",
426
+ raw: matchParen[0],
427
+ sequence: Number(matchParen[1])
428
+ };
429
+ }
430
+ /**
431
+ * Get the source location from a range in a node.
432
+ */
433
+ function getSourceLocationFromRange(sourceCode, node, range) {
434
+ const [nodeStart] = sourceCode.getRange(node);
435
+ let startLine, startColumn;
436
+ if (nodeStart <= range[0]) {
437
+ const loc = sourceCode.getLoc(node);
438
+ const beforeLines = sourceCode.text.slice(nodeStart, range[0]).split(/\n/u);
439
+ startLine = loc.start.line + beforeLines.length - 1;
440
+ startColumn = (beforeLines.length === 1 ? loc.start.column : 1) + (beforeLines.at(-1) || "").length;
441
+ } else {
442
+ const beforeLines = sourceCode.text.slice(0, range[0]).split(/\n/u);
443
+ startLine = beforeLines.length;
444
+ startColumn = 1 + (beforeLines.at(-1) || "").length;
445
+ }
446
+ const contentLines = sourceCode.text.slice(range[0], range[1]).split(/\n/u);
447
+ const endLine = startLine + contentLines.length - 1;
448
+ const endColumn = (contentLines.length === 1 ? startColumn : 1) + (contentLines.at(-1) || "").length;
449
+ return {
450
+ start: {
451
+ line: startLine,
452
+ column: startColumn
453
+ },
454
+ end: {
455
+ line: endLine,
456
+ column: endColumn
457
+ }
458
+ };
459
+ }
460
+
28
461
  //#endregion
29
462
  //#region src/rules/canonical-code-block-language.ts
30
463
  const DEFAULT_LANGUAGES = {
@@ -85,32 +518,17 @@ var canonical_code_block_language_default = createRule("canonical-code-block-lan
85
518
  const fenceMatch = fenceRegex.exec(nodeText.split("\n")[0]);
86
519
  if (!fenceMatch) return;
87
520
  const [, fence, langInfo] = fenceMatch;
88
- const langStart = nodeRange[0] + fence.length;
89
- const langEnd = langStart + langInfo.length;
90
- const nodeLoc = sourceCode.getLoc(node);
91
- const beforeFence = sourceCode.text.slice(nodeRange[0], langStart);
92
- const beforeLines = beforeFence.split(/\n/u);
93
- const line = nodeLoc.start.line + beforeLines.length - 1;
94
- const column = (beforeLines.length === 1 ? nodeLoc.start.column : 0) + (beforeLines.at(-1) || "").length;
521
+ const range = [nodeRange[0] + fence.length, nodeRange[0] + fence.length + langInfo.length];
95
522
  context.report({
96
523
  node,
97
- loc: {
98
- start: {
99
- line,
100
- column
101
- },
102
- end: {
103
- line,
104
- column: column + langInfo.length
105
- }
106
- },
524
+ loc: getSourceLocationFromRange(sourceCode, node, range),
107
525
  messageId: "useCanonical",
108
526
  data: {
109
527
  canonical,
110
528
  current
111
529
  },
112
530
  fix(fixer) {
113
- return fixer.replaceTextRange([langStart, langEnd], canonical);
531
+ return fixer.replaceTextRange(range, canonical);
114
532
  }
115
533
  });
116
534
  } };
@@ -158,6 +576,2079 @@ var definitions_last_default = createRule("definitions-last", {
158
576
  }
159
577
  });
160
578
 
579
+ //#endregion
580
+ //#region src/utils/regexp.ts
581
+ const RE_REGEXP_STR = /^\/(.+)\/([A-Za-z]*)$/u;
582
+ /**
583
+ * Convert a string to the `RegExp`.
584
+ * Normal strings (e.g. `"foo"`) is converted to `/^foo$/` of `RegExp`.
585
+ * Strings like `"/^foo/i"` are converted to `/^foo/i` of `RegExp`.
586
+ *
587
+ * @param {string} string The string to convert.
588
+ * @returns {RegExp} Returns the `RegExp`.
589
+ */
590
+ function toRegExp(string) {
591
+ const parts = RE_REGEXP_STR.exec(string);
592
+ if (parts) return new RegExp(parts[1], parts[2]);
593
+ return { test: (s) => s === string };
594
+ }
595
+ /**
596
+ * Checks whether given string is regexp string
597
+ * @param {string} string
598
+ * @returns {boolean}
599
+ */
600
+ function isRegExp(string) {
601
+ return Boolean(RE_REGEXP_STR.test(string));
602
+ }
603
+
604
+ //#endregion
605
+ //#region src/utils/resources/gh-emoji.ts
606
+ const GH_EMOJI_MAP = {
607
+ "100": "💯",
608
+ "1234": "🔢",
609
+ "+1": "👍",
610
+ "-1": "👎",
611
+ "1st_place_medal": "🥇",
612
+ "2nd_place_medal": "🥈",
613
+ "3rd_place_medal": "🥉",
614
+ "8ball": "🎱",
615
+ a: "🅰",
616
+ ab: "🆎",
617
+ abacus: "🧮",
618
+ abc: "🔤",
619
+ abcd: "🔡",
620
+ accept: "🉑",
621
+ accordion: "🪗",
622
+ adhesive_bandage: "🩹",
623
+ adult: "🧑",
624
+ aerial_tramway: "🚡",
625
+ afghanistan: "🇦🇫",
626
+ airplane: "✈",
627
+ aland_islands: "🇦🇽",
628
+ alarm_clock: "⏰",
629
+ albania: "🇦🇱",
630
+ alembic: "⚗",
631
+ algeria: "🇩🇿",
632
+ alien: "👽",
633
+ ambulance: "🚑",
634
+ american_samoa: "🇦🇸",
635
+ amphora: "🏺",
636
+ anatomical_heart: "🫀",
637
+ anchor: "⚓",
638
+ andorra: "🇦🇩",
639
+ angel: "👼",
640
+ anger: "💢",
641
+ angola: "🇦🇴",
642
+ angry: "😠",
643
+ anguilla: "🇦🇮",
644
+ anguished: "😧",
645
+ ant: "🐜",
646
+ antarctica: "🇦🇶",
647
+ antigua_barbuda: "🇦🇬",
648
+ apple: "🍎",
649
+ aquarius: "♒",
650
+ argentina: "🇦🇷",
651
+ aries: "♈",
652
+ armenia: "🇦🇲",
653
+ arrow_backward: "◀",
654
+ arrow_double_down: "⏬",
655
+ arrow_double_up: "⏫",
656
+ arrow_down: "⬇",
657
+ arrow_down_small: "🔽",
658
+ arrow_forward: "▶",
659
+ arrow_heading_down: "⤵",
660
+ arrow_heading_up: "⤴",
661
+ arrow_left: "⬅",
662
+ arrow_lower_left: "↙",
663
+ arrow_lower_right: "↘",
664
+ arrow_right: "➡",
665
+ arrow_right_hook: "↪",
666
+ arrow_up: "⬆",
667
+ arrow_up_down: "↕",
668
+ arrow_up_small: "🔼",
669
+ arrow_upper_left: "↖",
670
+ arrow_upper_right: "↗",
671
+ arrows_clockwise: "🔃",
672
+ arrows_counterclockwise: "🔄",
673
+ art: "🎨",
674
+ articulated_lorry: "🚛",
675
+ artificial_satellite: "🛰",
676
+ artist: "🧑‍🎨",
677
+ aruba: "🇦🇼",
678
+ ascension_island: "🇦🇨",
679
+ asterisk: "*️⃣",
680
+ astonished: "😲",
681
+ astronaut: "🧑‍🚀",
682
+ athletic_shoe: "👟",
683
+ atm: "🏧",
684
+ atom_symbol: "⚛",
685
+ australia: "🇦🇺",
686
+ austria: "🇦🇹",
687
+ auto_rickshaw: "🛺",
688
+ avocado: "🥑",
689
+ axe: "🪓",
690
+ azerbaijan: "🇦🇿",
691
+ b: "🅱",
692
+ baby: "👶",
693
+ baby_bottle: "🍼",
694
+ baby_chick: "🐤",
695
+ baby_symbol: "🚼",
696
+ back: "🔙",
697
+ bacon: "🥓",
698
+ badger: "🦡",
699
+ badminton: "🏸",
700
+ bagel: "🥯",
701
+ baggage_claim: "🛄",
702
+ baguette_bread: "🥖",
703
+ bahamas: "🇧🇸",
704
+ bahrain: "🇧🇭",
705
+ balance_scale: "⚖",
706
+ bald_man: "👨‍🦲",
707
+ bald_woman: "👩‍🦲",
708
+ ballet_shoes: "🩰",
709
+ balloon: "🎈",
710
+ ballot_box: "🗳",
711
+ ballot_box_with_check: "☑",
712
+ bamboo: "🎍",
713
+ banana: "🍌",
714
+ bangbang: "‼",
715
+ bangladesh: "🇧🇩",
716
+ banjo: "🪕",
717
+ bank: "🏦",
718
+ bar_chart: "📊",
719
+ barbados: "🇧🇧",
720
+ barber: "💈",
721
+ baseball: "⚾",
722
+ basket: "🧺",
723
+ basketball: "🏀",
724
+ basketball_man: "⛹‍♂",
725
+ basketball_woman: "⛹‍♀",
726
+ bat: "🦇",
727
+ bath: "🛀",
728
+ bathtub: "🛁",
729
+ battery: "🔋",
730
+ beach_umbrella: "🏖",
731
+ beans: "🫘",
732
+ bear: "🐻",
733
+ bearded_person: "🧔",
734
+ beaver: "🦫",
735
+ bed: "🛏",
736
+ bee: "🐝",
737
+ beer: "🍺",
738
+ beers: "🍻",
739
+ beetle: "🪲",
740
+ beginner: "🔰",
741
+ belarus: "🇧🇾",
742
+ belgium: "🇧🇪",
743
+ belize: "🇧🇿",
744
+ bell: "🔔",
745
+ bell_pepper: "🫑",
746
+ bellhop_bell: "🛎",
747
+ benin: "🇧🇯",
748
+ bento: "🍱",
749
+ bermuda: "🇧🇲",
750
+ beverage_box: "🧃",
751
+ bhutan: "🇧🇹",
752
+ bicyclist: "🚴",
753
+ bike: "🚲",
754
+ biking_man: "🚴‍♂",
755
+ biking_woman: "🚴‍♀",
756
+ bikini: "👙",
757
+ billed_cap: "🧢",
758
+ biohazard: "☣",
759
+ bird: "🐦",
760
+ birthday: "🎂",
761
+ bison: "🦬",
762
+ biting_lip: "🫦",
763
+ black_bird: "🐦‍⬛",
764
+ black_cat: "🐈‍⬛",
765
+ black_circle: "⚫",
766
+ black_flag: "🏴",
767
+ black_heart: "🖤",
768
+ black_joker: "🃏",
769
+ black_large_square: "⬛",
770
+ black_medium_small_square: "◾",
771
+ black_medium_square: "◼",
772
+ black_nib: "✒",
773
+ black_small_square: "▪",
774
+ black_square_button: "🔲",
775
+ blond_haired_man: "👱‍♂",
776
+ blond_haired_person: "👱",
777
+ blond_haired_woman: "👱‍♀",
778
+ blonde_woman: "👱‍♀",
779
+ blossom: "🌼",
780
+ blowfish: "🐡",
781
+ blue_book: "📘",
782
+ blue_car: "🚙",
783
+ blue_heart: "💙",
784
+ blue_square: "🟦",
785
+ blueberries: "🫐",
786
+ blush: "😊",
787
+ boar: "🐗",
788
+ boat: "⛵",
789
+ bolivia: "🇧🇴",
790
+ bomb: "💣",
791
+ bone: "🦴",
792
+ book: "📖",
793
+ bookmark: "🔖",
794
+ bookmark_tabs: "📑",
795
+ books: "📚",
796
+ boom: "💥",
797
+ boomerang: "🪃",
798
+ boot: "👢",
799
+ bosnia_herzegovina: "🇧🇦",
800
+ botswana: "🇧🇼",
801
+ bouncing_ball_man: "⛹‍♂",
802
+ bouncing_ball_person: "⛹",
803
+ bouncing_ball_woman: "⛹‍♀",
804
+ bouquet: "💐",
805
+ bouvet_island: "🇧🇻",
806
+ bow: "🙇",
807
+ bow_and_arrow: "🏹",
808
+ bowing_man: "🙇‍♂",
809
+ bowing_woman: "🙇‍♀",
810
+ bowl_with_spoon: "🥣",
811
+ bowling: "🎳",
812
+ boxing_glove: "🥊",
813
+ boy: "👦",
814
+ brain: "🧠",
815
+ brazil: "🇧🇷",
816
+ bread: "🍞",
817
+ breast_feeding: "🤱",
818
+ bricks: "🧱",
819
+ bride_with_veil: "👰‍♀",
820
+ bridge_at_night: "🌉",
821
+ briefcase: "💼",
822
+ british_indian_ocean_territory: "🇮🇴",
823
+ british_virgin_islands: "🇻🇬",
824
+ broccoli: "🥦",
825
+ broken_heart: "💔",
826
+ broom: "🧹",
827
+ brown_circle: "🟤",
828
+ brown_heart: "🤎",
829
+ brown_square: "🟫",
830
+ brunei: "🇧🇳",
831
+ bubble_tea: "🧋",
832
+ bubbles: "🫧",
833
+ bucket: "🪣",
834
+ bug: "🐛",
835
+ building_construction: "🏗",
836
+ bulb: "💡",
837
+ bulgaria: "🇧🇬",
838
+ bullettrain_front: "🚅",
839
+ bullettrain_side: "🚄",
840
+ burkina_faso: "🇧🇫",
841
+ burrito: "🌯",
842
+ burundi: "🇧🇮",
843
+ bus: "🚌",
844
+ business_suit_levitating: "🕴",
845
+ busstop: "🚏",
846
+ bust_in_silhouette: "👤",
847
+ busts_in_silhouette: "👥",
848
+ butter: "🧈",
849
+ butterfly: "🦋",
850
+ cactus: "🌵",
851
+ cake: "🍰",
852
+ calendar: "📆",
853
+ call_me_hand: "🤙",
854
+ calling: "📲",
855
+ cambodia: "🇰🇭",
856
+ camel: "🐫",
857
+ camera: "📷",
858
+ camera_flash: "📸",
859
+ cameroon: "🇨🇲",
860
+ camping: "🏕",
861
+ canada: "🇨🇦",
862
+ canary_islands: "🇮🇨",
863
+ cancer: "♋",
864
+ candle: "🕯",
865
+ candy: "🍬",
866
+ canned_food: "🥫",
867
+ canoe: "🛶",
868
+ cape_verde: "🇨🇻",
869
+ capital_abcd: "🔠",
870
+ capricorn: "♑",
871
+ car: "🚗",
872
+ card_file_box: "🗃",
873
+ card_index: "📇",
874
+ card_index_dividers: "🗂",
875
+ caribbean_netherlands: "🇧🇶",
876
+ carousel_horse: "🎠",
877
+ carpentry_saw: "🪚",
878
+ carrot: "🥕",
879
+ cartwheeling: "🤸",
880
+ cat: "🐱",
881
+ cat2: "🐈",
882
+ cayman_islands: "🇰🇾",
883
+ cd: "💿",
884
+ central_african_republic: "🇨🇫",
885
+ ceuta_melilla: "🇪🇦",
886
+ chad: "🇹🇩",
887
+ chains: "⛓",
888
+ chair: "🪑",
889
+ champagne: "🍾",
890
+ chart: "💹",
891
+ chart_with_downwards_trend: "📉",
892
+ chart_with_upwards_trend: "📈",
893
+ checkered_flag: "🏁",
894
+ cheese: "🧀",
895
+ cherries: "🍒",
896
+ cherry_blossom: "🌸",
897
+ chess_pawn: "♟",
898
+ chestnut: "🌰",
899
+ chicken: "🐔",
900
+ child: "🧒",
901
+ children_crossing: "🚸",
902
+ chile: "🇨🇱",
903
+ chipmunk: "🐿",
904
+ chocolate_bar: "🍫",
905
+ chopsticks: "🥢",
906
+ christmas_island: "🇨🇽",
907
+ christmas_tree: "🎄",
908
+ church: "⛪",
909
+ cinema: "🎦",
910
+ circus_tent: "🎪",
911
+ city_sunrise: "🌇",
912
+ city_sunset: "🌆",
913
+ cityscape: "🏙",
914
+ cl: "🆑",
915
+ clamp: "🗜",
916
+ clap: "👏",
917
+ clapper: "🎬",
918
+ classical_building: "🏛",
919
+ climbing: "🧗",
920
+ climbing_man: "🧗‍♂",
921
+ climbing_woman: "🧗‍♀",
922
+ clinking_glasses: "🥂",
923
+ clipboard: "📋",
924
+ clipperton_island: "🇨🇵",
925
+ clock1: "🕐",
926
+ clock10: "🕙",
927
+ clock1030: "🕥",
928
+ clock11: "🕚",
929
+ clock1130: "🕦",
930
+ clock12: "🕛",
931
+ clock1230: "🕧",
932
+ clock130: "🕜",
933
+ clock2: "🕑",
934
+ clock230: "🕝",
935
+ clock3: "🕒",
936
+ clock330: "🕞",
937
+ clock4: "🕓",
938
+ clock430: "🕟",
939
+ clock5: "🕔",
940
+ clock530: "🕠",
941
+ clock6: "🕕",
942
+ clock630: "🕡",
943
+ clock7: "🕖",
944
+ clock730: "🕢",
945
+ clock8: "🕗",
946
+ clock830: "🕣",
947
+ clock9: "🕘",
948
+ clock930: "🕤",
949
+ closed_book: "📕",
950
+ closed_lock_with_key: "🔐",
951
+ closed_umbrella: "🌂",
952
+ cloud: "☁",
953
+ cloud_with_lightning: "🌩",
954
+ cloud_with_lightning_and_rain: "⛈",
955
+ cloud_with_rain: "🌧",
956
+ cloud_with_snow: "🌨",
957
+ clown_face: "🤡",
958
+ clubs: "♣",
959
+ cn: "🇨🇳",
960
+ coat: "🧥",
961
+ cockroach: "🪳",
962
+ cocktail: "🍸",
963
+ coconut: "🥥",
964
+ cocos_islands: "🇨🇨",
965
+ coffee: "☕",
966
+ coffin: "⚰",
967
+ coin: "🪙",
968
+ cold_face: "🥶",
969
+ cold_sweat: "😰",
970
+ collision: "💥",
971
+ colombia: "🇨🇴",
972
+ comet: "☄",
973
+ comoros: "🇰🇲",
974
+ compass: "🧭",
975
+ computer: "💻",
976
+ computer_mouse: "🖱",
977
+ confetti_ball: "🎊",
978
+ confounded: "😖",
979
+ confused: "😕",
980
+ congo_brazzaville: "🇨🇬",
981
+ congo_kinshasa: "🇨🇩",
982
+ congratulations: "㊗",
983
+ construction: "🚧",
984
+ construction_worker: "👷",
985
+ construction_worker_man: "👷‍♂",
986
+ construction_worker_woman: "👷‍♀",
987
+ control_knobs: "🎛",
988
+ convenience_store: "🏪",
989
+ cook: "🧑‍🍳",
990
+ cook_islands: "🇨🇰",
991
+ cookie: "🍪",
992
+ cool: "🆒",
993
+ cop: "👮",
994
+ copyright: "©",
995
+ coral: "🪸",
996
+ corn: "🌽",
997
+ costa_rica: "🇨🇷",
998
+ cote_divoire: "🇨🇮",
999
+ couch_and_lamp: "🛋",
1000
+ couple: "👫",
1001
+ couple_with_heart: "💑",
1002
+ couple_with_heart_man_man: "👨‍❤‍👨",
1003
+ couple_with_heart_woman_man: "👩‍❤‍👨",
1004
+ couple_with_heart_woman_woman: "👩‍❤‍👩",
1005
+ couplekiss: "💏",
1006
+ couplekiss_man_man: "👨‍❤‍💋‍👨",
1007
+ couplekiss_man_woman: "👩‍❤‍💋‍👨",
1008
+ couplekiss_woman_woman: "👩‍❤‍💋‍👩",
1009
+ cow: "🐮",
1010
+ cow2: "🐄",
1011
+ cowboy_hat_face: "🤠",
1012
+ crab: "🦀",
1013
+ crayon: "🖍",
1014
+ credit_card: "💳",
1015
+ crescent_moon: "🌙",
1016
+ cricket: "🦗",
1017
+ cricket_game: "🏏",
1018
+ croatia: "🇭🇷",
1019
+ crocodile: "🐊",
1020
+ croissant: "🥐",
1021
+ crossed_fingers: "🤞",
1022
+ crossed_flags: "🎌",
1023
+ crossed_swords: "⚔",
1024
+ crown: "👑",
1025
+ crutch: "🩼",
1026
+ cry: "😢",
1027
+ crying_cat_face: "😿",
1028
+ crystal_ball: "🔮",
1029
+ cuba: "🇨🇺",
1030
+ cucumber: "🥒",
1031
+ cup_with_straw: "🥤",
1032
+ cupcake: "🧁",
1033
+ cupid: "💘",
1034
+ curacao: "🇨🇼",
1035
+ curling_stone: "🥌",
1036
+ curly_haired_man: "👨‍🦱",
1037
+ curly_haired_woman: "👩‍🦱",
1038
+ curly_loop: "➰",
1039
+ currency_exchange: "💱",
1040
+ curry: "🍛",
1041
+ cursing_face: "🤬",
1042
+ custard: "🍮",
1043
+ customs: "🛃",
1044
+ cut_of_meat: "🥩",
1045
+ cyclone: "🌀",
1046
+ cyprus: "🇨🇾",
1047
+ czech_republic: "🇨🇿",
1048
+ dagger: "🗡",
1049
+ dancer: "💃",
1050
+ dancers: "👯",
1051
+ dancing_men: "👯‍♂",
1052
+ dancing_women: "👯‍♀",
1053
+ dango: "🍡",
1054
+ dark_sunglasses: "🕶",
1055
+ dart: "🎯",
1056
+ dash: "💨",
1057
+ date: "📅",
1058
+ de: "🇩🇪",
1059
+ deaf_man: "🧏‍♂",
1060
+ deaf_person: "🧏",
1061
+ deaf_woman: "🧏‍♀",
1062
+ deciduous_tree: "🌳",
1063
+ deer: "🦌",
1064
+ denmark: "🇩🇰",
1065
+ department_store: "🏬",
1066
+ derelict_house: "🏚",
1067
+ desert: "🏜",
1068
+ desert_island: "🏝",
1069
+ desktop_computer: "🖥",
1070
+ detective: "🕵",
1071
+ diamond_shape_with_a_dot_inside: "💠",
1072
+ diamonds: "♦",
1073
+ diego_garcia: "🇩🇬",
1074
+ disappointed: "😞",
1075
+ disappointed_relieved: "😥",
1076
+ disguised_face: "🥸",
1077
+ diving_mask: "🤿",
1078
+ diya_lamp: "🪔",
1079
+ dizzy: "💫",
1080
+ dizzy_face: "😵",
1081
+ djibouti: "🇩🇯",
1082
+ dna: "🧬",
1083
+ do_not_litter: "🚯",
1084
+ dodo: "🦤",
1085
+ dog: "🐶",
1086
+ dog2: "🐕",
1087
+ dollar: "💵",
1088
+ dolls: "🎎",
1089
+ dolphin: "🐬",
1090
+ dominica: "🇩🇲",
1091
+ dominican_republic: "🇩🇴",
1092
+ donkey: "🫏",
1093
+ door: "🚪",
1094
+ dotted_line_face: "🫥",
1095
+ doughnut: "🍩",
1096
+ dove: "🕊",
1097
+ dragon: "🐉",
1098
+ dragon_face: "🐲",
1099
+ dress: "👗",
1100
+ dromedary_camel: "🐪",
1101
+ drooling_face: "🤤",
1102
+ drop_of_blood: "🩸",
1103
+ droplet: "💧",
1104
+ drum: "🥁",
1105
+ duck: "🦆",
1106
+ dumpling: "🥟",
1107
+ dvd: "📀",
1108
+ "e-mail": "📧",
1109
+ eagle: "🦅",
1110
+ ear: "👂",
1111
+ ear_of_rice: "🌾",
1112
+ ear_with_hearing_aid: "🦻",
1113
+ earth_africa: "🌍",
1114
+ earth_americas: "🌎",
1115
+ earth_asia: "🌏",
1116
+ ecuador: "🇪🇨",
1117
+ egg: "🥚",
1118
+ eggplant: "🍆",
1119
+ egypt: "🇪🇬",
1120
+ eight: "8️⃣",
1121
+ eight_pointed_black_star: "✴",
1122
+ eight_spoked_asterisk: "✳",
1123
+ eject_button: "⏏",
1124
+ el_salvador: "🇸🇻",
1125
+ electric_plug: "🔌",
1126
+ elephant: "🐘",
1127
+ elevator: "🛗",
1128
+ elf: "🧝",
1129
+ elf_man: "🧝‍♂",
1130
+ elf_woman: "🧝‍♀",
1131
+ email: "📧",
1132
+ empty_nest: "🪹",
1133
+ end: "🔚",
1134
+ england: "🏴󠁧󠁢󠁥󠁮󠁧󠁿",
1135
+ envelope: "✉",
1136
+ envelope_with_arrow: "📩",
1137
+ equatorial_guinea: "🇬🇶",
1138
+ eritrea: "🇪🇷",
1139
+ es: "🇪🇸",
1140
+ estonia: "🇪🇪",
1141
+ ethiopia: "🇪🇹",
1142
+ eu: "🇪🇺",
1143
+ euro: "💶",
1144
+ european_castle: "🏰",
1145
+ european_post_office: "🏤",
1146
+ european_union: "🇪🇺",
1147
+ evergreen_tree: "🌲",
1148
+ exclamation: "❗",
1149
+ exploding_head: "🤯",
1150
+ expressionless: "😑",
1151
+ eye: "👁",
1152
+ eye_speech_bubble: "👁‍🗨",
1153
+ eyeglasses: "👓",
1154
+ eyes: "👀",
1155
+ face_exhaling: "😮‍💨",
1156
+ face_holding_back_tears: "🥹",
1157
+ face_in_clouds: "😶‍🌫",
1158
+ face_with_diagonal_mouth: "🫤",
1159
+ face_with_head_bandage: "🤕",
1160
+ face_with_open_eyes_and_hand_over_mouth: "🫢",
1161
+ face_with_peeking_eye: "🫣",
1162
+ face_with_spiral_eyes: "😵‍💫",
1163
+ face_with_thermometer: "🤒",
1164
+ facepalm: "🤦",
1165
+ facepunch: "👊",
1166
+ factory: "🏭",
1167
+ factory_worker: "🧑‍🏭",
1168
+ fairy: "🧚",
1169
+ fairy_man: "🧚‍♂",
1170
+ fairy_woman: "🧚‍♀",
1171
+ falafel: "🧆",
1172
+ falkland_islands: "🇫🇰",
1173
+ fallen_leaf: "🍂",
1174
+ family: "👪",
1175
+ family_man_boy: "👨‍👦",
1176
+ family_man_boy_boy: "👨‍👦‍👦",
1177
+ family_man_girl: "👨‍👧",
1178
+ family_man_girl_boy: "👨‍👧‍👦",
1179
+ family_man_girl_girl: "👨‍👧‍👧",
1180
+ family_man_man_boy: "👨‍👨‍👦",
1181
+ family_man_man_boy_boy: "👨‍👨‍👦‍👦",
1182
+ family_man_man_girl: "👨‍👨‍👧",
1183
+ family_man_man_girl_boy: "👨‍👨‍👧‍👦",
1184
+ family_man_man_girl_girl: "👨‍👨‍👧‍👧",
1185
+ family_man_woman_boy: "👨‍👩‍👦",
1186
+ family_man_woman_boy_boy: "👨‍👩‍👦‍👦",
1187
+ family_man_woman_girl: "👨‍👩‍👧",
1188
+ family_man_woman_girl_boy: "👨‍👩‍👧‍👦",
1189
+ family_man_woman_girl_girl: "👨‍👩‍👧‍👧",
1190
+ family_woman_boy: "👩‍👦",
1191
+ family_woman_boy_boy: "👩‍👦‍👦",
1192
+ family_woman_girl: "👩‍👧",
1193
+ family_woman_girl_boy: "👩‍👧‍👦",
1194
+ family_woman_girl_girl: "👩‍👧‍👧",
1195
+ family_woman_woman_boy: "👩‍👩‍👦",
1196
+ family_woman_woman_boy_boy: "👩‍👩‍👦‍👦",
1197
+ family_woman_woman_girl: "👩‍👩‍👧",
1198
+ family_woman_woman_girl_boy: "👩‍👩‍👧‍👦",
1199
+ family_woman_woman_girl_girl: "👩‍👩‍👧‍👧",
1200
+ farmer: "🧑‍🌾",
1201
+ faroe_islands: "🇫🇴",
1202
+ fast_forward: "⏩",
1203
+ fax: "📠",
1204
+ fearful: "😨",
1205
+ feather: "🪶",
1206
+ feet: "🐾",
1207
+ female_detective: "🕵‍♀",
1208
+ female_sign: "♀",
1209
+ ferris_wheel: "🎡",
1210
+ ferry: "⛴",
1211
+ field_hockey: "🏑",
1212
+ fiji: "🇫🇯",
1213
+ file_cabinet: "🗄",
1214
+ file_folder: "📁",
1215
+ film_projector: "📽",
1216
+ film_strip: "🎞",
1217
+ finland: "🇫🇮",
1218
+ fire: "🔥",
1219
+ fire_engine: "🚒",
1220
+ fire_extinguisher: "🧯",
1221
+ firecracker: "🧨",
1222
+ firefighter: "🧑‍🚒",
1223
+ fireworks: "🎆",
1224
+ first_quarter_moon: "🌓",
1225
+ first_quarter_moon_with_face: "🌛",
1226
+ fish: "🐟",
1227
+ fish_cake: "🍥",
1228
+ fishing_pole_and_fish: "🎣",
1229
+ fist: "✊",
1230
+ fist_left: "🤛",
1231
+ fist_oncoming: "👊",
1232
+ fist_raised: "✊",
1233
+ fist_right: "🤜",
1234
+ five: "5️⃣",
1235
+ flags: "🎏",
1236
+ flamingo: "🦩",
1237
+ flashlight: "🔦",
1238
+ flat_shoe: "🥿",
1239
+ flatbread: "🫓",
1240
+ fleur_de_lis: "⚜",
1241
+ flight_arrival: "🛬",
1242
+ flight_departure: "🛫",
1243
+ flipper: "🐬",
1244
+ floppy_disk: "💾",
1245
+ flower_playing_cards: "🎴",
1246
+ flushed: "😳",
1247
+ flute: "🪈",
1248
+ fly: "🪰",
1249
+ flying_disc: "🥏",
1250
+ flying_saucer: "🛸",
1251
+ fog: "🌫",
1252
+ foggy: "🌁",
1253
+ folding_hand_fan: "🪭",
1254
+ fondue: "🫕",
1255
+ foot: "🦶",
1256
+ football: "🏈",
1257
+ footprints: "👣",
1258
+ fork_and_knife: "🍴",
1259
+ fortune_cookie: "🥠",
1260
+ fountain: "⛲",
1261
+ fountain_pen: "🖋",
1262
+ four: "4️⃣",
1263
+ four_leaf_clover: "🍀",
1264
+ fox_face: "🦊",
1265
+ fr: "🇫🇷",
1266
+ framed_picture: "🖼",
1267
+ free: "🆓",
1268
+ french_guiana: "🇬🇫",
1269
+ french_polynesia: "🇵🇫",
1270
+ french_southern_territories: "🇹🇫",
1271
+ fried_egg: "🍳",
1272
+ fried_shrimp: "🍤",
1273
+ fries: "🍟",
1274
+ frog: "🐸",
1275
+ frowning: "😦",
1276
+ frowning_face: "☹",
1277
+ frowning_man: "🙍‍♂",
1278
+ frowning_person: "🙍",
1279
+ frowning_woman: "🙍‍♀",
1280
+ fu: "🖕",
1281
+ fuelpump: "⛽",
1282
+ full_moon: "🌕",
1283
+ full_moon_with_face: "🌝",
1284
+ funeral_urn: "⚱",
1285
+ gabon: "🇬🇦",
1286
+ gambia: "🇬🇲",
1287
+ game_die: "🎲",
1288
+ garlic: "🧄",
1289
+ gb: "🇬🇧",
1290
+ gear: "⚙",
1291
+ gem: "💎",
1292
+ gemini: "♊",
1293
+ genie: "🧞",
1294
+ genie_man: "🧞‍♂",
1295
+ genie_woman: "🧞‍♀",
1296
+ georgia: "🇬🇪",
1297
+ ghana: "🇬🇭",
1298
+ ghost: "👻",
1299
+ gibraltar: "🇬🇮",
1300
+ gift: "🎁",
1301
+ gift_heart: "💝",
1302
+ ginger_root: "🫚",
1303
+ giraffe: "🦒",
1304
+ girl: "👧",
1305
+ globe_with_meridians: "🌐",
1306
+ gloves: "🧤",
1307
+ goal_net: "🥅",
1308
+ goat: "🐐",
1309
+ goggles: "🥽",
1310
+ golf: "⛳",
1311
+ golfing: "🏌",
1312
+ golfing_man: "🏌‍♂",
1313
+ golfing_woman: "🏌‍♀",
1314
+ goose: "🪿",
1315
+ gorilla: "🦍",
1316
+ grapes: "🍇",
1317
+ greece: "🇬🇷",
1318
+ green_apple: "🍏",
1319
+ green_book: "📗",
1320
+ green_circle: "🟢",
1321
+ green_heart: "💚",
1322
+ green_salad: "🥗",
1323
+ green_square: "🟩",
1324
+ greenland: "🇬🇱",
1325
+ grenada: "🇬🇩",
1326
+ grey_exclamation: "❕",
1327
+ grey_heart: "🩶",
1328
+ grey_question: "❔",
1329
+ grimacing: "😬",
1330
+ grin: "😁",
1331
+ grinning: "😀",
1332
+ guadeloupe: "🇬🇵",
1333
+ guam: "🇬🇺",
1334
+ guard: "💂",
1335
+ guardsman: "💂‍♂",
1336
+ guardswoman: "💂‍♀",
1337
+ guatemala: "🇬🇹",
1338
+ guernsey: "🇬🇬",
1339
+ guide_dog: "🦮",
1340
+ guinea: "🇬🇳",
1341
+ guinea_bissau: "🇬🇼",
1342
+ guitar: "🎸",
1343
+ gun: "🔫",
1344
+ guyana: "🇬🇾",
1345
+ hair_pick: "🪮",
1346
+ haircut: "💇",
1347
+ haircut_man: "💇‍♂",
1348
+ haircut_woman: "💇‍♀",
1349
+ haiti: "🇭🇹",
1350
+ hamburger: "🍔",
1351
+ hammer: "🔨",
1352
+ hammer_and_pick: "⚒",
1353
+ hammer_and_wrench: "🛠",
1354
+ hamsa: "🪬",
1355
+ hamster: "🐹",
1356
+ hand: "✋",
1357
+ hand_over_mouth: "🤭",
1358
+ hand_with_index_finger_and_thumb_crossed: "🫰",
1359
+ handbag: "👜",
1360
+ handball_person: "🤾",
1361
+ handshake: "🤝",
1362
+ hankey: "💩",
1363
+ hash: "#️⃣",
1364
+ hatched_chick: "🐥",
1365
+ hatching_chick: "🐣",
1366
+ headphones: "🎧",
1367
+ headstone: "🪦",
1368
+ health_worker: "🧑‍⚕",
1369
+ hear_no_evil: "🙉",
1370
+ heard_mcdonald_islands: "🇭🇲",
1371
+ heart: "❤",
1372
+ heart_decoration: "💟",
1373
+ heart_eyes: "😍",
1374
+ heart_eyes_cat: "😻",
1375
+ heart_hands: "🫶",
1376
+ heart_on_fire: "❤‍🔥",
1377
+ heartbeat: "💓",
1378
+ heartpulse: "💗",
1379
+ hearts: "♥",
1380
+ heavy_check_mark: "✔",
1381
+ heavy_division_sign: "➗",
1382
+ heavy_dollar_sign: "💲",
1383
+ heavy_equals_sign: "🟰",
1384
+ heavy_exclamation_mark: "❗",
1385
+ heavy_heart_exclamation: "❣",
1386
+ heavy_minus_sign: "➖",
1387
+ heavy_multiplication_x: "✖",
1388
+ heavy_plus_sign: "➕",
1389
+ hedgehog: "🦔",
1390
+ helicopter: "🚁",
1391
+ herb: "🌿",
1392
+ hibiscus: "🌺",
1393
+ high_brightness: "🔆",
1394
+ high_heel: "👠",
1395
+ hiking_boot: "🥾",
1396
+ hindu_temple: "🛕",
1397
+ hippopotamus: "🦛",
1398
+ hocho: "🔪",
1399
+ hole: "🕳",
1400
+ honduras: "🇭🇳",
1401
+ honey_pot: "🍯",
1402
+ honeybee: "🐝",
1403
+ hong_kong: "🇭🇰",
1404
+ hook: "🪝",
1405
+ horse: "🐴",
1406
+ horse_racing: "🏇",
1407
+ hospital: "🏥",
1408
+ hot_face: "🥵",
1409
+ hot_pepper: "🌶",
1410
+ hotdog: "🌭",
1411
+ hotel: "🏨",
1412
+ hotsprings: "♨",
1413
+ hourglass: "⌛",
1414
+ hourglass_flowing_sand: "⏳",
1415
+ house: "🏠",
1416
+ house_with_garden: "🏡",
1417
+ houses: "🏘",
1418
+ hugs: "🤗",
1419
+ hungary: "🇭🇺",
1420
+ hushed: "😯",
1421
+ hut: "🛖",
1422
+ hyacinth: "🪻",
1423
+ ice_cream: "🍨",
1424
+ ice_cube: "🧊",
1425
+ ice_hockey: "🏒",
1426
+ ice_skate: "⛸",
1427
+ icecream: "🍦",
1428
+ iceland: "🇮🇸",
1429
+ id: "🆔",
1430
+ identification_card: "🪪",
1431
+ ideograph_advantage: "🉐",
1432
+ imp: "👿",
1433
+ inbox_tray: "📥",
1434
+ incoming_envelope: "📨",
1435
+ index_pointing_at_the_viewer: "🫵",
1436
+ india: "🇮🇳",
1437
+ indonesia: "🇮🇩",
1438
+ infinity: "♾",
1439
+ information_desk_person: "💁",
1440
+ information_source: "ℹ",
1441
+ innocent: "😇",
1442
+ interrobang: "⁉",
1443
+ iphone: "📱",
1444
+ iran: "🇮🇷",
1445
+ iraq: "🇮🇶",
1446
+ ireland: "🇮🇪",
1447
+ isle_of_man: "🇮🇲",
1448
+ israel: "🇮🇱",
1449
+ it: "🇮🇹",
1450
+ izakaya_lantern: "🏮",
1451
+ jack_o_lantern: "🎃",
1452
+ jamaica: "🇯🇲",
1453
+ japan: "🗾",
1454
+ japanese_castle: "🏯",
1455
+ japanese_goblin: "👺",
1456
+ japanese_ogre: "👹",
1457
+ jar: "🫙",
1458
+ jeans: "👖",
1459
+ jellyfish: "🪼",
1460
+ jersey: "🇯🇪",
1461
+ jigsaw: "🧩",
1462
+ jordan: "🇯🇴",
1463
+ joy: "😂",
1464
+ joy_cat: "😹",
1465
+ joystick: "🕹",
1466
+ jp: "🇯🇵",
1467
+ judge: "🧑‍⚖",
1468
+ juggling_person: "🤹",
1469
+ kaaba: "🕋",
1470
+ kangaroo: "🦘",
1471
+ kazakhstan: "🇰🇿",
1472
+ kenya: "🇰🇪",
1473
+ key: "🔑",
1474
+ keyboard: "⌨",
1475
+ keycap_ten: "🔟",
1476
+ khanda: "🪯",
1477
+ kick_scooter: "🛴",
1478
+ kimono: "👘",
1479
+ kiribati: "🇰🇮",
1480
+ kiss: "💋",
1481
+ kissing: "😗",
1482
+ kissing_cat: "😽",
1483
+ kissing_closed_eyes: "😚",
1484
+ kissing_heart: "😘",
1485
+ kissing_smiling_eyes: "😙",
1486
+ kite: "🪁",
1487
+ kiwi_fruit: "🥝",
1488
+ kneeling_man: "🧎‍♂",
1489
+ kneeling_person: "🧎",
1490
+ kneeling_woman: "🧎‍♀",
1491
+ knife: "🔪",
1492
+ knot: "🪢",
1493
+ koala: "🐨",
1494
+ koko: "🈁",
1495
+ kosovo: "🇽🇰",
1496
+ kr: "🇰🇷",
1497
+ kuwait: "🇰🇼",
1498
+ kyrgyzstan: "🇰🇬",
1499
+ lab_coat: "🥼",
1500
+ label: "🏷",
1501
+ lacrosse: "🥍",
1502
+ ladder: "🪜",
1503
+ lady_beetle: "🐞",
1504
+ lantern: "🏮",
1505
+ laos: "🇱🇦",
1506
+ large_blue_circle: "🔵",
1507
+ large_blue_diamond: "🔷",
1508
+ large_orange_diamond: "🔶",
1509
+ last_quarter_moon: "🌗",
1510
+ last_quarter_moon_with_face: "🌜",
1511
+ latin_cross: "✝",
1512
+ latvia: "🇱🇻",
1513
+ laughing: "😆",
1514
+ leafy_green: "🥬",
1515
+ leaves: "🍃",
1516
+ lebanon: "🇱🇧",
1517
+ ledger: "📒",
1518
+ left_luggage: "🛅",
1519
+ left_right_arrow: "↔",
1520
+ left_speech_bubble: "🗨",
1521
+ leftwards_arrow_with_hook: "↩",
1522
+ leftwards_hand: "🫲",
1523
+ leftwards_pushing_hand: "🫷",
1524
+ leg: "🦵",
1525
+ lemon: "🍋",
1526
+ leo: "♌",
1527
+ leopard: "🐆",
1528
+ lesotho: "🇱🇸",
1529
+ level_slider: "🎚",
1530
+ liberia: "🇱🇷",
1531
+ libra: "♎",
1532
+ libya: "🇱🇾",
1533
+ liechtenstein: "🇱🇮",
1534
+ light_blue_heart: "🩵",
1535
+ light_rail: "🚈",
1536
+ link: "🔗",
1537
+ lion: "🦁",
1538
+ lips: "👄",
1539
+ lipstick: "💄",
1540
+ lithuania: "🇱🇹",
1541
+ lizard: "🦎",
1542
+ llama: "🦙",
1543
+ lobster: "🦞",
1544
+ lock: "🔒",
1545
+ lock_with_ink_pen: "🔏",
1546
+ lollipop: "🍭",
1547
+ long_drum: "🪘",
1548
+ loop: "➿",
1549
+ lotion_bottle: "🧴",
1550
+ lotus: "🪷",
1551
+ lotus_position: "🧘",
1552
+ lotus_position_man: "🧘‍♂",
1553
+ lotus_position_woman: "🧘‍♀",
1554
+ loud_sound: "🔊",
1555
+ loudspeaker: "📢",
1556
+ love_hotel: "🏩",
1557
+ love_letter: "💌",
1558
+ love_you_gesture: "🤟",
1559
+ low_battery: "🪫",
1560
+ low_brightness: "🔅",
1561
+ luggage: "🧳",
1562
+ lungs: "🫁",
1563
+ luxembourg: "🇱🇺",
1564
+ lying_face: "🤥",
1565
+ m: "Ⓜ",
1566
+ macau: "🇲🇴",
1567
+ macedonia: "🇲🇰",
1568
+ madagascar: "🇲🇬",
1569
+ mag: "🔍",
1570
+ mag_right: "🔎",
1571
+ mage: "🧙",
1572
+ mage_man: "🧙‍♂",
1573
+ mage_woman: "🧙‍♀",
1574
+ magic_wand: "🪄",
1575
+ magnet: "🧲",
1576
+ mahjong: "🀄",
1577
+ mailbox: "📫",
1578
+ mailbox_closed: "📪",
1579
+ mailbox_with_mail: "📬",
1580
+ mailbox_with_no_mail: "📭",
1581
+ malawi: "🇲🇼",
1582
+ malaysia: "🇲🇾",
1583
+ maldives: "🇲🇻",
1584
+ male_detective: "🕵‍♂",
1585
+ male_sign: "♂",
1586
+ mali: "🇲🇱",
1587
+ malta: "🇲🇹",
1588
+ mammoth: "🦣",
1589
+ man: "👨",
1590
+ man_artist: "👨‍🎨",
1591
+ man_astronaut: "👨‍🚀",
1592
+ man_beard: "🧔‍♂",
1593
+ man_cartwheeling: "🤸‍♂",
1594
+ man_cook: "👨‍🍳",
1595
+ man_dancing: "🕺",
1596
+ man_facepalming: "🤦‍♂",
1597
+ man_factory_worker: "👨‍🏭",
1598
+ man_farmer: "👨‍🌾",
1599
+ man_feeding_baby: "👨‍🍼",
1600
+ man_firefighter: "👨‍🚒",
1601
+ man_health_worker: "👨‍⚕",
1602
+ man_in_manual_wheelchair: "👨‍🦽",
1603
+ man_in_motorized_wheelchair: "👨‍🦼",
1604
+ man_in_tuxedo: "🤵‍♂",
1605
+ man_judge: "👨‍⚖",
1606
+ man_juggling: "🤹‍♂",
1607
+ man_mechanic: "👨‍🔧",
1608
+ man_office_worker: "👨‍💼",
1609
+ man_pilot: "👨‍✈",
1610
+ man_playing_handball: "🤾‍♂",
1611
+ man_playing_water_polo: "🤽‍♂",
1612
+ man_scientist: "👨‍🔬",
1613
+ man_shrugging: "🤷‍♂",
1614
+ man_singer: "👨‍🎤",
1615
+ man_student: "👨‍🎓",
1616
+ man_teacher: "👨‍🏫",
1617
+ man_technologist: "👨‍💻",
1618
+ man_with_gua_pi_mao: "👲",
1619
+ man_with_probing_cane: "👨‍🦯",
1620
+ man_with_turban: "👳‍♂",
1621
+ man_with_veil: "👰‍♂",
1622
+ mandarin: "🍊",
1623
+ mango: "🥭",
1624
+ mans_shoe: "👞",
1625
+ mantelpiece_clock: "🕰",
1626
+ manual_wheelchair: "🦽",
1627
+ maple_leaf: "🍁",
1628
+ maracas: "🪇",
1629
+ marshall_islands: "🇲🇭",
1630
+ martial_arts_uniform: "🥋",
1631
+ martinique: "🇲🇶",
1632
+ mask: "😷",
1633
+ massage: "💆",
1634
+ massage_man: "💆‍♂",
1635
+ massage_woman: "💆‍♀",
1636
+ mate: "🧉",
1637
+ mauritania: "🇲🇷",
1638
+ mauritius: "🇲🇺",
1639
+ mayotte: "🇾🇹",
1640
+ meat_on_bone: "🍖",
1641
+ mechanic: "🧑‍🔧",
1642
+ mechanical_arm: "🦾",
1643
+ mechanical_leg: "🦿",
1644
+ medal_military: "🎖",
1645
+ medal_sports: "🏅",
1646
+ medical_symbol: "⚕",
1647
+ mega: "📣",
1648
+ melon: "🍈",
1649
+ melting_face: "🫠",
1650
+ memo: "📝",
1651
+ men_wrestling: "🤼‍♂",
1652
+ mending_heart: "❤‍🩹",
1653
+ menorah: "🕎",
1654
+ mens: "🚹",
1655
+ mermaid: "🧜‍♀",
1656
+ merman: "🧜‍♂",
1657
+ merperson: "🧜",
1658
+ metal: "🤘",
1659
+ metro: "🚇",
1660
+ mexico: "🇲🇽",
1661
+ microbe: "🦠",
1662
+ micronesia: "🇫🇲",
1663
+ microphone: "🎤",
1664
+ microscope: "🔬",
1665
+ middle_finger: "🖕",
1666
+ military_helmet: "🪖",
1667
+ milk_glass: "🥛",
1668
+ milky_way: "🌌",
1669
+ minibus: "🚐",
1670
+ minidisc: "💽",
1671
+ mirror: "🪞",
1672
+ mirror_ball: "🪩",
1673
+ mobile_phone_off: "📴",
1674
+ moldova: "🇲🇩",
1675
+ monaco: "🇲🇨",
1676
+ money_mouth_face: "🤑",
1677
+ money_with_wings: "💸",
1678
+ moneybag: "💰",
1679
+ mongolia: "🇲🇳",
1680
+ monkey: "🐒",
1681
+ monkey_face: "🐵",
1682
+ monocle_face: "🧐",
1683
+ monorail: "🚝",
1684
+ montenegro: "🇲🇪",
1685
+ montserrat: "🇲🇸",
1686
+ moon: "🌔",
1687
+ moon_cake: "🥮",
1688
+ moose: "🫎",
1689
+ morocco: "🇲🇦",
1690
+ mortar_board: "🎓",
1691
+ mosque: "🕌",
1692
+ mosquito: "🦟",
1693
+ motor_boat: "🛥",
1694
+ motor_scooter: "🛵",
1695
+ motorcycle: "🏍",
1696
+ motorized_wheelchair: "🦼",
1697
+ motorway: "🛣",
1698
+ mount_fuji: "🗻",
1699
+ mountain: "⛰",
1700
+ mountain_bicyclist: "🚵",
1701
+ mountain_biking_man: "🚵‍♂",
1702
+ mountain_biking_woman: "🚵‍♀",
1703
+ mountain_cableway: "🚠",
1704
+ mountain_railway: "🚞",
1705
+ mountain_snow: "🏔",
1706
+ mouse: "🐭",
1707
+ mouse2: "🐁",
1708
+ mouse_trap: "🪤",
1709
+ movie_camera: "🎥",
1710
+ moyai: "🗿",
1711
+ mozambique: "🇲🇿",
1712
+ mrs_claus: "🤶",
1713
+ muscle: "💪",
1714
+ mushroom: "🍄",
1715
+ musical_keyboard: "🎹",
1716
+ musical_note: "🎵",
1717
+ musical_score: "🎼",
1718
+ mute: "🔇",
1719
+ mx_claus: "🧑‍🎄",
1720
+ myanmar: "🇲🇲",
1721
+ nail_care: "💅",
1722
+ name_badge: "📛",
1723
+ namibia: "🇳🇦",
1724
+ national_park: "🏞",
1725
+ nauru: "🇳🇷",
1726
+ nauseated_face: "🤢",
1727
+ nazar_amulet: "🧿",
1728
+ necktie: "👔",
1729
+ negative_squared_cross_mark: "❎",
1730
+ nepal: "🇳🇵",
1731
+ nerd_face: "🤓",
1732
+ nest_with_eggs: "🪺",
1733
+ nesting_dolls: "🪆",
1734
+ netherlands: "🇳🇱",
1735
+ neutral_face: "😐",
1736
+ new: "🆕",
1737
+ new_caledonia: "🇳🇨",
1738
+ new_moon: "🌑",
1739
+ new_moon_with_face: "🌚",
1740
+ new_zealand: "🇳🇿",
1741
+ newspaper: "📰",
1742
+ newspaper_roll: "🗞",
1743
+ next_track_button: "⏭",
1744
+ ng: "🆖",
1745
+ ng_man: "🙅‍♂",
1746
+ ng_woman: "🙅‍♀",
1747
+ nicaragua: "🇳🇮",
1748
+ niger: "🇳🇪",
1749
+ nigeria: "🇳🇬",
1750
+ night_with_stars: "🌃",
1751
+ nine: "9️⃣",
1752
+ ninja: "🥷",
1753
+ niue: "🇳🇺",
1754
+ no_bell: "🔕",
1755
+ no_bicycles: "🚳",
1756
+ no_entry: "⛔",
1757
+ no_entry_sign: "🚫",
1758
+ no_good: "🙅",
1759
+ no_good_man: "🙅‍♂",
1760
+ no_good_woman: "🙅‍♀",
1761
+ no_mobile_phones: "📵",
1762
+ no_mouth: "😶",
1763
+ no_pedestrians: "🚷",
1764
+ no_smoking: "🚭",
1765
+ "non-potable_water": "🚱",
1766
+ norfolk_island: "🇳🇫",
1767
+ north_korea: "🇰🇵",
1768
+ northern_mariana_islands: "🇲🇵",
1769
+ norway: "🇳🇴",
1770
+ nose: "👃",
1771
+ notebook: "📓",
1772
+ notebook_with_decorative_cover: "📔",
1773
+ notes: "🎶",
1774
+ nut_and_bolt: "🔩",
1775
+ o: "⭕",
1776
+ o2: "🅾",
1777
+ ocean: "🌊",
1778
+ octopus: "🐙",
1779
+ oden: "🍢",
1780
+ office: "🏢",
1781
+ office_worker: "🧑‍💼",
1782
+ oil_drum: "🛢",
1783
+ ok: "🆗",
1784
+ ok_hand: "👌",
1785
+ ok_man: "🙆‍♂",
1786
+ ok_person: "🙆",
1787
+ ok_woman: "🙆‍♀",
1788
+ old_key: "🗝",
1789
+ older_adult: "🧓",
1790
+ older_man: "👴",
1791
+ older_woman: "👵",
1792
+ olive: "🫒",
1793
+ om: "🕉",
1794
+ oman: "🇴🇲",
1795
+ on: "🔛",
1796
+ oncoming_automobile: "🚘",
1797
+ oncoming_bus: "🚍",
1798
+ oncoming_police_car: "🚔",
1799
+ oncoming_taxi: "🚖",
1800
+ one: "1️⃣",
1801
+ one_piece_swimsuit: "🩱",
1802
+ onion: "🧅",
1803
+ open_book: "📖",
1804
+ open_file_folder: "📂",
1805
+ open_hands: "👐",
1806
+ open_mouth: "😮",
1807
+ open_umbrella: "☂",
1808
+ ophiuchus: "⛎",
1809
+ orange: "🍊",
1810
+ orange_book: "📙",
1811
+ orange_circle: "🟠",
1812
+ orange_heart: "🧡",
1813
+ orange_square: "🟧",
1814
+ orangutan: "🦧",
1815
+ orthodox_cross: "☦",
1816
+ otter: "🦦",
1817
+ outbox_tray: "📤",
1818
+ owl: "🦉",
1819
+ ox: "🐂",
1820
+ oyster: "🦪",
1821
+ package: "📦",
1822
+ page_facing_up: "📄",
1823
+ page_with_curl: "📃",
1824
+ pager: "📟",
1825
+ paintbrush: "🖌",
1826
+ pakistan: "🇵🇰",
1827
+ palau: "🇵🇼",
1828
+ palestinian_territories: "🇵🇸",
1829
+ palm_down_hand: "🫳",
1830
+ palm_tree: "🌴",
1831
+ palm_up_hand: "🫴",
1832
+ palms_up_together: "🤲",
1833
+ panama: "🇵🇦",
1834
+ pancakes: "🥞",
1835
+ panda_face: "🐼",
1836
+ paperclip: "📎",
1837
+ paperclips: "🖇",
1838
+ papua_new_guinea: "🇵🇬",
1839
+ parachute: "🪂",
1840
+ paraguay: "🇵🇾",
1841
+ parasol_on_ground: "⛱",
1842
+ parking: "🅿",
1843
+ parrot: "🦜",
1844
+ part_alternation_mark: "〽",
1845
+ partly_sunny: "⛅",
1846
+ partying_face: "🥳",
1847
+ passenger_ship: "🛳",
1848
+ passport_control: "🛂",
1849
+ pause_button: "⏸",
1850
+ paw_prints: "🐾",
1851
+ pea_pod: "🫛",
1852
+ peace_symbol: "☮",
1853
+ peach: "🍑",
1854
+ peacock: "🦚",
1855
+ peanuts: "🥜",
1856
+ pear: "🍐",
1857
+ pen: "🖊",
1858
+ pencil: "📝",
1859
+ pencil2: "✏",
1860
+ penguin: "🐧",
1861
+ pensive: "😔",
1862
+ people_holding_hands: "🧑‍🤝‍🧑",
1863
+ people_hugging: "🫂",
1864
+ performing_arts: "🎭",
1865
+ persevere: "😣",
1866
+ person_bald: "🧑‍🦲",
1867
+ person_curly_hair: "🧑‍🦱",
1868
+ person_feeding_baby: "🧑‍🍼",
1869
+ person_fencing: "🤺",
1870
+ person_in_manual_wheelchair: "🧑‍🦽",
1871
+ person_in_motorized_wheelchair: "🧑‍🦼",
1872
+ person_in_tuxedo: "🤵",
1873
+ person_red_hair: "🧑‍🦰",
1874
+ person_white_hair: "🧑‍🦳",
1875
+ person_with_crown: "🫅",
1876
+ person_with_probing_cane: "🧑‍🦯",
1877
+ person_with_turban: "👳",
1878
+ person_with_veil: "👰",
1879
+ peru: "🇵🇪",
1880
+ petri_dish: "🧫",
1881
+ philippines: "🇵🇭",
1882
+ phone: "☎",
1883
+ pick: "⛏",
1884
+ pickup_truck: "🛻",
1885
+ pie: "🥧",
1886
+ pig: "🐷",
1887
+ pig2: "🐖",
1888
+ pig_nose: "🐽",
1889
+ pill: "💊",
1890
+ pilot: "🧑‍✈",
1891
+ pinata: "🪅",
1892
+ pinched_fingers: "🤌",
1893
+ pinching_hand: "🤏",
1894
+ pineapple: "🍍",
1895
+ ping_pong: "🏓",
1896
+ pink_heart: "🩷",
1897
+ pirate_flag: "🏴‍☠",
1898
+ pisces: "♓",
1899
+ pitcairn_islands: "🇵🇳",
1900
+ pizza: "🍕",
1901
+ placard: "🪧",
1902
+ place_of_worship: "🛐",
1903
+ plate_with_cutlery: "🍽",
1904
+ play_or_pause_button: "⏯",
1905
+ playground_slide: "🛝",
1906
+ pleading_face: "🥺",
1907
+ plunger: "🪠",
1908
+ point_down: "👇",
1909
+ point_left: "👈",
1910
+ point_right: "👉",
1911
+ point_up: "☝",
1912
+ point_up_2: "👆",
1913
+ poland: "🇵🇱",
1914
+ polar_bear: "🐻‍❄",
1915
+ police_car: "🚓",
1916
+ police_officer: "👮",
1917
+ policeman: "👮‍♂",
1918
+ policewoman: "👮‍♀",
1919
+ poodle: "🐩",
1920
+ poop: "💩",
1921
+ popcorn: "🍿",
1922
+ portugal: "🇵🇹",
1923
+ post_office: "🏣",
1924
+ postal_horn: "📯",
1925
+ postbox: "📮",
1926
+ potable_water: "🚰",
1927
+ potato: "🥔",
1928
+ potted_plant: "🪴",
1929
+ pouch: "👝",
1930
+ poultry_leg: "🍗",
1931
+ pound: "💷",
1932
+ pouring_liquid: "🫗",
1933
+ pout: "😡",
1934
+ pouting_cat: "😾",
1935
+ pouting_face: "🙎",
1936
+ pouting_man: "🙎‍♂",
1937
+ pouting_woman: "🙎‍♀",
1938
+ pray: "🙏",
1939
+ prayer_beads: "📿",
1940
+ pregnant_man: "🫃",
1941
+ pregnant_person: "🫄",
1942
+ pregnant_woman: "🤰",
1943
+ pretzel: "🥨",
1944
+ previous_track_button: "⏮",
1945
+ prince: "🤴",
1946
+ princess: "👸",
1947
+ printer: "🖨",
1948
+ probing_cane: "🦯",
1949
+ puerto_rico: "🇵🇷",
1950
+ punch: "👊",
1951
+ purple_circle: "🟣",
1952
+ purple_heart: "💜",
1953
+ purple_square: "🟪",
1954
+ purse: "👛",
1955
+ pushpin: "📌",
1956
+ put_litter_in_its_place: "🚮",
1957
+ qatar: "🇶🇦",
1958
+ question: "❓",
1959
+ rabbit: "🐰",
1960
+ rabbit2: "🐇",
1961
+ raccoon: "🦝",
1962
+ racehorse: "🐎",
1963
+ racing_car: "🏎",
1964
+ radio: "📻",
1965
+ radio_button: "🔘",
1966
+ radioactive: "☢",
1967
+ rage: "😡",
1968
+ railway_car: "🚃",
1969
+ railway_track: "🛤",
1970
+ rainbow: "🌈",
1971
+ rainbow_flag: "🏳‍🌈",
1972
+ raised_back_of_hand: "🤚",
1973
+ raised_eyebrow: "🤨",
1974
+ raised_hand: "✋",
1975
+ raised_hand_with_fingers_splayed: "🖐",
1976
+ raised_hands: "🙌",
1977
+ raising_hand: "🙋",
1978
+ raising_hand_man: "🙋‍♂",
1979
+ raising_hand_woman: "🙋‍♀",
1980
+ ram: "🐏",
1981
+ ramen: "🍜",
1982
+ rat: "🐀",
1983
+ razor: "🪒",
1984
+ receipt: "🧾",
1985
+ record_button: "⏺",
1986
+ recycle: "♻",
1987
+ red_car: "🚗",
1988
+ red_circle: "🔴",
1989
+ red_envelope: "🧧",
1990
+ red_haired_man: "👨‍🦰",
1991
+ red_haired_woman: "👩‍🦰",
1992
+ red_square: "🟥",
1993
+ registered: "®",
1994
+ relaxed: "☺",
1995
+ relieved: "😌",
1996
+ reminder_ribbon: "🎗",
1997
+ repeat: "🔁",
1998
+ repeat_one: "🔂",
1999
+ rescue_worker_helmet: "⛑",
2000
+ restroom: "🚻",
2001
+ reunion: "🇷🇪",
2002
+ revolving_hearts: "💞",
2003
+ rewind: "⏪",
2004
+ rhinoceros: "🦏",
2005
+ ribbon: "🎀",
2006
+ rice: "🍚",
2007
+ rice_ball: "🍙",
2008
+ rice_cracker: "🍘",
2009
+ rice_scene: "🎑",
2010
+ right_anger_bubble: "🗯",
2011
+ rightwards_hand: "🫱",
2012
+ rightwards_pushing_hand: "🫸",
2013
+ ring: "💍",
2014
+ ring_buoy: "🛟",
2015
+ ringed_planet: "🪐",
2016
+ robot: "🤖",
2017
+ rock: "🪨",
2018
+ rocket: "🚀",
2019
+ rofl: "🤣",
2020
+ roll_eyes: "🙄",
2021
+ roll_of_paper: "🧻",
2022
+ roller_coaster: "🎢",
2023
+ roller_skate: "🛼",
2024
+ romania: "🇷🇴",
2025
+ rooster: "🐓",
2026
+ rose: "🌹",
2027
+ rosette: "🏵",
2028
+ rotating_light: "🚨",
2029
+ round_pushpin: "📍",
2030
+ rowboat: "🚣",
2031
+ rowing_man: "🚣‍♂",
2032
+ rowing_woman: "🚣‍♀",
2033
+ ru: "🇷🇺",
2034
+ rugby_football: "🏉",
2035
+ runner: "🏃",
2036
+ running: "🏃",
2037
+ running_man: "🏃‍♂",
2038
+ running_shirt_with_sash: "🎽",
2039
+ running_woman: "🏃‍♀",
2040
+ rwanda: "🇷🇼",
2041
+ sa: "🈂",
2042
+ safety_pin: "🧷",
2043
+ safety_vest: "🦺",
2044
+ sagittarius: "♐",
2045
+ sailboat: "⛵",
2046
+ sake: "🍶",
2047
+ salt: "🧂",
2048
+ saluting_face: "🫡",
2049
+ samoa: "🇼🇸",
2050
+ san_marino: "🇸🇲",
2051
+ sandal: "👡",
2052
+ sandwich: "🥪",
2053
+ santa: "🎅",
2054
+ sao_tome_principe: "🇸🇹",
2055
+ sari: "🥻",
2056
+ sassy_man: "💁‍♂",
2057
+ sassy_woman: "💁‍♀",
2058
+ satellite: "📡",
2059
+ satisfied: "😆",
2060
+ saudi_arabia: "🇸🇦",
2061
+ sauna_man: "🧖‍♂",
2062
+ sauna_person: "🧖",
2063
+ sauna_woman: "🧖‍♀",
2064
+ sauropod: "🦕",
2065
+ saxophone: "🎷",
2066
+ scarf: "🧣",
2067
+ school: "🏫",
2068
+ school_satchel: "🎒",
2069
+ scientist: "🧑‍🔬",
2070
+ scissors: "✂",
2071
+ scorpion: "🦂",
2072
+ scorpius: "♏",
2073
+ scotland: "🏴󠁧󠁢󠁳󠁣󠁴󠁿",
2074
+ scream: "😱",
2075
+ scream_cat: "🙀",
2076
+ screwdriver: "🪛",
2077
+ scroll: "📜",
2078
+ seal: "🦭",
2079
+ seat: "💺",
2080
+ secret: "㊙",
2081
+ see_no_evil: "🙈",
2082
+ seedling: "🌱",
2083
+ selfie: "🤳",
2084
+ senegal: "🇸🇳",
2085
+ serbia: "🇷🇸",
2086
+ service_dog: "🐕‍🦺",
2087
+ seven: "7️⃣",
2088
+ sewing_needle: "🪡",
2089
+ seychelles: "🇸🇨",
2090
+ shaking_face: "🫨",
2091
+ shallow_pan_of_food: "🥘",
2092
+ shamrock: "☘",
2093
+ shark: "🦈",
2094
+ shaved_ice: "🍧",
2095
+ sheep: "🐑",
2096
+ shell: "🐚",
2097
+ shield: "🛡",
2098
+ shinto_shrine: "⛩",
2099
+ ship: "🚢",
2100
+ shirt: "👕",
2101
+ shit: "💩",
2102
+ shoe: "👞",
2103
+ shopping: "🛍",
2104
+ shopping_cart: "🛒",
2105
+ shorts: "🩳",
2106
+ shower: "🚿",
2107
+ shrimp: "🦐",
2108
+ shrug: "🤷",
2109
+ shushing_face: "🤫",
2110
+ sierra_leone: "🇸🇱",
2111
+ signal_strength: "📶",
2112
+ singapore: "🇸🇬",
2113
+ singer: "🧑‍🎤",
2114
+ sint_maarten: "🇸🇽",
2115
+ six: "6️⃣",
2116
+ six_pointed_star: "🔯",
2117
+ skateboard: "🛹",
2118
+ ski: "🎿",
2119
+ skier: "⛷",
2120
+ skull: "💀",
2121
+ skull_and_crossbones: "☠",
2122
+ skunk: "🦨",
2123
+ sled: "🛷",
2124
+ sleeping: "😴",
2125
+ sleeping_bed: "🛌",
2126
+ sleepy: "😪",
2127
+ slightly_frowning_face: "🙁",
2128
+ slightly_smiling_face: "🙂",
2129
+ slot_machine: "🎰",
2130
+ sloth: "🦥",
2131
+ slovakia: "🇸🇰",
2132
+ slovenia: "🇸🇮",
2133
+ small_airplane: "🛩",
2134
+ small_blue_diamond: "🔹",
2135
+ small_orange_diamond: "🔸",
2136
+ small_red_triangle: "🔺",
2137
+ small_red_triangle_down: "🔻",
2138
+ smile: "😄",
2139
+ smile_cat: "😸",
2140
+ smiley: "😃",
2141
+ smiley_cat: "😺",
2142
+ smiling_face_with_tear: "🥲",
2143
+ smiling_face_with_three_hearts: "🥰",
2144
+ smiling_imp: "😈",
2145
+ smirk: "😏",
2146
+ smirk_cat: "😼",
2147
+ smoking: "🚬",
2148
+ snail: "🐌",
2149
+ snake: "🐍",
2150
+ sneezing_face: "🤧",
2151
+ snowboarder: "🏂",
2152
+ snowflake: "❄",
2153
+ snowman: "⛄",
2154
+ snowman_with_snow: "☃",
2155
+ soap: "🧼",
2156
+ sob: "😭",
2157
+ soccer: "⚽",
2158
+ socks: "🧦",
2159
+ softball: "🥎",
2160
+ solomon_islands: "🇸🇧",
2161
+ somalia: "🇸🇴",
2162
+ soon: "🔜",
2163
+ sos: "🆘",
2164
+ sound: "🔉",
2165
+ south_africa: "🇿🇦",
2166
+ south_georgia_south_sandwich_islands: "🇬🇸",
2167
+ south_sudan: "🇸🇸",
2168
+ space_invader: "👾",
2169
+ spades: "♠",
2170
+ spaghetti: "🍝",
2171
+ sparkle: "❇",
2172
+ sparkler: "🎇",
2173
+ sparkles: "✨",
2174
+ sparkling_heart: "💖",
2175
+ speak_no_evil: "🙊",
2176
+ speaker: "🔈",
2177
+ speaking_head: "🗣",
2178
+ speech_balloon: "💬",
2179
+ speedboat: "🚤",
2180
+ spider: "🕷",
2181
+ spider_web: "🕸",
2182
+ spiral_calendar: "🗓",
2183
+ spiral_notepad: "🗒",
2184
+ sponge: "🧽",
2185
+ spoon: "🥄",
2186
+ squid: "🦑",
2187
+ sri_lanka: "🇱🇰",
2188
+ st_barthelemy: "🇧🇱",
2189
+ st_helena: "🇸🇭",
2190
+ st_kitts_nevis: "🇰🇳",
2191
+ st_lucia: "🇱🇨",
2192
+ st_martin: "🇲🇫",
2193
+ st_pierre_miquelon: "🇵🇲",
2194
+ st_vincent_grenadines: "🇻🇨",
2195
+ stadium: "🏟",
2196
+ standing_man: "🧍‍♂",
2197
+ standing_person: "🧍",
2198
+ standing_woman: "🧍‍♀",
2199
+ star: "⭐",
2200
+ star2: "🌟",
2201
+ star_and_crescent: "☪",
2202
+ star_of_david: "✡",
2203
+ star_struck: "🤩",
2204
+ stars: "🌠",
2205
+ station: "🚉",
2206
+ statue_of_liberty: "🗽",
2207
+ steam_locomotive: "🚂",
2208
+ stethoscope: "🩺",
2209
+ stew: "🍲",
2210
+ stop_button: "⏹",
2211
+ stop_sign: "🛑",
2212
+ stopwatch: "⏱",
2213
+ straight_ruler: "📏",
2214
+ strawberry: "🍓",
2215
+ stuck_out_tongue: "😛",
2216
+ stuck_out_tongue_closed_eyes: "😝",
2217
+ stuck_out_tongue_winking_eye: "😜",
2218
+ student: "🧑‍🎓",
2219
+ studio_microphone: "🎙",
2220
+ stuffed_flatbread: "🥙",
2221
+ sudan: "🇸🇩",
2222
+ sun_behind_large_cloud: "🌥",
2223
+ sun_behind_rain_cloud: "🌦",
2224
+ sun_behind_small_cloud: "🌤",
2225
+ sun_with_face: "🌞",
2226
+ sunflower: "🌻",
2227
+ sunglasses: "😎",
2228
+ sunny: "☀",
2229
+ sunrise: "🌅",
2230
+ sunrise_over_mountains: "🌄",
2231
+ superhero: "🦸",
2232
+ superhero_man: "🦸‍♂",
2233
+ superhero_woman: "🦸‍♀",
2234
+ supervillain: "🦹",
2235
+ supervillain_man: "🦹‍♂",
2236
+ supervillain_woman: "🦹‍♀",
2237
+ surfer: "🏄",
2238
+ surfing_man: "🏄‍♂",
2239
+ surfing_woman: "🏄‍♀",
2240
+ suriname: "🇸🇷",
2241
+ sushi: "🍣",
2242
+ suspension_railway: "🚟",
2243
+ svalbard_jan_mayen: "🇸🇯",
2244
+ swan: "🦢",
2245
+ swaziland: "🇸🇿",
2246
+ sweat: "😓",
2247
+ sweat_drops: "💦",
2248
+ sweat_smile: "😅",
2249
+ sweden: "🇸🇪",
2250
+ sweet_potato: "🍠",
2251
+ swim_brief: "🩲",
2252
+ swimmer: "🏊",
2253
+ swimming_man: "🏊‍♂",
2254
+ swimming_woman: "🏊‍♀",
2255
+ switzerland: "🇨🇭",
2256
+ symbols: "🔣",
2257
+ synagogue: "🕍",
2258
+ syria: "🇸🇾",
2259
+ syringe: "💉",
2260
+ "t-rex": "🦖",
2261
+ taco: "🌮",
2262
+ tada: "🎉",
2263
+ taiwan: "🇹🇼",
2264
+ tajikistan: "🇹🇯",
2265
+ takeout_box: "🥡",
2266
+ tamale: "🫔",
2267
+ tanabata_tree: "🎋",
2268
+ tangerine: "🍊",
2269
+ tanzania: "🇹🇿",
2270
+ taurus: "♉",
2271
+ taxi: "🚕",
2272
+ tea: "🍵",
2273
+ teacher: "🧑‍🏫",
2274
+ teapot: "🫖",
2275
+ technologist: "🧑‍💻",
2276
+ teddy_bear: "🧸",
2277
+ telephone: "☎",
2278
+ telephone_receiver: "📞",
2279
+ telescope: "🔭",
2280
+ tennis: "🎾",
2281
+ tent: "⛺",
2282
+ test_tube: "🧪",
2283
+ thailand: "🇹🇭",
2284
+ thermometer: "🌡",
2285
+ thinking: "🤔",
2286
+ thong_sandal: "🩴",
2287
+ thought_balloon: "💭",
2288
+ thread: "🧵",
2289
+ three: "3️⃣",
2290
+ thumbsdown: "👎",
2291
+ thumbsup: "👍",
2292
+ ticket: "🎫",
2293
+ tickets: "🎟",
2294
+ tiger: "🐯",
2295
+ tiger2: "🐅",
2296
+ timer_clock: "⏲",
2297
+ timor_leste: "🇹🇱",
2298
+ tipping_hand_man: "💁‍♂",
2299
+ tipping_hand_person: "💁",
2300
+ tipping_hand_woman: "💁‍♀",
2301
+ tired_face: "😫",
2302
+ tm: "™",
2303
+ togo: "🇹🇬",
2304
+ toilet: "🚽",
2305
+ tokelau: "🇹🇰",
2306
+ tokyo_tower: "🗼",
2307
+ tomato: "🍅",
2308
+ tonga: "🇹🇴",
2309
+ tongue: "👅",
2310
+ toolbox: "🧰",
2311
+ tooth: "🦷",
2312
+ toothbrush: "🪥",
2313
+ top: "🔝",
2314
+ tophat: "🎩",
2315
+ tornado: "🌪",
2316
+ tr: "🇹🇷",
2317
+ trackball: "🖲",
2318
+ tractor: "🚜",
2319
+ traffic_light: "🚥",
2320
+ train: "🚋",
2321
+ train2: "🚆",
2322
+ tram: "🚊",
2323
+ transgender_flag: "🏳‍⚧",
2324
+ transgender_symbol: "⚧",
2325
+ triangular_flag_on_post: "🚩",
2326
+ triangular_ruler: "📐",
2327
+ trident: "🔱",
2328
+ trinidad_tobago: "🇹🇹",
2329
+ tristan_da_cunha: "🇹🇦",
2330
+ triumph: "😤",
2331
+ troll: "🧌",
2332
+ trolleybus: "🚎",
2333
+ trophy: "🏆",
2334
+ tropical_drink: "🍹",
2335
+ tropical_fish: "🐠",
2336
+ truck: "🚚",
2337
+ trumpet: "🎺",
2338
+ tshirt: "👕",
2339
+ tulip: "🌷",
2340
+ tumbler_glass: "🥃",
2341
+ tunisia: "🇹🇳",
2342
+ turkey: "🦃",
2343
+ turkmenistan: "🇹🇲",
2344
+ turks_caicos_islands: "🇹🇨",
2345
+ turtle: "🐢",
2346
+ tuvalu: "🇹🇻",
2347
+ tv: "📺",
2348
+ twisted_rightwards_arrows: "🔀",
2349
+ two: "2️⃣",
2350
+ two_hearts: "💕",
2351
+ two_men_holding_hands: "👬",
2352
+ two_women_holding_hands: "👭",
2353
+ u5272: "🈹",
2354
+ u5408: "🈴",
2355
+ u55b6: "🈺",
2356
+ u6307: "🈯",
2357
+ u6708: "🈷",
2358
+ u6709: "🈶",
2359
+ u6e80: "🈵",
2360
+ u7121: "🈚",
2361
+ u7533: "🈸",
2362
+ u7981: "🈲",
2363
+ u7a7a: "🈳",
2364
+ uganda: "🇺🇬",
2365
+ uk: "🇬🇧",
2366
+ ukraine: "🇺🇦",
2367
+ umbrella: "☔",
2368
+ unamused: "😒",
2369
+ underage: "🔞",
2370
+ unicorn: "🦄",
2371
+ united_arab_emirates: "🇦🇪",
2372
+ united_nations: "🇺🇳",
2373
+ unlock: "🔓",
2374
+ up: "🆙",
2375
+ upside_down_face: "🙃",
2376
+ uruguay: "🇺🇾",
2377
+ us: "🇺🇸",
2378
+ us_outlying_islands: "🇺🇲",
2379
+ us_virgin_islands: "🇻🇮",
2380
+ uzbekistan: "🇺🇿",
2381
+ v: "✌",
2382
+ vampire: "🧛",
2383
+ vampire_man: "🧛‍♂",
2384
+ vampire_woman: "🧛‍♀",
2385
+ vanuatu: "🇻🇺",
2386
+ vatican_city: "🇻🇦",
2387
+ venezuela: "🇻🇪",
2388
+ vertical_traffic_light: "🚦",
2389
+ vhs: "📼",
2390
+ vibration_mode: "📳",
2391
+ video_camera: "📹",
2392
+ video_game: "🎮",
2393
+ vietnam: "🇻🇳",
2394
+ violin: "🎻",
2395
+ virgo: "♍",
2396
+ volcano: "🌋",
2397
+ volleyball: "🏐",
2398
+ vomiting_face: "🤮",
2399
+ vs: "🆚",
2400
+ vulcan_salute: "🖖",
2401
+ waffle: "🧇",
2402
+ wales: "🏴󠁧󠁢󠁷󠁬󠁳󠁿",
2403
+ walking: "🚶",
2404
+ walking_man: "🚶‍♂",
2405
+ walking_woman: "🚶‍♀",
2406
+ wallis_futuna: "🇼🇫",
2407
+ waning_crescent_moon: "🌘",
2408
+ waning_gibbous_moon: "🌖",
2409
+ warning: "⚠",
2410
+ wastebasket: "🗑",
2411
+ watch: "⌚",
2412
+ water_buffalo: "🐃",
2413
+ water_polo: "🤽",
2414
+ watermelon: "🍉",
2415
+ wave: "👋",
2416
+ wavy_dash: "〰",
2417
+ waxing_crescent_moon: "🌒",
2418
+ waxing_gibbous_moon: "🌔",
2419
+ wc: "🚾",
2420
+ weary: "😩",
2421
+ wedding: "💒",
2422
+ weight_lifting: "🏋",
2423
+ weight_lifting_man: "🏋‍♂",
2424
+ weight_lifting_woman: "🏋‍♀",
2425
+ western_sahara: "🇪🇭",
2426
+ whale: "🐳",
2427
+ whale2: "🐋",
2428
+ wheel: "🛞",
2429
+ wheel_of_dharma: "☸",
2430
+ wheelchair: "♿",
2431
+ white_check_mark: "✅",
2432
+ white_circle: "⚪",
2433
+ white_flag: "🏳",
2434
+ white_flower: "💮",
2435
+ white_haired_man: "👨‍🦳",
2436
+ white_haired_woman: "👩‍🦳",
2437
+ white_heart: "🤍",
2438
+ white_large_square: "⬜",
2439
+ white_medium_small_square: "◽",
2440
+ white_medium_square: "◻",
2441
+ white_small_square: "▫",
2442
+ white_square_button: "🔳",
2443
+ wilted_flower: "🥀",
2444
+ wind_chime: "🎐",
2445
+ wind_face: "🌬",
2446
+ window: "🪟",
2447
+ wine_glass: "🍷",
2448
+ wing: "🪽",
2449
+ wink: "😉",
2450
+ wireless: "🛜",
2451
+ wolf: "🐺",
2452
+ woman: "👩",
2453
+ woman_artist: "👩‍🎨",
2454
+ woman_astronaut: "👩‍🚀",
2455
+ woman_beard: "🧔‍♀",
2456
+ woman_cartwheeling: "🤸‍♀",
2457
+ woman_cook: "👩‍🍳",
2458
+ woman_dancing: "💃",
2459
+ woman_facepalming: "🤦‍♀",
2460
+ woman_factory_worker: "👩‍🏭",
2461
+ woman_farmer: "👩‍🌾",
2462
+ woman_feeding_baby: "👩‍🍼",
2463
+ woman_firefighter: "👩‍🚒",
2464
+ woman_health_worker: "👩‍⚕",
2465
+ woman_in_manual_wheelchair: "👩‍🦽",
2466
+ woman_in_motorized_wheelchair: "👩‍🦼",
2467
+ woman_in_tuxedo: "🤵‍♀",
2468
+ woman_judge: "👩‍⚖",
2469
+ woman_juggling: "🤹‍♀",
2470
+ woman_mechanic: "👩‍🔧",
2471
+ woman_office_worker: "👩‍💼",
2472
+ woman_pilot: "👩‍✈",
2473
+ woman_playing_handball: "🤾‍♀",
2474
+ woman_playing_water_polo: "🤽‍♀",
2475
+ woman_scientist: "👩‍🔬",
2476
+ woman_shrugging: "🤷‍♀",
2477
+ woman_singer: "👩‍🎤",
2478
+ woman_student: "👩‍🎓",
2479
+ woman_teacher: "👩‍🏫",
2480
+ woman_technologist: "👩‍💻",
2481
+ woman_with_headscarf: "🧕",
2482
+ woman_with_probing_cane: "👩‍🦯",
2483
+ woman_with_turban: "👳‍♀",
2484
+ woman_with_veil: "👰‍♀",
2485
+ womans_clothes: "👚",
2486
+ womans_hat: "👒",
2487
+ women_wrestling: "🤼‍♀",
2488
+ womens: "🚺",
2489
+ wood: "🪵",
2490
+ woozy_face: "🥴",
2491
+ world_map: "🗺",
2492
+ worm: "🪱",
2493
+ worried: "😟",
2494
+ wrench: "🔧",
2495
+ wrestling: "🤼",
2496
+ writing_hand: "✍",
2497
+ x: "❌",
2498
+ x_ray: "🩻",
2499
+ yarn: "🧶",
2500
+ yawning_face: "🥱",
2501
+ yellow_circle: "🟡",
2502
+ yellow_heart: "💛",
2503
+ yellow_square: "🟨",
2504
+ yemen: "🇾🇪",
2505
+ yen: "💴",
2506
+ yin_yang: "☯",
2507
+ yo_yo: "🪀",
2508
+ yum: "😋",
2509
+ zambia: "🇿🇲",
2510
+ zany_face: "🤪",
2511
+ zap: "⚡",
2512
+ zebra: "🦓",
2513
+ zero: "0️⃣",
2514
+ zimbabwe: "🇿🇼",
2515
+ zipper_mouth_face: "🤐",
2516
+ zombie: "🧟",
2517
+ zombie_man: "🧟‍♂",
2518
+ zombie_woman: "🧟‍♀",
2519
+ zzz: "💤"
2520
+ };
2521
+
2522
+ //#endregion
2523
+ //#region src/rules/emoji-notation.ts
2524
+ var EmojiData = class {
2525
+ _entries = null;
2526
+ _emojiToColon = null;
2527
+ _colonToEmoji = null;
2528
+ get entries() {
2529
+ return this._entries ??= Object.entries(GH_EMOJI_MAP);
2530
+ }
2531
+ get emojiToColon() {
2532
+ if (this._emojiToColon) return this._emojiToColon;
2533
+ const emojiToCode = this._emojiToColon = Object.create(null);
2534
+ for (const [name$2, unicode] of this.entries) emojiToCode[unicode] = `:${name$2}:`;
2535
+ return emojiToCode;
2536
+ }
2537
+ get colonToEmoji() {
2538
+ if (this._colonToEmoji) return this._colonToEmoji;
2539
+ const colonToEmoji = this._colonToEmoji = Object.create(null);
2540
+ for (const [name$2, unicode] of this.entries) colonToEmoji[`:${name$2}:`] = unicode;
2541
+ return colonToEmoji;
2542
+ }
2543
+ };
2544
+ const emojiData = new EmojiData();
2545
+ var emoji_notation_default = createRule("emoji-notation", {
2546
+ meta: {
2547
+ type: "suggestion",
2548
+ docs: {
2549
+ description: "enforce consistent emoji notation style in Markdown files.",
2550
+ categories: [],
2551
+ listCategory: "Preference"
2552
+ },
2553
+ fixable: "code",
2554
+ hasSuggestions: false,
2555
+ schema: [{
2556
+ type: "object",
2557
+ properties: {
2558
+ prefer: {
2559
+ enum: ["unicode", "colon"],
2560
+ description: "Preferred emoji notation style."
2561
+ },
2562
+ ignoreUnknown: {
2563
+ type: "boolean",
2564
+ description: "If true, suppress unknown colon-style emoji."
2565
+ },
2566
+ ignoreList: {
2567
+ type: "array",
2568
+ items: { type: "string" },
2569
+ uniqueItems: true,
2570
+ description: "List of colon-style, Unicode emoji, or regex (as string) to suppress."
2571
+ }
2572
+ },
2573
+ additionalProperties: false
2574
+ }],
2575
+ messages: {
2576
+ preferUnicode: "Use Unicode emoji '{{unicode}}' instead of colon-style emoji ('{{colon}}').",
2577
+ preferColon: "Use colon-style emoji '{{colon}}' instead of Unicode emoji ('{{unicode}}').",
2578
+ preferUnknownUnicode: "Use Unicode emoji (e.g. '{{unicode}}') instead of colon-style emoji ('{{colon}}').",
2579
+ preferUnknownColon: "Use colon-style emoji (e.g. '{{colon}}') instead of Unicode emoji ('{{unicode}}')."
2580
+ }
2581
+ },
2582
+ create(context) {
2583
+ const sourceCode = context.sourceCode;
2584
+ const options = context.options?.[0] || {};
2585
+ const prefer = options.prefer || "unicode";
2586
+ const ignoreUnknown = options.ignoreUnknown ?? true;
2587
+ const ignoreList = (options.ignoreList || []).map((s) => toRegExp(s)).flatMap((re) => {
2588
+ const result = [re];
2589
+ for (const [name$2, unicode] of emojiData.entries) if (re.test(`:${name$2}:`) || re.test(unicode)) result.push(toRegExp(`:${name$2}:`), toRegExp(unicode));
2590
+ return result;
2591
+ });
2592
+ const isIgnoreBase = (s) => ignoreList.some((re) => re.test(s));
2593
+ if (prefer === "colon") {
2594
+ let isIgnore$1;
2595
+ if (ignoreUnknown) isIgnore$1 = (s) => isIgnoreBase(s) || !emojiData.emojiToColon[s];
2596
+ else isIgnore$1 = (s) => isIgnoreBase(s);
2597
+ return { text(node) {
2598
+ const re = emojiRegex();
2599
+ const text = sourceCode.getText(node);
2600
+ for (const match of text.matchAll(re)) {
2601
+ const emoji = match[0];
2602
+ if (isIgnore$1(emoji)) continue;
2603
+ const emojiOffset = match.index;
2604
+ const [nodeStart] = sourceCode.getRange(node);
2605
+ const range = [nodeStart + emojiOffset, nodeStart + emojiOffset + emoji.length];
2606
+ const colon = emojiData.emojiToColon[emoji];
2607
+ context.report({
2608
+ node,
2609
+ loc: getSourceLocationFromRange(sourceCode, node, range),
2610
+ messageId: colon ? "preferColon" : "preferUnknownColon",
2611
+ data: {
2612
+ unicode: emoji,
2613
+ colon: colon || ":smile:"
2614
+ },
2615
+ fix: colon ? (fixer) => {
2616
+ return fixer.replaceTextRange(range, colon);
2617
+ } : null
2618
+ });
2619
+ }
2620
+ } };
2621
+ }
2622
+ let isIgnore;
2623
+ if (ignoreUnknown) isIgnore = (s) => isIgnoreBase(s) || !emojiData.colonToEmoji[s];
2624
+ else isIgnore = (s) => isIgnoreBase(s);
2625
+ return { text(node) {
2626
+ const re = /:[^\s\x00-\x0f:\u{7f}]+:/gu;
2627
+ const text = sourceCode.getText(node);
2628
+ for (const match of text.matchAll(re)) {
2629
+ const colon = match[0];
2630
+ if (isIgnore(colon)) continue;
2631
+ const colonOffset = match.index;
2632
+ const [nodeStart] = sourceCode.getRange(node);
2633
+ const range = [nodeStart + colonOffset, nodeStart + colonOffset + colon.length];
2634
+ const emoji = emojiData.colonToEmoji[colon];
2635
+ context.report({
2636
+ node,
2637
+ loc: getSourceLocationFromRange(sourceCode, node, range),
2638
+ messageId: emoji ? "preferUnicode" : "preferUnknownUnicode",
2639
+ data: {
2640
+ unicode: emoji || "😄",
2641
+ colon
2642
+ },
2643
+ fix: emoji ? (fixer) => {
2644
+ return fixer.replaceTextRange(range, emoji);
2645
+ } : null
2646
+ });
2647
+ }
2648
+ } };
2649
+ }
2650
+ });
2651
+
161
2652
  //#endregion
162
2653
  //#region src/rules/hard-linebreak-style.ts
163
2654
  var hard_linebreak_style_default = createRule("hard-linebreak-style", {
@@ -203,31 +2694,6 @@ var hard_linebreak_style_default = createRule("hard-linebreak-style", {
203
2694
  }
204
2695
  });
205
2696
 
206
- //#endregion
207
- //#region src/utils/regexp.ts
208
- const RE_REGEXP_STR = /^\/(.+)\/([A-Za-z]*)$/u;
209
- /**
210
- * Convert a string to the `RegExp`.
211
- * Normal strings (e.g. `"foo"`) is converted to `/^foo$/` of `RegExp`.
212
- * Strings like `"/^foo/i"` are converted to `/^foo/i` of `RegExp`.
213
- *
214
- * @param {string} string The string to convert.
215
- * @returns {RegExp} Returns the `RegExp`.
216
- */
217
- function toRegExp(string) {
218
- const parts = RE_REGEXP_STR.exec(string);
219
- if (parts) return new RegExp(parts[1], parts[2]);
220
- return { test: (s) => s === string };
221
- }
222
- /**
223
- * Checks whether given string is regexp string
224
- * @param {string} string
225
- * @returns {boolean}
226
- */
227
- function isRegExp(string) {
228
- return Boolean(RE_REGEXP_STR.test(string));
229
- }
230
-
231
2697
  //#endregion
232
2698
  //#region src/resources/preserve-words.ts
233
2699
  const defaultPreserveWords = [
@@ -347,6 +2813,7 @@ const defaultPreserveWords = [
347
2813
  "Biome",
348
2814
  "oxc",
349
2815
  "swc",
2816
+ "markdownlint",
350
2817
  "Webpack",
351
2818
  "Vite",
352
2819
  "Babel",
@@ -682,7 +3149,8 @@ const defaultPreserveWords = [
682
3149
  "Insomnia",
683
3150
  "Redoc",
684
3151
  "Stoplight",
685
- "FAQ"
3152
+ "FAQ",
3153
+ "YouTube"
686
3154
  ];
687
3155
 
688
3156
  //#endregion
@@ -721,44 +3189,113 @@ const defaultMinorWords = [
721
3189
  ];
722
3190
 
723
3191
  //#endregion
724
- //#region src/rules/heading-casing.ts
3192
+ //#region src/utils/word-casing.ts
725
3193
  /**
726
- * Parse preserve words and phrases from the options
727
- * - Single words are added to preserveWords
728
- * - Multi-word phrases are added to preservePhrases and added to preserveWords with no spaces
3194
+ * Converts the casing of a word based on the specified case style and whether it is the first or last word in a phrase.
729
3195
  */
730
- function parsePreserveWords(preserveWordsOption) {
731
- const preserveWords = /* @__PURE__ */ new Map();
732
- /**
733
- * Add a single word to the preserveWords map
734
- */
735
- function addPreserveWord(word) {
736
- const lowerWord = word.toLowerCase();
737
- let list = preserveWords.get(lowerWord);
738
- if (!list) {
739
- list = [];
740
- preserveWords.set(lowerWord, list);
3196
+ function convertWordCasing({ word, first, last }, { caseStyle, minorWords }) {
3197
+ if (caseStyle === "Title Case") {
3198
+ if (first || last) return {
3199
+ word: word.charAt(0).toUpperCase() + word.slice(1).toLowerCase(),
3200
+ isMinorWord: false
3201
+ };
3202
+ if (minorWords.some((minorWord) => minorWord.toLowerCase() === word.toLowerCase())) return {
3203
+ word: word.toLowerCase(),
3204
+ isMinorWord: true
3205
+ };
3206
+ return {
3207
+ word: word.charAt(0).toUpperCase() + word.slice(1).toLowerCase(),
3208
+ isMinorWord: false
3209
+ };
3210
+ }
3211
+ if (first) return {
3212
+ word: word.charAt(0).toUpperCase() + word.slice(1).toLowerCase(),
3213
+ isMinorWord: false
3214
+ };
3215
+ return {
3216
+ word: word.toLowerCase(),
3217
+ isMinorWord: false
3218
+ };
3219
+ }
3220
+
3221
+ //#endregion
3222
+ //#region src/utils/preserve-words.ts
3223
+ var PreserveWordsContext = class {
3224
+ preserveWords;
3225
+ preservePhrases;
3226
+ constructor(preserveWordsOption) {
3227
+ const preserveWords = /* @__PURE__ */ new Map();
3228
+ /**
3229
+ * Add a single word to the preserveWords map
3230
+ */
3231
+ function addPreserveWord(word) {
3232
+ const lowerWord = word.toLowerCase();
3233
+ let list = preserveWords.get(lowerWord);
3234
+ if (!list) {
3235
+ list = [];
3236
+ preserveWords.set(lowerWord, list);
3237
+ }
3238
+ list.push(word);
3239
+ }
3240
+ const preservePhrases = /* @__PURE__ */ new Map();
3241
+ for (const word of preserveWordsOption) {
3242
+ const splitted = word.split(/\s+/);
3243
+ if (splitted.length <= 1) addPreserveWord(word);
3244
+ else {
3245
+ preservePhrases.set(word, splitted);
3246
+ addPreserveWord(splitted.join(""));
3247
+ }
741
3248
  }
742
- list.push(word);
3249
+ this.preserveWords = preserveWords;
3250
+ this.preservePhrases = [...preservePhrases.values()].sort((a, b) => b.length - a.length);
743
3251
  }
744
- const preservePhrases = /* @__PURE__ */ new Map();
745
- for (const word of preserveWordsOption) {
746
- const splitted = word.split(/\s+/);
747
- if (splitted.length <= 1) addPreserveWord(word);
748
- else {
749
- preservePhrases.set(word, splitted);
750
- addPreserveWord(splitted.join(""));
3252
+ findPreserveWord(word) {
3253
+ return this.preserveWords.get(word.toLowerCase()) ?? null;
3254
+ }
3255
+ findPreservePhrase(words) {
3256
+ const firstWord = words.next();
3257
+ if (firstWord.done) return null;
3258
+ const firstLowerWord = firstWord.value.toLowerCase();
3259
+ let returnCandidate = null;
3260
+ const subWords = [firstWord.value];
3261
+ for (const phrase of this.preservePhrases) {
3262
+ if (returnCandidate && returnCandidate.preservePhrase.length !== phrase.length) break;
3263
+ if (firstLowerWord !== phrase[0].toLowerCase()) continue;
3264
+ while (subWords.length < phrase.length) {
3265
+ const word = words.next();
3266
+ if (word.done) return null;
3267
+ subWords.push(word.value);
3268
+ }
3269
+ if (subWords.every((word, i) => word.toLowerCase() === phrase[i].toLowerCase())) {
3270
+ let matchCount = 0;
3271
+ for (let i = 0; i < subWords.length; i++) {
3272
+ const word = subWords[i];
3273
+ if (word === phrase[i]) matchCount++;
3274
+ }
3275
+ if (!returnCandidate || matchCount > returnCandidate.matchCount) returnCandidate = {
3276
+ preservePhrase: phrase,
3277
+ matchCount
3278
+ };
3279
+ }
751
3280
  }
3281
+ return returnCandidate?.preservePhrase ?? null;
752
3282
  }
753
- return {
754
- preserveWords,
755
- preservePhrases: [...preservePhrases.values()].sort((a, b) => b.length - a.length)
756
- };
3283
+ };
3284
+ /**
3285
+ * Parse preserve words and phrases from the options
3286
+ * - Single words are added to preserveWords
3287
+ * - Multi-word phrases are added to preservePhrases and added to preserveWords with no spaces
3288
+ */
3289
+ function parsePreserveWordsOption(preserveWordsOption) {
3290
+ return new PreserveWordsContext(preserveWordsOption);
757
3291
  }
3292
+
3293
+ //#endregion
3294
+ //#region src/utils/words.ts
758
3295
  /**
759
3296
  * Parse text into words with offsets
760
3297
  */
761
- function parseText(text, firstNode, lastNode) {
3298
+ function parseWordsFromText(text, firstNode, lastNode) {
762
3299
  const words = [];
763
3300
  const pattern = /(\w+(?:[^\s\w]\w+)*|:\w+:|[^\s\w]+|\s+)/gu;
764
3301
  let match;
@@ -775,47 +3312,23 @@ function parseText(text, firstNode, lastNode) {
775
3312
  });
776
3313
  }
777
3314
  if (firstNode) {
778
- for (const w of words) if (!w.punctuation) {
779
- w.first = true;
780
- break;
781
- }
782
- }
783
- if (lastNode) for (let i = words.length - 1; i >= 0; i--) {
784
- const w = words[i];
785
- if (!w.punctuation) {
786
- w.last = true;
787
- break;
788
- }
789
- }
790
- return words;
791
- }
792
- /**
793
- * Convert a single word based on case style and context
794
- */
795
- function convertWord({ word, first, last }, caseStyle, minorWords) {
796
- if (caseStyle === "Title Case") {
797
- if (first || last) return {
798
- word: word.charAt(0).toUpperCase() + word.slice(1).toLowerCase(),
799
- isMinorWord: false
800
- };
801
- if (minorWords.some((minorWord) => minorWord.toLowerCase() === word.toLowerCase())) return {
802
- word: word.toLowerCase(),
803
- isMinorWord: true
804
- };
805
- return {
806
- word: word.charAt(0).toUpperCase() + word.slice(1).toLowerCase(),
807
- isMinorWord: false
808
- };
3315
+ for (const w of words) if (!w.punctuation) {
3316
+ w.first = true;
3317
+ break;
3318
+ }
809
3319
  }
810
- if (first) return {
811
- word: word.charAt(0).toUpperCase() + word.slice(1).toLowerCase(),
812
- isMinorWord: false
813
- };
814
- return {
815
- word: word.toLowerCase(),
816
- isMinorWord: false
817
- };
3320
+ if (lastNode) for (let i = words.length - 1; i >= 0; i--) {
3321
+ const w = words[i];
3322
+ if (!w.punctuation) {
3323
+ w.last = true;
3324
+ break;
3325
+ }
3326
+ }
3327
+ return words;
818
3328
  }
3329
+
3330
+ //#endregion
3331
+ //#region src/rules/heading-casing.ts
819
3332
  var heading_casing_default = createRule("heading-casing", {
820
3333
  meta: {
821
3334
  type: "suggestion",
@@ -858,14 +3371,14 @@ var heading_casing_default = createRule("heading-casing", {
858
3371
  create(context) {
859
3372
  const sourceCode = context.sourceCode;
860
3373
  const caseStyle = context.options[0]?.style || "Title Case";
861
- const { preserveWords, preservePhrases } = parsePreserveWords(context.options[0]?.preserveWords || defaultPreserveWords);
3374
+ const preserveWordsOption = parsePreserveWordsOption(context.options[0]?.preserveWords || defaultPreserveWords);
862
3375
  const minorWords = context.options[0]?.minorWords || defaultMinorWords;
863
3376
  const ignorePatterns = (context.options[0]?.ignorePatterns || [
864
3377
  "/^v\\d+/u",
865
3378
  "/\\w+\\.[a-z\\d]+$/u",
866
- "/\\w*(?:API|Api)$/u",
867
- "/\\w*(?:SDK|Sdk)$/u",
868
- "/\\w*(?:CLI|Cli)$/u"
3379
+ "/\\w+(?:API|Api)$/u",
3380
+ "/\\w+(?:SDK|Sdk)$/u",
3381
+ "/\\w+(?:CLI|Cli)$/u"
869
3382
  ]).map((pattern) => {
870
3383
  if (isRegExp(pattern)) return toRegExp(pattern);
871
3384
  try {
@@ -881,7 +3394,7 @@ var heading_casing_default = createRule("heading-casing", {
881
3394
  */
882
3395
  function checkTextNode(node, firstNode, lastNode) {
883
3396
  const text = sourceCode.getText(node);
884
- const wordAndOffsets = parseText(text, firstNode, lastNode);
3397
+ const wordAndOffsets = parseWordsFromText(text, firstNode, lastNode);
885
3398
  const processed = /* @__PURE__ */ new Set();
886
3399
  for (let index = 0; index < wordAndOffsets.length; index++) {
887
3400
  if (processed.has(index)) continue;
@@ -889,7 +3402,12 @@ var heading_casing_default = createRule("heading-casing", {
889
3402
  const wordAndOffset = wordAndOffsets[index];
890
3403
  if (wordAndOffset.punctuation) continue;
891
3404
  if (ignorePatterns.some((pattern) => pattern.test(wordAndOffset.word))) continue;
892
- const preservePhrase = findPreservePhrase(wordAndOffsets, index);
3405
+ const preservePhrase = preserveWordsOption.findPreservePhrase((function* () {
3406
+ const firstWord = wordAndOffsets[index];
3407
+ if (firstWord.punctuation) return;
3408
+ yield firstWord.word;
3409
+ for (let next = index + 1; next < wordAndOffsets.length; next++) yield wordAndOffsets[next].word;
3410
+ })());
893
3411
  if (preservePhrase) {
894
3412
  for (let wordIndex = 0; wordIndex < preservePhrase.length; wordIndex++) {
895
3413
  processed.add(index + wordIndex);
@@ -897,12 +3415,15 @@ var heading_casing_default = createRule("heading-casing", {
897
3415
  }
898
3416
  continue;
899
3417
  }
900
- const preserveWordList = preserveWords.get(wordAndOffset.word.toLowerCase());
3418
+ const preserveWordList = preserveWordsOption.findPreserveWord(wordAndOffset.word);
901
3419
  if (preserveWordList) {
902
3420
  if (!preserveWordList.some((w) => w === wordAndOffset.word)) verifyWord(wordAndOffset, preserveWordList[0], "preserved");
903
3421
  continue;
904
3422
  }
905
- const expectedWordResult = convertWord(wordAndOffset, caseStyle, minorWords);
3423
+ const expectedWordResult = convertWordCasing(wordAndOffset, {
3424
+ caseStyle,
3425
+ minorWords
3426
+ });
906
3427
  verifyWord(wordAndOffset, expectedWordResult.word, expectedWordResult.isMinorWord ? "minor" : "normal");
907
3428
  }
908
3429
  /**
@@ -911,12 +3432,8 @@ var heading_casing_default = createRule("heading-casing", {
911
3432
  function verifyWord(wordAndOffset, expectedWord, wordType = "normal") {
912
3433
  const { word, offset } = wordAndOffset;
913
3434
  if (word === expectedWord) return;
914
- const nodeLoc = sourceCode.getLoc(node);
915
- const beforeLines = text.slice(0, offset).split(/\n/u);
916
- const line = nodeLoc.start.line + beforeLines.length - 1;
917
- const column = (beforeLines.length === 1 ? nodeLoc.start.column : 1) + (beforeLines.at(-1) || "").length;
918
- const nodeRange = sourceCode.getRange(node);
919
- const wordRange = [nodeRange[0] + offset, nodeRange[0] + offset + word.length];
3435
+ const [nodeStart] = sourceCode.getRange(node);
3436
+ const range = [nodeStart + offset, nodeStart + offset + word.length];
920
3437
  context.report({
921
3438
  node,
922
3439
  messageId: wordType === "preserved" ? "expectedPreserveWord" : caseStyle === "Title Case" ? wordType === "minor" ? "expectedTitleCaseMinorWord" : "expectedTitleCase" : "expectedSentenceCase",
@@ -924,112 +3441,23 @@ var heading_casing_default = createRule("heading-casing", {
924
3441
  actual: word,
925
3442
  expected: expectedWord
926
3443
  },
927
- loc: {
928
- start: {
929
- line,
930
- column
931
- },
932
- end: {
933
- line,
934
- column: column + word.length
935
- }
936
- },
3444
+ loc: getSourceLocationFromRange(sourceCode, node, range),
937
3445
  fix(fixer) {
938
- return fixer.replaceTextRange(wordRange, expectedWord);
3446
+ return fixer.replaceTextRange(range, expectedWord);
939
3447
  }
940
3448
  });
941
3449
  }
942
3450
  }
943
- /**
944
- * Find a preserve phrase starting from the given index
945
- * Returns the longest matching phrase or null if no match is found
946
- */
947
- function findPreservePhrase(wordAndOffsets, index) {
948
- const firstWord = wordAndOffsets[index];
949
- if (firstWord.punctuation) return null;
950
- const firstLowerWord = firstWord.word.toLowerCase();
951
- let returnCandidate = null;
952
- let subWords = null;
953
- for (const phrase of preservePhrases) {
954
- if (returnCandidate && returnCandidate.preservePhrase.length !== phrase.length) break;
955
- if (firstLowerWord !== phrase[0].toLowerCase()) continue;
956
- if (!subWords || subWords.length !== phrase.length) subWords = wordAndOffsets.slice(index, index + phrase.length).map((wo) => wo.word);
957
- if (subWords.length === phrase.length && subWords.every((word, i) => word.toLowerCase() === phrase[i].toLowerCase())) {
958
- let matchCount = 0;
959
- for (let i = 0; i < subWords.length; i++) {
960
- const word = subWords[i];
961
- if (word === phrase[i]) matchCount++;
962
- }
963
- if (!returnCandidate || matchCount > returnCandidate.matchCount) returnCandidate = {
964
- preservePhrase: phrase,
965
- matchCount
966
- };
967
- }
968
- }
969
- return returnCandidate?.preservePhrase ?? null;
970
- }
971
3451
  return { heading(node) {
972
3452
  if (!node.children.length) return;
973
3453
  const children = node.children.filter((child) => child.type !== "text" || child.value.trim());
974
3454
  children.forEach((child, i) => {
975
- if (child.type === "text") checkTextNode(child, i === 0, i === node.children.length - 1);
3455
+ if (child.type === "text") checkTextNode(child, i === 0, i === children.length - 1);
976
3456
  });
977
3457
  } };
978
3458
  }
979
3459
  });
980
3460
 
981
- //#endregion
982
- //#region src/utils/lines.ts
983
- const cache = /* @__PURE__ */ new WeakMap();
984
- var ParsedLines = class {
985
- lines;
986
- constructor(codeText) {
987
- let offset = 0;
988
- this.lines = codeText.split(/(?<=\n)/u).map((lineText, index) => {
989
- const start = offset;
990
- offset += lineText.length;
991
- const range = [start, offset];
992
- let text = lineText;
993
- let linebreak = "";
994
- if (text.at(-1) === "\n") {
995
- text = text.slice(0, -1);
996
- linebreak = "\n";
997
- }
998
- if (text.at(-1) === "\r") {
999
- text = text.slice(0, -1);
1000
- linebreak = `\r${linebreak}`;
1001
- }
1002
- return {
1003
- text,
1004
- range,
1005
- line: index + 1,
1006
- linebreak
1007
- };
1008
- });
1009
- }
1010
- [Symbol.iterator]() {
1011
- return this.lines[Symbol.iterator]();
1012
- }
1013
- get length() {
1014
- return this.lines.length;
1015
- }
1016
- get(lineNumber) {
1017
- return this.lines[lineNumber - 1];
1018
- }
1019
- };
1020
- /**
1021
- * Parse the lines of the source code.
1022
- * @param sourceCode source code to parse
1023
- * @returns parsed lines
1024
- */
1025
- function parseLines(sourceCode) {
1026
- const cached = cache.get(sourceCode);
1027
- if (cached) return cached;
1028
- const parsedLines = new ParsedLines(sourceCode.text);
1029
- cache.set(sourceCode, parsedLines);
1030
- return parsedLines;
1031
- }
1032
-
1033
3461
  //#endregion
1034
3462
  //#region src/rules/no-laziness-blockquotes.ts
1035
3463
  /**
@@ -1309,11 +3737,11 @@ var no_multiple_empty_lines_default = createRule("no-multiple-empty-lines", {
1309
3737
  //#region src/rules/no-text-backslash-linebreak.ts
1310
3738
  var no_text_backslash_linebreak_default = createRule("no-text-backslash-linebreak", {
1311
3739
  meta: {
1312
- type: "suggestion",
3740
+ type: "layout",
1313
3741
  docs: {
1314
3742
  description: "disallow text backslash at the end of a line.",
1315
3743
  categories: ["recommended"],
1316
- listCategory: "Preference"
3744
+ listCategory: "Stylistic"
1317
3745
  },
1318
3746
  fixable: void 0,
1319
3747
  hasSuggestions: true,
@@ -1333,27 +3761,15 @@ var no_text_backslash_linebreak_default = createRule("no-text-backslash-linebrea
1333
3761
  if (c.trim() !== "") return;
1334
3762
  if (c === "\n") break;
1335
3763
  }
1336
- const loc = sourceCode.getLoc(node);
1337
- const beforeLines = sourceCode.text.slice(range[0], range[1] - 1).split(/\n/u);
1338
- const line = loc.start.line + beforeLines.length - 1;
1339
- const column = (beforeLines.length === 1 ? loc.start.column : 1) + (beforeLines.at(-1) || "").length;
3764
+ const backslashRange = [range[1] - 1, range[1]];
1340
3765
  context.report({
1341
3766
  node,
1342
- loc: {
1343
- start: {
1344
- line,
1345
- column
1346
- },
1347
- end: {
1348
- line,
1349
- column: column + 1
1350
- }
1351
- },
3767
+ loc: getSourceLocationFromRange(sourceCode, node, backslashRange),
1352
3768
  messageId: "textBackslashWithLinebreak",
1353
3769
  suggest: [{
1354
3770
  messageId: "removeBackslash",
1355
3771
  fix: (fixer) => {
1356
- return fixer.removeRange([range[1] - 1, range[1]]);
3772
+ return fixer.removeRange(backslashRange);
1357
3773
  }
1358
3774
  }]
1359
3775
  });
@@ -1464,54 +3880,6 @@ var no_trailing_spaces_default = createRule("no-trailing-spaces", {
1464
3880
  }
1465
3881
  });
1466
3882
 
1467
- //#endregion
1468
- //#region src/utils/ast.ts
1469
- /**
1470
- * Get the kind of code block.
1471
- */
1472
- function getCodeBlockKind(sourceCode, node) {
1473
- const text = sourceCode.getText(node);
1474
- return text.startsWith("```") ? "backtick-fenced" : text.startsWith("~~~") ? "tilde-fenced" : "indented";
1475
- }
1476
- /**
1477
- * Get the kind of link.
1478
- */
1479
- function getLinkKind(sourceCode, node) {
1480
- const text = sourceCode.getText(node);
1481
- return text.startsWith("[") ? "inline" : text.startsWith("<") && text.endsWith(">") ? "autolink" : "gfm-autolink";
1482
- }
1483
- /**
1484
- * Get the marker of a list item.
1485
- */
1486
- function getListItemMarker(sourceCode, node) {
1487
- const item = node.type === "list" ? node.children[0] || node : node;
1488
- const text = sourceCode.getText(item);
1489
- if (text.startsWith("-")) return {
1490
- kind: "-",
1491
- raw: "-"
1492
- };
1493
- if (text.startsWith("*")) return {
1494
- kind: "*",
1495
- raw: "*"
1496
- };
1497
- if (text.startsWith("+")) return {
1498
- kind: "+",
1499
- raw: "+"
1500
- };
1501
- const matchDot = /^(\d+)\./.exec(text);
1502
- if (matchDot) return {
1503
- kind: ".",
1504
- raw: matchDot[0],
1505
- sequence: Number(matchDot[1])
1506
- };
1507
- const matchParen = /^(\d+)\)/.exec(text);
1508
- return {
1509
- kind: ")",
1510
- raw: matchParen[0],
1511
- sequence: Number(matchParen[1])
1512
- };
1513
- }
1514
-
1515
3883
  //#endregion
1516
3884
  //#region src/rules/ordered-list-marker-sequence.ts
1517
3885
  var ordered_list_marker_sequence_default = createRule("ordered-list-marker-sequence", {
@@ -1852,23 +4220,11 @@ function* iterateSearchWords({ sourceCode, node, words, ignores }) {
1852
4220
  if (index < 0) break;
1853
4221
  startPosition = index + word.length;
1854
4222
  if (!RE_BOUNDARY.test(text[index - 1] || "") || !RE_BOUNDARY.test(text[index + word.length] || "")) continue;
1855
- const loc = sourceCode.getLoc(node);
1856
- const beforeLines = text.slice(0, index).split(/\n/u);
1857
- const line = loc.start.line + beforeLines.length - 1;
1858
- const column = (beforeLines.length === 1 ? loc.start.column : 1) + (beforeLines.at(-1) || "").length;
1859
- const range = sourceCode.getRange(node);
4223
+ const [nodeStart] = sourceCode.getRange(node);
4224
+ const range = [nodeStart + index, nodeStart + index + word.length];
1860
4225
  yield {
1861
- loc: {
1862
- start: {
1863
- line,
1864
- column
1865
- },
1866
- end: {
1867
- line,
1868
- column: column + word.length
1869
- }
1870
- },
1871
- range: [range[0] + index, range[0] + index + word.length],
4226
+ loc: getSourceLocationFromRange(sourceCode, node, range),
4227
+ range,
1872
4228
  word
1873
4229
  };
1874
4230
  }
@@ -2562,11 +4918,148 @@ function normalizedURL(url) {
2562
4918
  return urlObj.href.endsWith("/") ? urlObj.href : `${urlObj.href}/`;
2563
4919
  }
2564
4920
 
4921
+ //#endregion
4922
+ //#region src/rules/table-header-casing.ts
4923
+ var table_header_casing_default = createRule("table-header-casing", {
4924
+ meta: {
4925
+ type: "suggestion",
4926
+ fixable: "code",
4927
+ docs: {
4928
+ description: "enforce consistent casing in table header cells.",
4929
+ categories: [],
4930
+ listCategory: "Preference"
4931
+ },
4932
+ schema: [{
4933
+ type: "object",
4934
+ properties: {
4935
+ style: { enum: ["Title Case", "Sentence case"] },
4936
+ preserveWords: {
4937
+ type: "array",
4938
+ items: { type: "string" },
4939
+ description: "Words that should be preserved as-is (case-insensitive matching)"
4940
+ },
4941
+ ignorePatterns: {
4942
+ type: "array",
4943
+ items: { type: "string" },
4944
+ description: "Regular expression patterns for words to ignore during casing checks"
4945
+ },
4946
+ minorWords: {
4947
+ type: "array",
4948
+ items: { type: "string" },
4949
+ description: "Words that should not be capitalized in Title Case (unless they're the first or last word)"
4950
+ }
4951
+ },
4952
+ additionalProperties: false
4953
+ }],
4954
+ messages: {
4955
+ expectedTitleCase: "Expected \"{{actual}}\" to be \"{{expected}}\" (Title Case).",
4956
+ expectedTitleCaseMinorWord: "Expected \"{{actual}}\" to be \"{{expected}}\" (Title Case - minor word).",
4957
+ expectedSentenceCase: "Expected \"{{actual}}\" to be \"{{expected}}\" (Sentence case).",
4958
+ expectedPreserveWord: "Expected \"{{actual}}\" to be \"{{expected}}\" (preserved word)."
4959
+ }
4960
+ },
4961
+ create(context) {
4962
+ const sourceCode = context.sourceCode;
4963
+ const caseStyle = context.options[0]?.style || "Title Case";
4964
+ const preserveWordsOption = parsePreserveWordsOption(context.options[0]?.preserveWords || defaultPreserveWords);
4965
+ const minorWords = context.options[0]?.minorWords || defaultMinorWords;
4966
+ const ignorePatterns = (context.options[0]?.ignorePatterns || [
4967
+ "/^v\\d+/u",
4968
+ "/\\w+\\.[a-z\\d]+$/u",
4969
+ "/\\w+(?:API|Api)$/u",
4970
+ "/\\w+(?:SDK|Sdk)$/u",
4971
+ "/\\w+(?:CLI|Cli)$/u"
4972
+ ]).map((pattern) => {
4973
+ if (isRegExp(pattern)) return toRegExp(pattern);
4974
+ try {
4975
+ return new RegExp(pattern, "v");
4976
+ } catch {}
4977
+ try {
4978
+ return new RegExp(pattern, "u");
4979
+ } catch {}
4980
+ return new RegExp(pattern);
4981
+ });
4982
+ /**
4983
+ * Check text node and report word-level errors
4984
+ */
4985
+ function checkTextNode(node, firstNode, lastNode) {
4986
+ const text = sourceCode.getText(node);
4987
+ const wordAndOffsets = parseWordsFromText(text, firstNode, lastNode);
4988
+ const processed = /* @__PURE__ */ new Set();
4989
+ for (let index = 0; index < wordAndOffsets.length; index++) {
4990
+ if (processed.has(index)) continue;
4991
+ processed.add(index);
4992
+ const wordAndOffset = wordAndOffsets[index];
4993
+ if (wordAndOffset.punctuation) continue;
4994
+ if (ignorePatterns.some((pattern) => pattern.test(wordAndOffset.word))) continue;
4995
+ const preservePhrase = preserveWordsOption.findPreservePhrase((function* () {
4996
+ const firstWord = wordAndOffsets[index];
4997
+ if (firstWord.punctuation) return;
4998
+ yield firstWord.word;
4999
+ for (let next = index + 1; next < wordAndOffsets.length; next++) yield wordAndOffsets[next].word;
5000
+ })());
5001
+ if (preservePhrase) {
5002
+ for (let wordIndex = 0; wordIndex < preservePhrase.length; wordIndex++) {
5003
+ processed.add(index + wordIndex);
5004
+ verifyWord(wordAndOffsets[index + wordIndex], preservePhrase[wordIndex], "preserved");
5005
+ }
5006
+ continue;
5007
+ }
5008
+ const preserveWordList = preserveWordsOption.findPreserveWord(wordAndOffset.word);
5009
+ if (preserveWordList) {
5010
+ if (!preserveWordList.some((w) => w === wordAndOffset.word)) verifyWord(wordAndOffset, preserveWordList[0], "preserved");
5011
+ continue;
5012
+ }
5013
+ const expectedWordResult = convertWordCasing(wordAndOffset, {
5014
+ caseStyle,
5015
+ minorWords
5016
+ });
5017
+ verifyWord(wordAndOffset, expectedWordResult.word, expectedWordResult.isMinorWord ? "minor" : "normal");
5018
+ }
5019
+ /**
5020
+ * Verify a single word against the expected casing
5021
+ */
5022
+ function verifyWord(wordAndOffset, expectedWord, wordType = "normal") {
5023
+ const { word, offset } = wordAndOffset;
5024
+ if (word === expectedWord) return;
5025
+ const [nodeStart] = sourceCode.getRange(node);
5026
+ const range = [nodeStart + offset, nodeStart + offset + word.length];
5027
+ context.report({
5028
+ node,
5029
+ messageId: wordType === "preserved" ? "expectedPreserveWord" : caseStyle === "Title Case" ? wordType === "minor" ? "expectedTitleCaseMinorWord" : "expectedTitleCase" : "expectedSentenceCase",
5030
+ data: {
5031
+ actual: word,
5032
+ expected: expectedWord
5033
+ },
5034
+ loc: getSourceLocationFromRange(sourceCode, node, range),
5035
+ fix(fixer) {
5036
+ return fixer.replaceTextRange(range, expectedWord);
5037
+ }
5038
+ });
5039
+ }
5040
+ }
5041
+ return { table(node) {
5042
+ if (!node.children.length) return;
5043
+ const headerRow = node.children[0];
5044
+ if (headerRow.type !== "tableRow") return;
5045
+ for (const cell of headerRow.children) {
5046
+ const children = cell.children.filter((child) => child.type !== "text" || child.value.trim());
5047
+ children.forEach((child, i) => {
5048
+ if (child.type === "text") checkTextNode(child, i === 0, i === children.length - 1);
5049
+ });
5050
+ }
5051
+ } };
5052
+ }
5053
+ });
5054
+
2565
5055
  //#endregion
2566
5056
  //#region src/utils/rules.ts
2567
5057
  const rules$1 = [
5058
+ atx_headings_closing_sequence_length_default,
5059
+ atx_headings_closing_sequence_default,
2568
5060
  canonical_code_block_language_default,
2569
5061
  definitions_last_default,
5062
+ emoji_notation_default,
2570
5063
  hard_linebreak_style_default,
2571
5064
  heading_casing_default,
2572
5065
  no_laziness_blockquotes_default,
@@ -2580,7 +5073,8 @@ const rules$1 = [
2580
5073
  prefer_inline_code_words_default,
2581
5074
  prefer_link_reference_definitions_default,
2582
5075
  prefer_linked_words_default,
2583
- sort_definitions_default
5076
+ sort_definitions_default,
5077
+ table_header_casing_default
2584
5078
  ];
2585
5079
 
2586
5080
  //#endregion
@@ -2620,7 +5114,7 @@ __export(meta_exports, {
2620
5114
  version: () => version
2621
5115
  });
2622
5116
  const name = "eslint-plugin-markdown-preferences";
2623
- const version = "0.12.0";
5117
+ const version = "0.14.0";
2624
5118
 
2625
5119
  //#endregion
2626
5120
  //#region src/index.ts