@mandolin/jsdoc-plugin-hia-sys 0.1.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.
@@ -0,0 +1,796 @@
1
+ "use strict";
2
+
3
+ const {
4
+ getResourceEntry,
5
+ loadLocalizationResources,
6
+ normalizeLocalizedValue,
7
+ parseLocaleValue
8
+ } = require("../runtime/i18n.cjs");
9
+
10
+ const TEXT_I18N_MODEL = "hia-jsdoc-text-i18n";
11
+ const TEXT_I18N_MODEL_VERSION = "0.2.0";
12
+
13
+ function rememberTag(doclet, name, value) {
14
+ doclet.hiaTags = doclet.hiaTags || {};
15
+ doclet.hiaTags[name] = value;
16
+ }
17
+
18
+ function appendTag(doclet, name, value) {
19
+ doclet.hiaTags = doclet.hiaTags || {};
20
+ doclet.hiaTags[name] = doclet.hiaTags[name] || [];
21
+ doclet.hiaTags[name].push(value);
22
+ }
23
+
24
+ function getDocletLabel(doclet) {
25
+ return doclet.longname || doclet.name || "";
26
+ }
27
+
28
+ function getFallbackLocales(config) {
29
+ const fallbackLocale = config.i18n.fallbackLocale;
30
+
31
+ if (Array.isArray(fallbackLocale)) {
32
+ return fallbackLocale.filter(Boolean);
33
+ }
34
+
35
+ return fallbackLocale ? [fallbackLocale] : [];
36
+ }
37
+
38
+ function normalizeLocales(config) {
39
+ const locales = Array.isArray(config.i18n.locales)
40
+ ? config.i18n.locales.slice()
41
+ : [];
42
+
43
+ if (config.i18n.defaultLocale && !locales.includes(config.i18n.defaultLocale)) {
44
+ locales.unshift(config.i18n.defaultLocale);
45
+ }
46
+
47
+ return locales;
48
+ }
49
+
50
+ function pushUnique(target, value) {
51
+ if (value && !target.includes(value)) {
52
+ target.push(value);
53
+ }
54
+ }
55
+
56
+ function getParentLocale(locale) {
57
+ const match = /^([A-Za-z]{2,3})[-_]/.exec(locale || "");
58
+ return match ? match[1] : "";
59
+ }
60
+
61
+ function buildFallbackChain(requestedLocale, config) {
62
+ const chain = [];
63
+
64
+ pushUnique(chain, requestedLocale);
65
+ pushUnique(chain, getParentLocale(requestedLocale));
66
+
67
+ for (const locale of getFallbackLocales(config)) {
68
+ pushUnique(chain, locale);
69
+ pushUnique(chain, getParentLocale(locale));
70
+ }
71
+
72
+ pushUnique(chain, config.i18n.defaultLocale);
73
+
74
+ return chain;
75
+ }
76
+
77
+ function isKnownLocale(locale, context) {
78
+ const knownLocales = new Set([
79
+ ...normalizeLocales(context.config),
80
+ ...getFallbackLocales(context.config),
81
+ context.config.i18n.defaultLocale
82
+ ].filter(Boolean));
83
+
84
+ return knownLocales.has(locale) || knownLocales.has(getParentLocale(locale));
85
+ }
86
+
87
+ function addUnknownLocaleDiagnostic(locale, context, doclet, fieldPath) {
88
+ if (!locale || isKnownLocale(locale, context)) {
89
+ return;
90
+ }
91
+
92
+ context.addDiagnostic({
93
+ code: "HIA_I18N_LOCALE_UNKNOWN",
94
+ severity: "warning",
95
+ message: `Unknown locale in localized documentation: ${locale}`,
96
+ plugin: "doc-i18n",
97
+ data: {
98
+ locale,
99
+ fieldPath,
100
+ doclet: getDocletLabel(doclet)
101
+ }
102
+ });
103
+ }
104
+
105
+ function buildLocalizationKey(doclet, tags) {
106
+ return tags.key || doclet.longname || doclet.name || "";
107
+ }
108
+
109
+ function buildLocalizationPath(doclet, tags) {
110
+ return tags.path || doclet.memberof || doclet.longname || doclet.name || "";
111
+ }
112
+
113
+ function parseAttributes(rawAttributes) {
114
+ const attributes = {};
115
+ const pattern = /([A-Za-z_:][\w:.-]*)\s*=\s*(?:"([^"]*)"|'([^']*)')/g;
116
+ let match;
117
+
118
+ while ((match = pattern.exec(rawAttributes || ""))) {
119
+ attributes[match[1]] = match[2] || match[3] || "";
120
+ }
121
+
122
+ return attributes;
123
+ }
124
+
125
+ function parseInlineLocalizedValues(innerText, context, doclet, fieldPath) {
126
+ const localized = {};
127
+ const pattern = /<([A-Za-z]{2,3}(?:[-_][A-Za-z0-9]{2,8})*)>([\s\S]*?)<\/\1>/g;
128
+ let match;
129
+
130
+ while ((match = pattern.exec(innerText || ""))) {
131
+ const locale = match[1];
132
+
133
+ addUnknownLocaleDiagnostic(locale, context, doclet, fieldPath);
134
+
135
+ if (Object.prototype.hasOwnProperty.call(localized, locale)) {
136
+ context.addDiagnostic({
137
+ code: "HIA_I18N_INLINE_LOCALE_DUPLICATE",
138
+ severity: "error",
139
+ message: `Duplicate inline localized text for locale: ${locale}`,
140
+ plugin: "doc-i18n",
141
+ data: {
142
+ locale,
143
+ fieldPath,
144
+ doclet: getDocletLabel(doclet)
145
+ }
146
+ });
147
+ }
148
+
149
+ localized[locale] = match[2].trim();
150
+ }
151
+
152
+ return localized;
153
+ }
154
+
155
+ function parseInlineSegments(text, fieldPath, context, doclet) {
156
+ const sourceText = String(text || "");
157
+ const segments = [];
158
+ const seenKeys = new Set();
159
+ const pattern = /<lang\b([^>]*)>([\s\S]*?)<\/lang>/g;
160
+ let match;
161
+
162
+ while ((match = pattern.exec(sourceText))) {
163
+ const attributes = parseAttributes(match[1]);
164
+ const localized = parseInlineLocalizedValues(match[2], context, doclet, fieldPath);
165
+ const key = attributes.key || "";
166
+
167
+ if (key) {
168
+ if (seenKeys.has(key)) {
169
+ context.addDiagnostic({
170
+ code: "HIA_I18N_INLINE_KEY_DUPLICATE",
171
+ severity: "warning",
172
+ message: `Duplicate inline localized key: ${key}`,
173
+ plugin: "doc-i18n",
174
+ data: {
175
+ key,
176
+ fieldPath,
177
+ doclet: getDocletLabel(doclet)
178
+ }
179
+ });
180
+ }
181
+
182
+ seenKeys.add(key);
183
+ }
184
+
185
+ if (Object.keys(localized).length === 0) {
186
+ context.addDiagnostic({
187
+ code: "HIA_I18N_INLINE_LANG_MALFORMED",
188
+ severity: "error",
189
+ message: "Malformed <lang> inline segment has no localized child nodes.",
190
+ plugin: "doc-i18n",
191
+ data: {
192
+ fieldPath,
193
+ doclet: getDocletLabel(doclet)
194
+ }
195
+ });
196
+ }
197
+
198
+ segments.push({
199
+ kind: "lang-inline",
200
+ id: `${fieldPath}.${segments.length}`,
201
+ key,
202
+ path: attributes.path || "",
203
+ fieldPath,
204
+ raw: match[0],
205
+ localized,
206
+ rangeInField: {
207
+ start: match.index,
208
+ end: match.index + match[0].length
209
+ }
210
+ });
211
+ }
212
+
213
+ const rawLangCount = (sourceText.match(/<lang\b/gi) || []).length;
214
+
215
+ if (rawLangCount > segments.length) {
216
+ context.addDiagnostic({
217
+ code: "HIA_I18N_INLINE_LANG_MALFORMED",
218
+ severity: "error",
219
+ message: "Malformed <lang> inline segment was found.",
220
+ plugin: "doc-i18n",
221
+ data: {
222
+ fieldPath,
223
+ doclet: getDocletLabel(doclet)
224
+ }
225
+ });
226
+ }
227
+
228
+ return segments;
229
+ }
230
+
231
+ function resolveLocalizedValue(variants, requestedLocale, config, defaultText) {
232
+ const fallbackChain = buildFallbackChain(requestedLocale, config);
233
+
234
+ for (const locale of fallbackChain) {
235
+ if (typeof variants[locale] === "string" && variants[locale].length > 0) {
236
+ return {
237
+ text: variants[locale],
238
+ resolution: {
239
+ requestedLocale,
240
+ resolvedLocale: locale,
241
+ fallbackChain,
242
+ usedFallback: locale !== requestedLocale,
243
+ missing: false
244
+ }
245
+ };
246
+ }
247
+ }
248
+
249
+ return {
250
+ text: defaultText || "",
251
+ resolution: {
252
+ requestedLocale,
253
+ resolvedLocale: defaultText ? config.i18n.defaultLocale : "",
254
+ fallbackChain,
255
+ usedFallback: Boolean(defaultText && requestedLocale !== config.i18n.defaultLocale),
256
+ missing: !defaultText
257
+ }
258
+ };
259
+ }
260
+
261
+ function renderTextWithSegments(text, segments, requestedLocale, config) {
262
+ let result = "";
263
+ let lastIndex = 0;
264
+
265
+ for (const segment of segments) {
266
+ const resolved = resolveLocalizedValue(
267
+ segment.localized,
268
+ requestedLocale,
269
+ config,
270
+ segment.raw
271
+ );
272
+
273
+ result += String(text || "").slice(lastIndex, segment.rangeInField.start);
274
+ result += resolved.text;
275
+ lastIndex = segment.rangeInField.end;
276
+ }
277
+
278
+ result += String(text || "").slice(lastIndex);
279
+
280
+ return result;
281
+ }
282
+
283
+ function createLangBlock(rawValue, source, context, doclet) {
284
+ const parsed = parseLocaleValue(rawValue);
285
+ const locale = parsed.locale;
286
+
287
+ if (!locale) {
288
+ context.addDiagnostic({
289
+ code: source.startsWith("legacy")
290
+ ? "HIA_I18N_INLINE_LOCALE_MISSING"
291
+ : "HIA_I18N_LANG_LOCALE_MISSING",
292
+ severity: "error",
293
+ message: "Missing locale for localized documentation block.",
294
+ plugin: "doc-i18n",
295
+ data: {
296
+ doclet: getDocletLabel(doclet)
297
+ }
298
+ });
299
+ }
300
+
301
+ if (locale) {
302
+ addUnknownLocaleDiagnostic(locale, context, doclet, "description");
303
+ }
304
+
305
+ if (locale && !parsed.value) {
306
+ context.addDiagnostic({
307
+ code: "HIA_I18N_LANG_EMPTY",
308
+ severity: "warning",
309
+ message: `Empty localized documentation block for locale: ${locale}`,
310
+ plugin: "doc-i18n",
311
+ data: {
312
+ locale,
313
+ doclet: getDocletLabel(doclet)
314
+ }
315
+ });
316
+ }
317
+
318
+ return {
319
+ kind: "lang-block",
320
+ locale,
321
+ fieldPath: "description",
322
+ text: parsed.value,
323
+ block: "",
324
+ source,
325
+ rangeInComment: null
326
+ };
327
+ }
328
+
329
+ function addBlock(blocks, block, context, doclet) {
330
+ if (!block.locale) {
331
+ return;
332
+ }
333
+
334
+ const duplicate = blocks.some((item) => item.locale === block.locale);
335
+
336
+ if (duplicate) {
337
+ context.addDiagnostic({
338
+ code: block.source.startsWith("legacy")
339
+ ? "HIA_I18N_INLINE_LOCALE_DUPLICATE"
340
+ : "HIA_I18N_LANG_LOCALE_DUPLICATE",
341
+ severity: "error",
342
+ message: `Duplicate localized documentation block for locale: ${block.locale}`,
343
+ plugin: "doc-i18n",
344
+ data: {
345
+ locale: block.locale,
346
+ fieldPath: block.fieldPath,
347
+ doclet: getDocletLabel(doclet)
348
+ }
349
+ });
350
+ }
351
+
352
+ blocks.push(block);
353
+ }
354
+
355
+ function buildDescriptionBlocks(doclet, tags, context) {
356
+ const blocks = [];
357
+
358
+ for (const rawValue of tags.lang || []) {
359
+ addBlock(blocks, createLangBlock(rawValue, "tag", context, doclet), context, doclet);
360
+ }
361
+
362
+ for (const rawValue of tags.text || []) {
363
+ addBlock(blocks, createLangBlock(rawValue, "legacy-text", context, doclet), context, doclet);
364
+ }
365
+
366
+ for (const rawValue of tags.block || []) {
367
+ const block = createLangBlock(rawValue, "legacy-block", context, doclet);
368
+ block.block = block.text;
369
+ addBlock(blocks, block, context, doclet);
370
+ }
371
+
372
+ return blocks;
373
+ }
374
+
375
+ function addResourceBlocks(blocks, key, context) {
376
+ const existingLocales = new Set(blocks.map((block) => block.locale));
377
+
378
+ for (const locale of normalizeLocales(context.config)) {
379
+ if (existingLocales.has(locale)) {
380
+ continue;
381
+ }
382
+
383
+ const resourceEntry = getResourceEntry(
384
+ context.state.registries.localizationEntries,
385
+ locale,
386
+ key
387
+ );
388
+
389
+ if (!resourceEntry) {
390
+ continue;
391
+ }
392
+
393
+ const normalized = normalizeLocalizedValue(resourceEntry);
394
+ blocks.push({
395
+ kind: "lang-block",
396
+ locale,
397
+ fieldPath: "description",
398
+ text: normalized.text || normalized.block || "",
399
+ block: normalized.block || "",
400
+ source: "resource",
401
+ rangeInComment: null,
402
+ data: normalized.data
403
+ });
404
+ existingLocales.add(locale);
405
+ }
406
+ }
407
+
408
+ function sanitizeFieldPathPart(value, fallback) {
409
+ const text = String(value || fallback || "").trim();
410
+ return text.replace(/\s+/g, "_").replace(/[.]/g, "_") || fallback;
411
+ }
412
+
413
+ function addTextField(target, fieldPath, kind, defaultText, source, blocks) {
414
+ if (!defaultText && (!Array.isArray(blocks) || blocks.length === 0)) {
415
+ return;
416
+ }
417
+
418
+ target.push({
419
+ fieldPath,
420
+ kind,
421
+ defaultText: String(defaultText || ""),
422
+ source,
423
+ blocks: Array.isArray(blocks) ? blocks : []
424
+ });
425
+ }
426
+
427
+ function splitExample(example) {
428
+ const text = String(example || "");
429
+ const match = /^<caption>([\s\S]*?)<\/caption>\s*([\s\S]*)$/i.exec(text);
430
+
431
+ if (!match) {
432
+ return {
433
+ caption: "",
434
+ body: text
435
+ };
436
+ }
437
+
438
+ return {
439
+ caption: match[1].trim(),
440
+ body: match[2]
441
+ };
442
+ }
443
+
444
+ function collectTextFields(doclet, descriptionBlocks) {
445
+ const fields = [];
446
+
447
+ addTextField(fields, "description", "description", doclet.description, "doclet.description", descriptionBlocks);
448
+ addTextField(fields, "classdesc", "classdesc", doclet.classdesc, "doclet.classdesc", []);
449
+
450
+ for (const [index, param] of (doclet.params || []).entries()) {
451
+ addTextField(
452
+ fields,
453
+ `params.${sanitizeFieldPathPart(param.name, index)}.description`,
454
+ "param.description",
455
+ param.description,
456
+ `doclet.params.${index}.description`,
457
+ []
458
+ );
459
+ }
460
+
461
+ for (const [index, item] of (doclet.returns || []).entries()) {
462
+ addTextField(
463
+ fields,
464
+ `returns.${index}.description`,
465
+ "return.description",
466
+ item.description,
467
+ `doclet.returns.${index}.description`,
468
+ []
469
+ );
470
+ }
471
+
472
+ for (const [index, property] of (doclet.properties || []).entries()) {
473
+ addTextField(
474
+ fields,
475
+ `properties.${sanitizeFieldPathPart(property.name, index)}.description`,
476
+ "property.description",
477
+ property.description,
478
+ `doclet.properties.${index}.description`,
479
+ []
480
+ );
481
+ }
482
+
483
+ for (const [index, example] of (doclet.examples || []).entries()) {
484
+ const parsed = splitExample(example);
485
+ addTextField(
486
+ fields,
487
+ `examples.${index}.caption`,
488
+ "example.caption",
489
+ parsed.caption,
490
+ `doclet.examples.${index}.caption`,
491
+ []
492
+ );
493
+ addTextField(
494
+ fields,
495
+ `examples.${index}.body`,
496
+ "example.body",
497
+ parsed.body,
498
+ `doclet.examples.${index}.body`,
499
+ []
500
+ );
501
+ }
502
+
503
+ return fields;
504
+ }
505
+
506
+ function findBlockForLocale(blocks, locale) {
507
+ for (let index = blocks.length - 1; index >= 0; index -= 1) {
508
+ if (blocks[index].locale === locale) {
509
+ return blocks[index];
510
+ }
511
+ }
512
+
513
+ return null;
514
+ }
515
+
516
+ function resolveFieldText(fieldSeed, segments, requestedLocale, context) {
517
+ const fallbackChain = buildFallbackChain(requestedLocale, context.config);
518
+
519
+ for (const locale of fallbackChain) {
520
+ const block = findBlockForLocale(fieldSeed.blocks, locale);
521
+
522
+ if (block && (block.text || block.block)) {
523
+ return {
524
+ text: block.text || block.block,
525
+ resolution: {
526
+ requestedLocale,
527
+ resolvedLocale: locale,
528
+ fallbackChain,
529
+ usedFallback: locale !== requestedLocale,
530
+ missing: false
531
+ }
532
+ };
533
+ }
534
+ }
535
+
536
+ const rendered = renderTextWithSegments(
537
+ fieldSeed.defaultText,
538
+ segments,
539
+ requestedLocale,
540
+ context.config
541
+ );
542
+ const hasText = Boolean(rendered);
543
+
544
+ return {
545
+ text: rendered,
546
+ resolution: {
547
+ requestedLocale,
548
+ resolvedLocale: hasText ? context.config.i18n.defaultLocale : "",
549
+ fallbackChain,
550
+ usedFallback: hasText && requestedLocale !== context.config.i18n.defaultLocale,
551
+ missing: !hasText
552
+ }
553
+ };
554
+ }
555
+
556
+ function createTextField(fieldSeed, context, doclet) {
557
+ const segments = parseInlineSegments(
558
+ fieldSeed.defaultText,
559
+ fieldSeed.fieldPath,
560
+ context,
561
+ doclet
562
+ );
563
+ const localizedText = {};
564
+ const resolutions = {};
565
+ const directLocales = new Set();
566
+ const locales = normalizeLocales(context.config);
567
+
568
+ if (fieldSeed.defaultText) {
569
+ directLocales.add(context.config.i18n.defaultLocale);
570
+ }
571
+
572
+ for (const block of fieldSeed.blocks) {
573
+ if (block.locale) {
574
+ directLocales.add(block.locale);
575
+ }
576
+ }
577
+
578
+ for (const locale of locales) {
579
+ const resolved = resolveFieldText(fieldSeed, segments, locale, context);
580
+ localizedText[locale] = resolved.text;
581
+ resolutions[locale] = resolved.resolution;
582
+ }
583
+
584
+ return {
585
+ fieldPath: fieldSeed.fieldPath,
586
+ kind: fieldSeed.kind,
587
+ defaultLocale: context.config.i18n.defaultLocale,
588
+ defaultText: fieldSeed.defaultText,
589
+ source: fieldSeed.source,
590
+ blocks: fieldSeed.blocks,
591
+ segments,
592
+ localizedText,
593
+ resolutions,
594
+ missingLocales: locales.filter((locale) => !directLocales.has(locale))
595
+ };
596
+ }
597
+
598
+ function buildFields(doclet, descriptionBlocks, context) {
599
+ const fields = {};
600
+
601
+ for (const fieldSeed of collectTextFields(doclet, descriptionBlocks)) {
602
+ fields[fieldSeed.fieldPath] = createTextField(fieldSeed, context, doclet);
603
+ }
604
+
605
+ return fields;
606
+ }
607
+
608
+ function hasLocalizationIntent(tags) {
609
+ return Boolean(
610
+ tags.key ||
611
+ tags.path ||
612
+ tags.locale ||
613
+ (Array.isArray(tags.lang) && tags.lang.length > 0) ||
614
+ (Array.isArray(tags.text) && tags.text.length > 0) ||
615
+ (Array.isArray(tags.block) && tags.block.length > 0)
616
+ );
617
+ }
618
+
619
+ function diagnoseMissingDescriptionLocales(descriptionField, context, doclet, tags) {
620
+ if (!descriptionField || !hasLocalizationIntent(tags)) {
621
+ return;
622
+ }
623
+
624
+ for (const locale of descriptionField.missingLocales) {
625
+ context.addDiagnostic({
626
+ code: "HIA_I18N_LOCALE_MISSING",
627
+ severity: "warning",
628
+ message: `Missing localized content for locale: ${locale}`,
629
+ plugin: "doc-i18n",
630
+ data: {
631
+ locale,
632
+ fieldPath: "description",
633
+ doclet: getDocletLabel(doclet)
634
+ }
635
+ });
636
+ }
637
+ }
638
+
639
+ function getCompatSource(field, locale) {
640
+ const block = findBlockForLocale(field.blocks, locale);
641
+
642
+ if (!block) {
643
+ return locale === field.defaultLocale ? "description" : "fallback";
644
+ }
645
+
646
+ if (block.source.startsWith("legacy")) {
647
+ return "inline";
648
+ }
649
+
650
+ return block.source;
651
+ }
652
+
653
+ function buildCompatLocalized(descriptionField, context) {
654
+ const localized = {};
655
+
656
+ if (!descriptionField) {
657
+ return localized;
658
+ }
659
+
660
+ for (const locale of normalizeLocales(context.config)) {
661
+ const block = findBlockForLocale(descriptionField.blocks, locale);
662
+ localized[locale] = {
663
+ locale,
664
+ text: descriptionField.localizedText[locale] || "",
665
+ block: block && block.block ? block.block : "",
666
+ source: getCompatSource(descriptionField, locale)
667
+ };
668
+ }
669
+
670
+ return localized;
671
+ }
672
+
673
+ function buildGenerationData(localized, fields, context) {
674
+ const locales = normalizeLocales(context.config);
675
+
676
+ return {
677
+ mode: context.config.i18n.mode,
678
+ perLocale: locales.reduce((result, locale) => {
679
+ result[locale] = localized[locale] || null;
680
+ return result;
681
+ }, {}),
682
+ runtimeSwitch: {
683
+ locales,
684
+ fallbackLocale: context.config.i18n.fallbackLocale,
685
+ content: localized,
686
+ fields
687
+ },
688
+ hiaIntegration: {
689
+ localized,
690
+ fields
691
+ }
692
+ };
693
+ }
694
+
695
+ module.exports = {
696
+ name: "doc-i18n",
697
+ order: 40,
698
+
699
+ setup(context) {
700
+ const loaded = loadLocalizationResources(context.config, context.diagnostics);
701
+ context.state.registries.localizationResources = loaded.resources;
702
+ context.state.registries.localizationEntries = loaded.entries;
703
+ },
704
+
705
+ defineTags(event) {
706
+ const dictionary = event && event.dictionary;
707
+
708
+ if (!dictionary || typeof dictionary.defineTag !== "function") {
709
+ return;
710
+ }
711
+
712
+ dictionary.defineTag("hiaLocale", {
713
+ canHaveValue: true,
714
+ onTagged(doclet, tag) {
715
+ rememberTag(doclet, "locale", tag.value || tag.text || "");
716
+ }
717
+ });
718
+
719
+ dictionary.defineTag("hiaKey", {
720
+ canHaveValue: true,
721
+ onTagged(doclet, tag) {
722
+ rememberTag(doclet, "key", tag.value || tag.text || "");
723
+ }
724
+ });
725
+
726
+ dictionary.defineTag("hiaPath", {
727
+ canHaveValue: true,
728
+ onTagged(doclet, tag) {
729
+ rememberTag(doclet, "path", tag.value || tag.text || "");
730
+ }
731
+ });
732
+
733
+ dictionary.defineTag("lang", {
734
+ canHaveValue: true,
735
+ onTagged(doclet, tag) {
736
+ appendTag(doclet, "lang", tag.value || tag.text || "");
737
+ }
738
+ });
739
+
740
+ dictionary.defineTag("hiaText", {
741
+ canHaveValue: true,
742
+ onTagged(doclet, tag) {
743
+ appendTag(doclet, "text", tag.value || tag.text || "");
744
+ }
745
+ });
746
+
747
+ dictionary.defineTag("hiaBlock", {
748
+ canHaveValue: true,
749
+ onTagged(doclet, tag) {
750
+ appendTag(doclet, "block", tag.value || tag.text || "");
751
+ }
752
+ });
753
+ },
754
+
755
+ newDoclet(event, context) {
756
+ if (!event || !event.doclet) {
757
+ return;
758
+ }
759
+
760
+ const doclet = event.doclet;
761
+ const metadata = context.markMicroPlugin(doclet, this.name);
762
+ const tags = doclet.hiaTags || {};
763
+ const key = buildLocalizationKey(doclet, tags);
764
+ const descriptionBlocks = buildDescriptionBlocks(doclet, tags, context);
765
+
766
+ addResourceBlocks(descriptionBlocks, key, context);
767
+
768
+ const fields = buildFields(doclet, descriptionBlocks, context);
769
+ const descriptionField = fields.description || null;
770
+ const localized = buildCompatLocalized(descriptionField, context);
771
+ const missingLocales = hasLocalizationIntent(tags) && descriptionField
772
+ ? descriptionField.missingLocales
773
+ : [];
774
+
775
+ diagnoseMissingDescriptionLocales(descriptionField, context, doclet, tags);
776
+
777
+ metadata.i18n = {
778
+ enabled: Boolean(context.config.i18n.enabled),
779
+ model: TEXT_I18N_MODEL,
780
+ modelVersion: TEXT_I18N_MODEL_VERSION,
781
+ defaultLocale: context.config.i18n.defaultLocale,
782
+ fallbackLocale: context.config.i18n.fallbackLocale,
783
+ locales: normalizeLocales(context.config),
784
+ mode: context.config.i18n.mode,
785
+ key: tags.key || "",
786
+ path: buildLocalizationPath(doclet, tags),
787
+ locale: tags.locale || "",
788
+ fields,
789
+ localized,
790
+ missingLocales,
791
+ resources: context.state.registries.localizationResources || [],
792
+ diagnostics: [],
793
+ generation: buildGenerationData(localized, fields, context)
794
+ };
795
+ }
796
+ };