@jjlmoya/utils-developer 1.27.0 → 1.29.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/package.json +1 -1
- package/src/entries.ts +4 -1
- package/src/tests/i18n_coverage.test.ts +5 -2
- package/src/tests/locale_completeness.test.ts +1 -1
- package/src/tests/qa-test-helpers.ts +32 -0
- package/src/tests/qa_bibliography_links.test.ts +43 -0
- package/src/tests/qa_claim_evidence.test.ts +69 -0
- package/src/tests/qa_logic_reference_coverage.test.ts +46 -0
- package/src/tests/qa_runtime_i18n.test.ts +115 -0
- package/src/tests/spanish_leakage.test.ts +5 -1
- package/src/tests/tool_validation.test.ts +1 -1
- package/src/tool/aspectRatio/bibliography.astro +2 -10
- package/src/tool/aspectRatio/bibliography.ts +7 -0
- package/src/tool/aspectRatio/i18n/de.ts +2 -14
- package/src/tool/aspectRatio/i18n/en.ts +2 -14
- package/src/tool/aspectRatio/i18n/es.ts +2 -14
- package/src/tool/aspectRatio/i18n/fr.ts +2 -14
- package/src/tool/aspectRatio/i18n/id.ts +2 -14
- package/src/tool/aspectRatio/i18n/it.ts +2 -14
- package/src/tool/aspectRatio/i18n/ja.ts +2 -14
- package/src/tool/aspectRatio/i18n/ko.ts +2 -14
- package/src/tool/aspectRatio/i18n/nl.ts +2 -14
- package/src/tool/aspectRatio/i18n/pl.ts +2 -14
- package/src/tool/aspectRatio/i18n/pt.ts +2 -14
- package/src/tool/aspectRatio/i18n/ru.ts +2 -14
- package/src/tool/aspectRatio/i18n/sv.ts +2 -14
- package/src/tool/aspectRatio/i18n/tr.ts +2 -14
- package/src/tool/aspectRatio/i18n/zh.ts +2 -14
- package/src/tool/calculadoraTiempoDatos/bibliography.astro +2 -10
- package/src/tool/calculadoraTiempoDatos/bibliography.ts +8 -0
- package/src/tool/calculadoraTiempoDatos/component.astro +6 -2
- package/src/tool/calculadoraTiempoDatos/i18n/de.ts +2 -6
- package/src/tool/calculadoraTiempoDatos/i18n/en.ts +2 -6
- package/src/tool/calculadoraTiempoDatos/i18n/es.ts +2 -6
- package/src/tool/calculadoraTiempoDatos/i18n/fr.ts +2 -6
- package/src/tool/calculadoraTiempoDatos/i18n/id.ts +2 -6
- package/src/tool/calculadoraTiempoDatos/i18n/it.ts +2 -6
- package/src/tool/calculadoraTiempoDatos/i18n/ja.ts +2 -6
- package/src/tool/calculadoraTiempoDatos/i18n/ko.ts +2 -6
- package/src/tool/calculadoraTiempoDatos/i18n/nl.ts +2 -6
- package/src/tool/calculadoraTiempoDatos/i18n/pl.ts +2 -6
- package/src/tool/calculadoraTiempoDatos/i18n/pt.ts +2 -6
- package/src/tool/calculadoraTiempoDatos/i18n/ru.ts +2 -6
- package/src/tool/calculadoraTiempoDatos/i18n/sv.ts +2 -6
- package/src/tool/calculadoraTiempoDatos/i18n/tr.ts +2 -6
- package/src/tool/calculadoraTiempoDatos/i18n/zh.ts +2 -6
- package/src/tool/colorConverter/bibliography.astro +2 -10
- package/src/tool/colorConverter/bibliography.ts +7 -0
- package/src/tool/colorConverter/i18n/de.ts +2 -5
- package/src/tool/colorConverter/i18n/en.ts +5 -8
- package/src/tool/colorConverter/i18n/es.ts +4 -7
- package/src/tool/colorConverter/i18n/fr.ts +2 -5
- package/src/tool/colorConverter/i18n/id.ts +2 -5
- package/src/tool/colorConverter/i18n/it.ts +2 -5
- package/src/tool/colorConverter/i18n/ja.ts +2 -5
- package/src/tool/colorConverter/i18n/ko.ts +2 -5
- package/src/tool/colorConverter/i18n/nl.ts +2 -5
- package/src/tool/colorConverter/i18n/pl.ts +2 -5
- package/src/tool/colorConverter/i18n/pt.ts +2 -5
- package/src/tool/colorConverter/i18n/ru.ts +2 -5
- package/src/tool/colorConverter/i18n/sv.ts +2 -5
- package/src/tool/colorConverter/i18n/tr.ts +2 -5
- package/src/tool/colorConverter/i18n/zh.ts +2 -5
- package/src/tool/conversorExcelCsvHtml/bibliography.astro +2 -10
- package/src/tool/conversorExcelCsvHtml/bibliography.ts +8 -0
- package/src/tool/conversorExcelCsvHtml/component.astro +4 -3
- package/src/tool/conversorExcelCsvHtml/i18n/de.ts +2 -6
- package/src/tool/conversorExcelCsvHtml/i18n/en.ts +2 -6
- package/src/tool/conversorExcelCsvHtml/i18n/es.ts +2 -6
- package/src/tool/conversorExcelCsvHtml/i18n/fr.ts +2 -6
- package/src/tool/conversorExcelCsvHtml/i18n/id.ts +2 -6
- package/src/tool/conversorExcelCsvHtml/i18n/it.ts +2 -6
- package/src/tool/conversorExcelCsvHtml/i18n/ja.ts +2 -6
- package/src/tool/conversorExcelCsvHtml/i18n/ko.ts +2 -6
- package/src/tool/conversorExcelCsvHtml/i18n/nl.ts +2 -6
- package/src/tool/conversorExcelCsvHtml/i18n/pl.ts +2 -6
- package/src/tool/conversorExcelCsvHtml/i18n/pt.ts +2 -6
- package/src/tool/conversorExcelCsvHtml/i18n/ru.ts +2 -6
- package/src/tool/conversorExcelCsvHtml/i18n/sv.ts +2 -6
- package/src/tool/conversorExcelCsvHtml/i18n/tr.ts +2 -6
- package/src/tool/conversorExcelCsvHtml/i18n/zh.ts +2 -6
- package/src/tool/cronGenerator/bibliography.astro +2 -10
- package/src/tool/cronGenerator/bibliography.ts +6 -0
- package/src/tool/cronGenerator/component.astro +5 -1
- package/src/tool/cronGenerator/i18n/de.ts +2 -10
- package/src/tool/cronGenerator/i18n/en.ts +2 -10
- package/src/tool/cronGenerator/i18n/es.ts +2 -10
- package/src/tool/cronGenerator/i18n/fr.ts +2 -10
- package/src/tool/cronGenerator/i18n/id.ts +2 -10
- package/src/tool/cronGenerator/i18n/it.ts +2 -10
- package/src/tool/cronGenerator/i18n/ja.ts +2 -10
- package/src/tool/cronGenerator/i18n/ko.ts +2 -10
- package/src/tool/cronGenerator/i18n/nl.ts +2 -10
- package/src/tool/cronGenerator/i18n/pl.ts +2 -10
- package/src/tool/cronGenerator/i18n/pt.ts +2 -10
- package/src/tool/cronGenerator/i18n/ru.ts +2 -10
- package/src/tool/cronGenerator/i18n/sv.ts +2 -10
- package/src/tool/cronGenerator/i18n/tr.ts +2 -10
- package/src/tool/cronGenerator/i18n/zh.ts +2 -10
- package/src/tool/cssBoxShadowGenerator/component.astro +2 -1
- package/src/tool/cssBoxShadowGenerator/logic.test.ts +28 -0
- package/src/tool/cssSpecificityCalculator/bibliography.astro +2 -10
- package/src/tool/cssSpecificityCalculator/bibliography.ts +6 -0
- package/src/tool/cssSpecificityCalculator/i18n/de.ts +2 -10
- package/src/tool/cssSpecificityCalculator/i18n/en.ts +2 -10
- package/src/tool/cssSpecificityCalculator/i18n/es.ts +2 -10
- package/src/tool/cssSpecificityCalculator/i18n/fr.ts +2 -10
- package/src/tool/cssSpecificityCalculator/i18n/id.ts +2 -10
- package/src/tool/cssSpecificityCalculator/i18n/it.ts +2 -10
- package/src/tool/cssSpecificityCalculator/i18n/ja.ts +2 -10
- package/src/tool/cssSpecificityCalculator/i18n/ko.ts +2 -10
- package/src/tool/cssSpecificityCalculator/i18n/nl.ts +2 -10
- package/src/tool/cssSpecificityCalculator/i18n/pl.ts +2 -10
- package/src/tool/cssSpecificityCalculator/i18n/pt.ts +2 -10
- package/src/tool/cssSpecificityCalculator/i18n/ru.ts +2 -10
- package/src/tool/cssSpecificityCalculator/i18n/sv.ts +2 -10
- package/src/tool/cssSpecificityCalculator/i18n/tr.ts +2 -10
- package/src/tool/cssSpecificityCalculator/i18n/zh.ts +2 -10
- package/src/tool/cssToInlineConverter/bibliography.astro +2 -10
- package/src/tool/cssToInlineConverter/bibliography.ts +7 -0
- package/src/tool/cssToInlineConverter/i18n/de.ts +2 -14
- package/src/tool/cssToInlineConverter/i18n/en.ts +4 -16
- package/src/tool/cssToInlineConverter/i18n/es.ts +5 -17
- package/src/tool/cssToInlineConverter/i18n/fr.ts +2 -14
- package/src/tool/cssToInlineConverter/i18n/id.ts +2 -14
- package/src/tool/cssToInlineConverter/i18n/it.ts +2 -14
- package/src/tool/cssToInlineConverter/i18n/ja.ts +2 -14
- package/src/tool/cssToInlineConverter/i18n/ko.ts +2 -14
- package/src/tool/cssToInlineConverter/i18n/nl.ts +2 -14
- package/src/tool/cssToInlineConverter/i18n/pl.ts +2 -14
- package/src/tool/cssToInlineConverter/i18n/pt.ts +2 -14
- package/src/tool/cssToInlineConverter/i18n/ru.ts +2 -14
- package/src/tool/cssToInlineConverter/i18n/sv.ts +2 -14
- package/src/tool/cssToInlineConverter/i18n/tr.ts +2 -14
- package/src/tool/cssToInlineConverter/i18n/zh.ts +2 -14
- package/src/tool/duplicateCssRemover/bibliography.astro +2 -10
- package/src/tool/duplicateCssRemover/bibliography.ts +7 -0
- package/src/tool/duplicateCssRemover/i18n/de.ts +2 -14
- package/src/tool/duplicateCssRemover/i18n/en.ts +4 -16
- package/src/tool/duplicateCssRemover/i18n/es.ts +4 -16
- package/src/tool/duplicateCssRemover/i18n/fr.ts +2 -14
- package/src/tool/duplicateCssRemover/i18n/id.ts +2 -14
- package/src/tool/duplicateCssRemover/i18n/it.ts +2 -14
- package/src/tool/duplicateCssRemover/i18n/ja.ts +2 -14
- package/src/tool/duplicateCssRemover/i18n/ko.ts +2 -14
- package/src/tool/duplicateCssRemover/i18n/nl.ts +2 -14
- package/src/tool/duplicateCssRemover/i18n/pl.ts +2 -14
- package/src/tool/duplicateCssRemover/i18n/pt.ts +2 -14
- package/src/tool/duplicateCssRemover/i18n/ru.ts +2 -14
- package/src/tool/duplicateCssRemover/i18n/sv.ts +2 -14
- package/src/tool/duplicateCssRemover/i18n/tr.ts +2 -14
- package/src/tool/duplicateCssRemover/i18n/zh.ts +2 -14
- package/src/tool/generadorSecurityTxt/bibliography.astro +2 -10
- package/src/tool/generadorSecurityTxt/bibliography.ts +7 -0
- package/src/tool/generadorSecurityTxt/component.astro +1 -2
- package/src/tool/generadorSecurityTxt/i18n/de.ts +2 -5
- package/src/tool/generadorSecurityTxt/i18n/en.ts +2 -5
- package/src/tool/generadorSecurityTxt/i18n/es.ts +2 -5
- package/src/tool/generadorSecurityTxt/i18n/fr.ts +2 -5
- package/src/tool/generadorSecurityTxt/i18n/id.ts +2 -5
- package/src/tool/generadorSecurityTxt/i18n/it.ts +2 -5
- package/src/tool/generadorSecurityTxt/i18n/ja.ts +2 -5
- package/src/tool/generadorSecurityTxt/i18n/ko.ts +2 -5
- package/src/tool/generadorSecurityTxt/i18n/nl.ts +2 -5
- package/src/tool/generadorSecurityTxt/i18n/pl.ts +2 -5
- package/src/tool/generadorSecurityTxt/i18n/pt.ts +2 -5
- package/src/tool/generadorSecurityTxt/i18n/ru.ts +2 -5
- package/src/tool/generadorSecurityTxt/i18n/sv.ts +2 -5
- package/src/tool/generadorSecurityTxt/i18n/tr.ts +2 -5
- package/src/tool/generadorSecurityTxt/i18n/zh.ts +2 -5
- package/src/tool/hashGenerator/bibliography.astro +2 -10
- package/src/tool/hashGenerator/bibliography.ts +7 -0
- package/src/tool/hashGenerator/i18n/de.ts +2 -5
- package/src/tool/hashGenerator/i18n/en.ts +2 -5
- package/src/tool/hashGenerator/i18n/es.ts +2 -5
- package/src/tool/hashGenerator/i18n/fr.ts +2 -5
- package/src/tool/hashGenerator/i18n/id.ts +2 -5
- package/src/tool/hashGenerator/i18n/it.ts +2 -5
- package/src/tool/hashGenerator/i18n/ja.ts +2 -5
- package/src/tool/hashGenerator/i18n/ko.ts +2 -5
- package/src/tool/hashGenerator/i18n/nl.ts +2 -5
- package/src/tool/hashGenerator/i18n/pl.ts +2 -5
- package/src/tool/hashGenerator/i18n/pt.ts +2 -5
- package/src/tool/hashGenerator/i18n/ru.ts +2 -5
- package/src/tool/hashGenerator/i18n/sv.ts +2 -5
- package/src/tool/hashGenerator/i18n/tr.ts +2 -5
- package/src/tool/hashGenerator/i18n/zh.ts +2 -5
- package/src/tool/inspectorCertificadosSsl/bibliography.astro +2 -10
- package/src/tool/inspectorCertificadosSsl/bibliography.ts +8 -0
- package/src/tool/inspectorCertificadosSsl/component.astro +4 -3
- package/src/tool/inspectorCertificadosSsl/i18n/de.ts +2 -6
- package/src/tool/inspectorCertificadosSsl/i18n/en.ts +2 -6
- package/src/tool/inspectorCertificadosSsl/i18n/es.ts +2 -6
- package/src/tool/inspectorCertificadosSsl/i18n/fr.ts +2 -6
- package/src/tool/inspectorCertificadosSsl/i18n/id.ts +2 -6
- package/src/tool/inspectorCertificadosSsl/i18n/it.ts +2 -6
- package/src/tool/inspectorCertificadosSsl/i18n/ja.ts +2 -6
- package/src/tool/inspectorCertificadosSsl/i18n/ko.ts +2 -6
- package/src/tool/inspectorCertificadosSsl/i18n/nl.ts +2 -6
- package/src/tool/inspectorCertificadosSsl/i18n/pl.ts +2 -6
- package/src/tool/inspectorCertificadosSsl/i18n/pt.ts +2 -6
- package/src/tool/inspectorCertificadosSsl/i18n/ru.ts +2 -6
- package/src/tool/inspectorCertificadosSsl/i18n/sv.ts +2 -6
- package/src/tool/inspectorCertificadosSsl/i18n/tr.ts +2 -6
- package/src/tool/inspectorCertificadosSsl/i18n/zh.ts +2 -6
- package/src/tool/jsonFormatter/bibliography.astro +2 -10
- package/src/tool/jsonFormatter/bibliography.ts +8 -0
- package/src/tool/jsonFormatter/i18n/de.ts +2 -18
- package/src/tool/jsonFormatter/i18n/en.ts +2 -18
- package/src/tool/jsonFormatter/i18n/es.ts +2 -18
- package/src/tool/jsonFormatter/i18n/fr.ts +2 -18
- package/src/tool/jsonFormatter/i18n/id.ts +2 -18
- package/src/tool/jsonFormatter/i18n/it.ts +2 -18
- package/src/tool/jsonFormatter/i18n/ja.ts +2 -18
- package/src/tool/jsonFormatter/i18n/ko.ts +2 -18
- package/src/tool/jsonFormatter/i18n/nl.ts +2 -18
- package/src/tool/jsonFormatter/i18n/pl.ts +2 -18
- package/src/tool/jsonFormatter/i18n/pt.ts +2 -18
- package/src/tool/jsonFormatter/i18n/ru.ts +2 -18
- package/src/tool/jsonFormatter/i18n/sv.ts +2 -18
- package/src/tool/jsonFormatter/i18n/tr.ts +2 -18
- package/src/tool/jsonFormatter/i18n/zh.ts +2 -18
- package/src/tool/jwtDecoder/component.astro +2 -1
- package/src/tool/jwtDecoder/logic.test.ts +32 -0
- package/src/tool/keycode/bibliography.astro +2 -10
- package/src/tool/keycode/bibliography.ts +7 -0
- package/src/tool/keycode/i18n/de.ts +2 -14
- package/src/tool/keycode/i18n/en.ts +2 -14
- package/src/tool/keycode/i18n/es.ts +2 -14
- package/src/tool/keycode/i18n/fr.ts +2 -14
- package/src/tool/keycode/i18n/id.ts +2 -14
- package/src/tool/keycode/i18n/it.ts +2 -14
- package/src/tool/keycode/i18n/ja.ts +2 -14
- package/src/tool/keycode/i18n/ko.ts +2 -14
- package/src/tool/keycode/i18n/nl.ts +2 -14
- package/src/tool/keycode/i18n/pl.ts +2 -14
- package/src/tool/keycode/i18n/pt.ts +2 -14
- package/src/tool/keycode/i18n/ru.ts +2 -14
- package/src/tool/keycode/i18n/sv.ts +2 -14
- package/src/tool/keycode/i18n/tr.ts +2 -14
- package/src/tool/keycode/i18n/zh.ts +2 -14
- package/src/tool/llmCostCalculator/bibliography.astro +2 -10
- package/src/tool/llmCostCalculator/bibliography.ts +8 -0
- package/src/tool/llmCostCalculator/i18n/de.ts +2 -18
- package/src/tool/llmCostCalculator/i18n/en.ts +2 -18
- package/src/tool/llmCostCalculator/i18n/es.ts +2 -18
- package/src/tool/llmCostCalculator/i18n/fr.ts +2 -18
- package/src/tool/llmCostCalculator/i18n/id.ts +2 -18
- package/src/tool/llmCostCalculator/i18n/it.ts +2 -18
- package/src/tool/llmCostCalculator/i18n/ja.ts +2 -18
- package/src/tool/llmCostCalculator/i18n/ko.ts +2 -18
- package/src/tool/llmCostCalculator/i18n/nl.ts +2 -18
- package/src/tool/llmCostCalculator/i18n/pl.ts +2 -18
- package/src/tool/llmCostCalculator/i18n/pt.ts +2 -18
- package/src/tool/llmCostCalculator/i18n/ru.ts +2 -18
- package/src/tool/llmCostCalculator/i18n/sv.ts +2 -18
- package/src/tool/llmCostCalculator/i18n/tr.ts +2 -18
- package/src/tool/llmCostCalculator/i18n/zh.ts +2 -18
- package/src/tool/mobileMockupGenerator/bibliography.astro +2 -10
- package/src/tool/mobileMockupGenerator/bibliography.ts +6 -0
- package/src/tool/mobileMockupGenerator/i18n/de.ts +2 -4
- package/src/tool/mobileMockupGenerator/i18n/en.ts +2 -4
- package/src/tool/mobileMockupGenerator/i18n/es.ts +2 -4
- package/src/tool/mobileMockupGenerator/i18n/fr.ts +2 -4
- package/src/tool/mobileMockupGenerator/i18n/id.ts +2 -4
- package/src/tool/mobileMockupGenerator/i18n/it.ts +2 -4
- package/src/tool/mobileMockupGenerator/i18n/ja.ts +2 -4
- package/src/tool/mobileMockupGenerator/i18n/ko.ts +2 -4
- package/src/tool/mobileMockupGenerator/i18n/nl.ts +2 -4
- package/src/tool/mobileMockupGenerator/i18n/pl.ts +2 -1
- package/src/tool/mobileMockupGenerator/i18n/pt.ts +2 -4
- package/src/tool/mobileMockupGenerator/i18n/ru.ts +2 -4
- package/src/tool/mobileMockupGenerator/i18n/sv.ts +2 -4
- package/src/tool/mobileMockupGenerator/i18n/tr.ts +2 -4
- package/src/tool/mobileMockupGenerator/i18n/zh.ts +2 -4
- package/src/tool/musicalTypography/bibliography.astro +2 -10
- package/src/tool/musicalTypography/bibliography.ts +7 -0
- package/src/tool/musicalTypography/i18n/de.ts +2 -14
- package/src/tool/musicalTypography/i18n/en.ts +3 -15
- package/src/tool/musicalTypography/i18n/es.ts +3 -15
- package/src/tool/musicalTypography/i18n/fr.ts +2 -14
- package/src/tool/musicalTypography/i18n/id.ts +2 -14
- package/src/tool/musicalTypography/i18n/it.ts +2 -14
- package/src/tool/musicalTypography/i18n/ja.ts +2 -14
- package/src/tool/musicalTypography/i18n/ko.ts +2 -14
- package/src/tool/musicalTypography/i18n/nl.ts +2 -14
- package/src/tool/musicalTypography/i18n/pl.ts +2 -14
- package/src/tool/musicalTypography/i18n/pt.ts +2 -5
- package/src/tool/musicalTypography/i18n/ru.ts +2 -5
- package/src/tool/musicalTypography/i18n/sv.ts +2 -1
- package/src/tool/musicalTypography/i18n/tr.ts +2 -1
- package/src/tool/musicalTypography/i18n/zh.ts +2 -1
- package/src/tool/placeholderGenerator/bibliography.astro +2 -10
- package/src/tool/placeholderGenerator/bibliography.ts +7 -0
- package/src/tool/placeholderGenerator/i18n/de.ts +2 -14
- package/src/tool/placeholderGenerator/i18n/en.ts +4 -16
- package/src/tool/placeholderGenerator/i18n/es.ts +4 -16
- package/src/tool/placeholderGenerator/i18n/fr.ts +2 -14
- package/src/tool/placeholderGenerator/i18n/id.ts +2 -14
- package/src/tool/placeholderGenerator/i18n/it.ts +2 -14
- package/src/tool/placeholderGenerator/i18n/ja.ts +2 -14
- package/src/tool/placeholderGenerator/i18n/ko.ts +2 -14
- package/src/tool/placeholderGenerator/i18n/nl.ts +2 -14
- package/src/tool/placeholderGenerator/i18n/pl.ts +2 -14
- package/src/tool/placeholderGenerator/i18n/pt.ts +2 -14
- package/src/tool/placeholderGenerator/i18n/ru.ts +2 -14
- package/src/tool/placeholderGenerator/i18n/sv.ts +2 -14
- package/src/tool/placeholderGenerator/i18n/tr.ts +2 -14
- package/src/tool/placeholderGenerator/i18n/zh.ts +2 -14
- package/src/tool/promoteThisWebsite/asset-bindings.ts +73 -0
- package/src/tool/promoteThisWebsite/bibliography.astro +14 -0
- package/src/tool/promoteThisWebsite/bibliography.ts +14 -0
- package/src/tool/promoteThisWebsite/component.astro +136 -0
- package/src/tool/promoteThisWebsite/control-views.ts +83 -0
- package/src/tool/promoteThisWebsite/controller.ts +232 -0
- package/src/tool/promoteThisWebsite/dom-views.ts +322 -0
- package/src/tool/promoteThisWebsite/entry.ts +15 -0
- package/src/tool/promoteThisWebsite/evaluator.ts +9 -0
- package/src/tool/promoteThisWebsite/i18n/en.ts +111 -0
- package/src/tool/promoteThisWebsite/index.ts +11 -0
- package/src/tool/promoteThisWebsite/jjlmoya-overlay.png +0 -0
- package/src/tool/promoteThisWebsite/logic.test.ts +29 -0
- package/src/tool/promoteThisWebsite/logic.ts +108 -0
- package/src/tool/promoteThisWebsite/pixel-cat.png +0 -0
- package/src/tool/promoteThisWebsite/promote-this-website.css +322 -0
- package/src/tool/promoteThisWebsite/seo.astro +15 -0
- package/src/tool/promoteThisWebsite/storage.ts +28 -0
- package/src/tool/promoteThisWebsite/title-view.ts +206 -0
- package/src/tool/promoteThisWebsite/ui.ts +59 -0
- package/src/tool/promptLibrary/bibliography.astro +2 -10
- package/src/tool/promptLibrary/bibliography.ts +6 -0
- package/src/tool/promptLibrary/i18n/de.ts +2 -4
- package/src/tool/promptLibrary/i18n/en.ts +2 -4
- package/src/tool/promptLibrary/i18n/es.ts +2 -4
- package/src/tool/promptLibrary/i18n/fr.ts +2 -4
- package/src/tool/promptLibrary/i18n/id.ts +2 -4
- package/src/tool/promptLibrary/i18n/it.ts +2 -4
- package/src/tool/promptLibrary/i18n/ja.ts +2 -4
- package/src/tool/promptLibrary/i18n/ko.ts +2 -4
- package/src/tool/promptLibrary/i18n/nl.ts +2 -4
- package/src/tool/promptLibrary/i18n/pl.ts +2 -1
- package/src/tool/promptLibrary/i18n/pt.ts +2 -4
- package/src/tool/promptLibrary/i18n/ru.ts +2 -4
- package/src/tool/promptLibrary/i18n/sv.ts +2 -4
- package/src/tool/promptLibrary/i18n/tr.ts +2 -4
- package/src/tool/promptLibrary/i18n/zh.ts +2 -4
- package/src/tool/readabilityCalculator/bibliography.astro +2 -10
- package/src/tool/readabilityCalculator/bibliography.ts +7 -0
- package/src/tool/readabilityCalculator/i18n/de.ts +2 -5
- package/src/tool/readabilityCalculator/i18n/en.ts +2 -5
- package/src/tool/readabilityCalculator/i18n/es.ts +2 -5
- package/src/tool/readabilityCalculator/i18n/fr.ts +2 -5
- package/src/tool/readabilityCalculator/i18n/id.ts +2 -5
- package/src/tool/readabilityCalculator/i18n/it.ts +2 -5
- package/src/tool/readabilityCalculator/i18n/ja.ts +2 -5
- package/src/tool/readabilityCalculator/i18n/ko.ts +2 -5
- package/src/tool/readabilityCalculator/i18n/nl.ts +2 -5
- package/src/tool/readabilityCalculator/i18n/pl.ts +2 -1
- package/src/tool/readabilityCalculator/i18n/pt.ts +2 -5
- package/src/tool/readabilityCalculator/i18n/ru.ts +2 -5
- package/src/tool/readabilityCalculator/i18n/sv.ts +2 -5
- package/src/tool/readabilityCalculator/i18n/tr.ts +2 -5
- package/src/tool/readabilityCalculator/i18n/zh.ts +2 -5
- package/src/tool/serpPixelSimulator/controller.ts +1 -0
- package/src/tool/serpPixelSimulator/i18n/en.ts +2 -2
- package/src/tool/serpPixelSimulator/i18n/es.ts +2 -2
- package/src/tool/serpPixelSimulator/logic.test.ts +25 -0
- package/src/tool/svgSanitizer/bibliography.astro +2 -10
- package/src/tool/svgSanitizer/bibliography.ts +7 -0
- package/src/tool/svgSanitizer/i18n/de.ts +2 -5
- package/src/tool/svgSanitizer/i18n/en.ts +2 -5
- package/src/tool/svgSanitizer/i18n/es.ts +2 -5
- package/src/tool/svgSanitizer/i18n/fr.ts +2 -5
- package/src/tool/svgSanitizer/i18n/id.ts +2 -5
- package/src/tool/svgSanitizer/i18n/it.ts +2 -5
- package/src/tool/svgSanitizer/i18n/ja.ts +2 -5
- package/src/tool/svgSanitizer/i18n/ko.ts +2 -5
- package/src/tool/svgSanitizer/i18n/nl.ts +2 -5
- package/src/tool/svgSanitizer/i18n/pl.ts +2 -5
- package/src/tool/svgSanitizer/i18n/pt.ts +2 -1
- package/src/tool/svgSanitizer/i18n/ru.ts +2 -5
- package/src/tool/svgSanitizer/i18n/sv.ts +2 -5
- package/src/tool/svgSanitizer/i18n/tr.ts +2 -5
- package/src/tool/svgSanitizer/i18n/zh.ts +2 -5
- package/src/tool/svgToCss/bibliography.astro +2 -10
- package/src/tool/svgToCss/bibliography.ts +8 -0
- package/src/tool/svgToCss/i18n/de.ts +2 -18
- package/src/tool/svgToCss/i18n/en.ts +2 -18
- package/src/tool/svgToCss/i18n/es.ts +2 -18
- package/src/tool/svgToCss/i18n/fr.ts +2 -18
- package/src/tool/svgToCss/i18n/id.ts +2 -18
- package/src/tool/svgToCss/i18n/it.ts +2 -18
- package/src/tool/svgToCss/i18n/ja.ts +2 -18
- package/src/tool/svgToCss/i18n/ko.ts +2 -18
- package/src/tool/svgToCss/i18n/nl.ts +2 -18
- package/src/tool/svgToCss/i18n/pl.ts +2 -18
- package/src/tool/svgToCss/i18n/pt.ts +2 -18
- package/src/tool/svgToCss/i18n/ru.ts +2 -18
- package/src/tool/svgToCss/i18n/sv.ts +2 -18
- package/src/tool/svgToCss/i18n/tr.ts +2 -18
- package/src/tool/svgToCss/i18n/zh.ts +2 -18
- package/src/tool/urlCleaner/bibliography.astro +2 -10
- package/src/tool/urlCleaner/bibliography.ts +7 -0
- package/src/tool/urlCleaner/i18n/de.ts +2 -5
- package/src/tool/urlCleaner/i18n/en.ts +2 -5
- package/src/tool/urlCleaner/i18n/es.ts +2 -5
- package/src/tool/urlCleaner/i18n/fr.ts +2 -5
- package/src/tool/urlCleaner/i18n/id.ts +2 -5
- package/src/tool/urlCleaner/i18n/it.ts +2 -5
- package/src/tool/urlCleaner/i18n/ja.ts +2 -5
- package/src/tool/urlCleaner/i18n/ko.ts +2 -5
- package/src/tool/urlCleaner/i18n/nl.ts +2 -5
- package/src/tool/urlCleaner/i18n/pl.ts +2 -1
- package/src/tool/urlCleaner/i18n/pt.ts +2 -5
- package/src/tool/urlCleaner/i18n/ru.ts +2 -5
- package/src/tool/urlCleaner/i18n/sv.ts +2 -5
- package/src/tool/urlCleaner/i18n/tr.ts +2 -5
- package/src/tool/urlCleaner/i18n/zh.ts +2 -5
- package/src/tool/urlEncoderDecoder/bibliography.astro +2 -10
- package/src/tool/urlEncoderDecoder/bibliography.ts +7 -0
- package/src/tool/urlEncoderDecoder/i18n/de.ts +2 -14
- package/src/tool/urlEncoderDecoder/i18n/en.ts +3 -15
- package/src/tool/urlEncoderDecoder/i18n/es.ts +3 -15
- package/src/tool/urlEncoderDecoder/i18n/fr.ts +2 -14
- package/src/tool/urlEncoderDecoder/i18n/id.ts +2 -14
- package/src/tool/urlEncoderDecoder/i18n/it.ts +2 -14
- package/src/tool/urlEncoderDecoder/i18n/ja.ts +2 -14
- package/src/tool/urlEncoderDecoder/i18n/ko.ts +2 -14
- package/src/tool/urlEncoderDecoder/i18n/nl.ts +2 -14
- package/src/tool/urlEncoderDecoder/i18n/pl.ts +2 -14
- package/src/tool/urlEncoderDecoder/i18n/pt.ts +2 -14
- package/src/tool/urlEncoderDecoder/i18n/ru.ts +2 -14
- package/src/tool/urlEncoderDecoder/i18n/sv.ts +2 -14
- package/src/tool/urlEncoderDecoder/i18n/tr.ts +2 -14
- package/src/tool/urlEncoderDecoder/i18n/zh.ts +2 -14
- package/src/tool/utmGenerator/bibliography.astro +2 -10
- package/src/tool/utmGenerator/bibliography.ts +6 -0
- package/src/tool/utmGenerator/i18n/de.ts +2 -4
- package/src/tool/utmGenerator/i18n/en.ts +2 -4
- package/src/tool/utmGenerator/i18n/es.ts +2 -4
- package/src/tool/utmGenerator/i18n/fr.ts +2 -4
- package/src/tool/utmGenerator/i18n/id.ts +2 -4
- package/src/tool/utmGenerator/i18n/it.ts +2 -4
- package/src/tool/utmGenerator/i18n/ja.ts +2 -4
- package/src/tool/utmGenerator/i18n/ko.ts +2 -4
- package/src/tool/utmGenerator/i18n/nl.ts +2 -4
- package/src/tool/utmGenerator/i18n/pl.ts +2 -4
- package/src/tool/utmGenerator/i18n/pt.ts +2 -4
- package/src/tool/utmGenerator/i18n/ru.ts +2 -4
- package/src/tool/utmGenerator/i18n/sv.ts +2 -4
- package/src/tool/utmGenerator/i18n/tr.ts +2 -4
- package/src/tool/utmGenerator/i18n/zh.ts +2 -4
- package/src/tool/visualCssGridFlexboxGenerator/component.astro +1 -0
- package/src/tool/visualCssGridFlexboxGenerator/logic.test.ts +29 -0
- package/src/tool/visualCssGridFlexboxGenerator/workspace.ts +13 -1
- package/src/tools.ts +2 -1
package/package.json
CHANGED
package/src/entries.ts
CHANGED
|
@@ -54,6 +54,8 @@ export { visualCssGridFlexboxGenerator } from './tool/visualCssGridFlexboxGenera
|
|
|
54
54
|
export type { VisualCssGridFlexboxGeneratorLocaleContent } from './tool/visualCssGridFlexboxGenerator/entry';
|
|
55
55
|
export { cssBoxShadowGenerator } from './tool/cssBoxShadowGenerator/entry';
|
|
56
56
|
export type { CssBoxShadowGeneratorLocaleContent } from './tool/cssBoxShadowGenerator/entry';
|
|
57
|
+
export { promoteThisWebsite } from './tool/promoteThisWebsite/entry';
|
|
58
|
+
export type { PromoteThisWebsiteLocaleContent } from './tool/promoteThisWebsite/entry';
|
|
57
59
|
export { developerCategory } from './category';
|
|
58
60
|
import { aspectRatio } from './tool/aspectRatio/entry';
|
|
59
61
|
import { calculadoraTiempoDatos } from './tool/calculadoraTiempoDatos/entry';
|
|
@@ -83,4 +85,5 @@ import { serpPixelSimulator } from './tool/serpPixelSimulator/entry';
|
|
|
83
85
|
import { jwtDecoder } from './tool/jwtDecoder/entry';
|
|
84
86
|
import { visualCssGridFlexboxGenerator } from './tool/visualCssGridFlexboxGenerator/entry';
|
|
85
87
|
import { cssBoxShadowGenerator } from './tool/cssBoxShadowGenerator/entry';
|
|
86
|
-
|
|
88
|
+
import { promoteThisWebsite } from './tool/promoteThisWebsite/entry';
|
|
89
|
+
export const ALL_ENTRIES = [aspectRatio, calculadoraTiempoDatos, colorConverter, conversorExcelCsvHtml, cronGenerator, cssSpecificityCalculator, cssToInlineConverter, duplicateCssRemover, generadorSecurityTxt, hashGenerator, inspectorCertificadosSsl, jsonFormatter, keycode, llmCostCalculator, mobileMockupGenerator, musicalTypography, placeholderGenerator, promptLibrary, readabilityCalculator, svgSanitizer, svgToCss, urlCleaner, urlEncoderDecoder, utmGenerator, serpPixelSimulator, jwtDecoder, visualCssGridFlexboxGenerator, cssBoxShadowGenerator, promoteThisWebsite];
|
|
@@ -4,6 +4,7 @@ import { ALL_TOOLS } from '../tools';
|
|
|
4
4
|
const EXPECTED_LOCALES = [
|
|
5
5
|
'de', 'en', 'es', 'fr', 'id', 'it', 'ja', 'ko', 'nl', 'pl', 'pt', 'ru', 'sv', 'tr', 'zh'
|
|
6
6
|
];
|
|
7
|
+
const ENGLISH_FIRST_TOOLS = new Set(['promote-this-website']);
|
|
7
8
|
|
|
8
9
|
describe('I18n Coverage Validation', () => {
|
|
9
10
|
it('all tools should be registered', () => {
|
|
@@ -14,7 +15,8 @@ describe('I18n Coverage Validation', () => {
|
|
|
14
15
|
describe(`Tool: ${entry.id}`, () => {
|
|
15
16
|
it('should have all 15 required locales', () => {
|
|
16
17
|
const registeredLocales = Object.keys(entry.i18n);
|
|
17
|
-
|
|
18
|
+
const requiredLocales = ENGLISH_FIRST_TOOLS.has(entry.id) ? ['en'] : EXPECTED_LOCALES;
|
|
19
|
+
requiredLocales.forEach((locale) => {
|
|
18
20
|
expect(
|
|
19
21
|
registeredLocales,
|
|
20
22
|
`Tool "${entry.id}" is missing locale "${locale}"`,
|
|
@@ -23,7 +25,8 @@ describe('I18n Coverage Validation', () => {
|
|
|
23
25
|
});
|
|
24
26
|
|
|
25
27
|
it('all locale loaders should be functions', () => {
|
|
26
|
-
|
|
28
|
+
const requiredLocales = ENGLISH_FIRST_TOOLS.has(entry.id) ? ['en'] : EXPECTED_LOCALES;
|
|
29
|
+
requiredLocales.forEach((locale) => {
|
|
27
30
|
const loader = entry.i18n[locale as keyof typeof entry.i18n];
|
|
28
31
|
expect(
|
|
29
32
|
typeof loader,
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { readdirSync, readFileSync, statSync } from 'node:fs';
|
|
2
|
+
import { join, relative } from 'node:path';
|
|
3
|
+
|
|
4
|
+
export const repositoryRoot = process.cwd();
|
|
5
|
+
export const toolRoot = join(repositoryRoot, 'src', 'tool');
|
|
6
|
+
|
|
7
|
+
export function listToolDirectories(): string[] {
|
|
8
|
+
return readdirSync(toolRoot)
|
|
9
|
+
.map((name) => join(toolRoot, name))
|
|
10
|
+
.filter((path) => statSync(path).isDirectory());
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export function findFiles(directory: string, extensions: string[]): string[] {
|
|
14
|
+
const files: string[] = [];
|
|
15
|
+
|
|
16
|
+
for (const entry of readdirSync(directory, { withFileTypes: true })) {
|
|
17
|
+
const path = join(directory, entry.name);
|
|
18
|
+
if (entry.isDirectory()) files.push(...findFiles(path, extensions));
|
|
19
|
+
else if (extensions.some((extension) => entry.name.endsWith(extension))) files.push(path);
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
return files;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export function read(path: string): string {
|
|
26
|
+
return readFileSync(path, 'utf8');
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export function displayPath(path: string): string {
|
|
30
|
+
return relative(repositoryRoot, path).replace(/\\/g, '/');
|
|
31
|
+
}
|
|
32
|
+
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { describe, expect, it } from 'vitest';
|
|
2
|
+
import { ALL_TOOLS } from '../tools';
|
|
3
|
+
import type { ToolLocaleContent } from '../types';
|
|
4
|
+
|
|
5
|
+
interface LinkFailure {
|
|
6
|
+
tool: string;
|
|
7
|
+
message: string;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
function inspectEntry(tool: string, entry: { url: string }, seen: Set<string>): LinkFailure[] {
|
|
11
|
+
let url: URL;
|
|
12
|
+
try {
|
|
13
|
+
url = new URL(entry.url);
|
|
14
|
+
} catch {
|
|
15
|
+
return [{ tool, message: `invalid URL: ${entry.url}` }];
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
const failures: LinkFailure[] = [];
|
|
19
|
+
if (url.protocol !== 'https:') failures.push({ tool, message: `non-HTTPS URL: ${entry.url}` });
|
|
20
|
+
if (url.pathname === '/' && !url.search && !url.hash) failures.push({ tool, message: `generic homepage, cite the exact document: ${entry.url}` });
|
|
21
|
+
if (seen.has(url.href)) failures.push({ tool, message: `duplicate source URL: ${entry.url}` });
|
|
22
|
+
seen.add(url.href);
|
|
23
|
+
return failures;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
async function inspectTool(tool: typeof ALL_TOOLS[number]): Promise<LinkFailure[]> {
|
|
27
|
+
const loader = tool.entry.i18n.en;
|
|
28
|
+
if (!loader) return [{ tool: tool.entry.id, message: 'English locale loader is missing' }];
|
|
29
|
+
const content = (await loader()) as ToolLocaleContent;
|
|
30
|
+
const seen = new Set<string>();
|
|
31
|
+
return (content.bibliography ?? []).flatMap((entry) => inspectEntry(tool.entry.id, entry, seen));
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
describe('QA: bibliography links are specific and usable', () => {
|
|
35
|
+
it('uses unique HTTPS links to exact source pages instead of generic homepages', async () => {
|
|
36
|
+
const failures: LinkFailure[] = [];
|
|
37
|
+
|
|
38
|
+
for (const tool of ALL_TOOLS) failures.push(...await inspectTool(tool));
|
|
39
|
+
|
|
40
|
+
const messages = failures.map(({ tool, message }) => `${tool}: ${message}`);
|
|
41
|
+
expect(messages, `Bibliography hygiene failures:\n${messages.join('\n')}`).toEqual([]);
|
|
42
|
+
});
|
|
43
|
+
});
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import { describe, expect, it } from 'vitest';
|
|
2
|
+
import { existsSync } from 'node:fs';
|
|
3
|
+
import { join } from 'node:path';
|
|
4
|
+
import { displayPath, listToolDirectories, read } from './qa-test-helpers';
|
|
5
|
+
|
|
6
|
+
const evidenceClaims = [
|
|
7
|
+
/\bofficial algorithm\b/i,
|
|
8
|
+
/\balgoritmo oficial\b/i,
|
|
9
|
+
/\b(?:records|data|rates|tables) updated(?:\s+(?:to|through)\s+20\d{2})?\b/i,
|
|
10
|
+
/\b(?:registros|datos|tasas|tablas) actualizad[oa]s?(?:\s+(?:a|hasta)\s+20\d{2})?\b/i,
|
|
11
|
+
/\b(?:validated|verified) (?:method|algorithm|calculation)\b/i,
|
|
12
|
+
/\b(?:método|algoritmo|cálculo) (?:validado|verificado)\b/i,
|
|
13
|
+
/\b(?:guarantees|ensures)\b/i,
|
|
14
|
+
/\bgarantiza\b/i,
|
|
15
|
+
/\bofficial (?:data|rate|calculation)\b/i,
|
|
16
|
+
/\b(?:datos|tasa|cálculo) oficial(?:es)?\b/i,
|
|
17
|
+
];
|
|
18
|
+
|
|
19
|
+
const requiredEvidenceFields = [
|
|
20
|
+
'reviewedAt',
|
|
21
|
+
'methodology',
|
|
22
|
+
'sources',
|
|
23
|
+
'referenceCases',
|
|
24
|
+
'limitations',
|
|
25
|
+
];
|
|
26
|
+
|
|
27
|
+
describe('QA: strong factual claims are traceable', () => {
|
|
28
|
+
it('requires machine-readable validation evidence beside tools making strong claims', () => {
|
|
29
|
+
const failures: string[] = [];
|
|
30
|
+
|
|
31
|
+
for (const directory of listToolDirectories()) {
|
|
32
|
+
const localePaths = ['en', 'es']
|
|
33
|
+
.map((locale) => join(directory, 'i18n', `${locale}.ts`))
|
|
34
|
+
.filter(existsSync);
|
|
35
|
+
const claims = localePaths.flatMap((path) => {
|
|
36
|
+
const source = read(path);
|
|
37
|
+
return evidenceClaims
|
|
38
|
+
.filter((pattern) => pattern.test(source))
|
|
39
|
+
.map((pattern) => `${displayPath(path)} matches ${pattern.source}`);
|
|
40
|
+
});
|
|
41
|
+
if (claims.length === 0) continue;
|
|
42
|
+
|
|
43
|
+
const evidencePath = join(directory, 'validation.ts');
|
|
44
|
+
if (!existsSync(evidencePath)) {
|
|
45
|
+
failures.push(`${displayPath(evidencePath)} missing; claims: ${claims.join(' | ')}`);
|
|
46
|
+
continue;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
const evidence = read(evidencePath);
|
|
50
|
+
const missingFields = requiredEvidenceFields.filter(
|
|
51
|
+
(field) => !new RegExp(`\\b${field}\\s*:`).test(evidence),
|
|
52
|
+
);
|
|
53
|
+
if (missingFields.length > 0) {
|
|
54
|
+
failures.push(`${displayPath(evidencePath)} missing fields: ${missingFields.join(', ')}`);
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
expect(
|
|
59
|
+
failures,
|
|
60
|
+
[
|
|
61
|
+
'Claims such as official, validated, guaranteed or updated need inspectable evidence.',
|
|
62
|
+
'Add validation.ts with reviewedAt, methodology, sources, referenceCases and limitations,',
|
|
63
|
+
'or weaken/remove the unsupported claim.',
|
|
64
|
+
...failures,
|
|
65
|
+
].join('\n'),
|
|
66
|
+
).toEqual([]);
|
|
67
|
+
});
|
|
68
|
+
});
|
|
69
|
+
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import { describe, expect, it } from 'vitest';
|
|
2
|
+
import { basename, join } from 'node:path';
|
|
3
|
+
import { existsSync } from 'node:fs';
|
|
4
|
+
import {
|
|
5
|
+
displayPath,
|
|
6
|
+
findFiles,
|
|
7
|
+
listToolDirectories,
|
|
8
|
+
read,
|
|
9
|
+
repositoryRoot,
|
|
10
|
+
} from './qa-test-helpers';
|
|
11
|
+
|
|
12
|
+
function hasDedicatedLogicTest(toolDirectory: string): boolean {
|
|
13
|
+
const localCandidates = [
|
|
14
|
+
join(toolDirectory, 'logic.test.ts'),
|
|
15
|
+
join(toolDirectory, 'logic.spec.ts'),
|
|
16
|
+
join(toolDirectory, '__tests__', 'logic.test.ts'),
|
|
17
|
+
join(toolDirectory, '__tests__', 'logic.spec.ts'),
|
|
18
|
+
];
|
|
19
|
+
if (localCandidates.some(existsSync)) return true;
|
|
20
|
+
|
|
21
|
+
const toolName = basename(toolDirectory);
|
|
22
|
+
const centralTests = findFiles(join(repositoryRoot, 'src', 'tests'), ['.test.ts', '.spec.ts']);
|
|
23
|
+
return centralTests.some((testPath) => {
|
|
24
|
+
const source = read(testPath).replace(/\\/g, '/');
|
|
25
|
+
return source.includes(`/tool/${toolName}/logic`) || source.includes(`../tool/${toolName}/logic`);
|
|
26
|
+
});
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
describe('QA: calculation logic has reference tests', () => {
|
|
30
|
+
it('gives every public calculator logic module its own behavioral test suite', () => {
|
|
31
|
+
const failures = listToolDirectories()
|
|
32
|
+
.filter((directory) => existsSync(join(directory, 'logic.ts')))
|
|
33
|
+
.filter((directory) => !hasDedicatedLogicTest(directory))
|
|
34
|
+
.map((directory) => `${displayPath(join(directory, 'logic.ts'))} -> no test imports this module`);
|
|
35
|
+
|
|
36
|
+
expect(
|
|
37
|
+
failures,
|
|
38
|
+
[
|
|
39
|
+
'Add behavioral tests through each logic module public API.',
|
|
40
|
+
'At minimum cover a documented reference case, boundaries, invalid input and invariants.',
|
|
41
|
+
...failures,
|
|
42
|
+
].join('\n'),
|
|
43
|
+
).toEqual([]);
|
|
44
|
+
});
|
|
45
|
+
});
|
|
46
|
+
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
import { describe, expect, it } from 'vitest';
|
|
2
|
+
import { basename, join } from 'node:path';
|
|
3
|
+
import { existsSync } from 'node:fs';
|
|
4
|
+
import {
|
|
5
|
+
displayPath,
|
|
6
|
+
findFiles,
|
|
7
|
+
listToolDirectories,
|
|
8
|
+
read,
|
|
9
|
+
repositoryRoot,
|
|
10
|
+
} from './qa-test-helpers';
|
|
11
|
+
|
|
12
|
+
interface VisibleLiteral {
|
|
13
|
+
line: number;
|
|
14
|
+
value: string;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
const domTextAssignment = /\.(?:innerText|textContent|innerHTML)\s*=/;
|
|
18
|
+
const quotedLiteral = /(['"`])((?:\\.|(?!\1).)*)\1/g;
|
|
19
|
+
|
|
20
|
+
function visibleWords(value: string): string {
|
|
21
|
+
return value
|
|
22
|
+
.replace(/\$\{[^}]*\}/g, ' ')
|
|
23
|
+
.replace(/<[^>]+>/g, ' ')
|
|
24
|
+
.replace(/&[a-z]+;/gi, ' ')
|
|
25
|
+
.replace(/[\d\p{P}\p{S}_]+/gu, ' ')
|
|
26
|
+
.replace(/\s+/g, ' ')
|
|
27
|
+
.trim();
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
const technicalLiteralPatterns = [
|
|
31
|
+
/^(?:\.|#|\[)/,
|
|
32
|
+
/^data-[a-z0-9-]+$/i,
|
|
33
|
+
/^(?:cc|ss)-copied$/i,
|
|
34
|
+
/^invalid-segments$/,
|
|
35
|
+
/^\(space\)$/,
|
|
36
|
+
/^(?:SHA-1|SHA-256|SHA-512|en-US)$/i,
|
|
37
|
+
/^(?:h|px|años)$/i,
|
|
38
|
+
/^\d+\s+[A-Z]$/,
|
|
39
|
+
/^(?:if \(|\{ key:)/,
|
|
40
|
+
];
|
|
41
|
+
|
|
42
|
+
function isTechnicalLiteral(value: string): boolean {
|
|
43
|
+
const trimmed = value.trim();
|
|
44
|
+
return value.includes('${t.')
|
|
45
|
+
|| value.includes('${ui.')
|
|
46
|
+
|| value.includes('${localized.')
|
|
47
|
+
|| technicalLiteralPatterns.some((pattern) => pattern.test(value) || pattern.test(trimmed))
|
|
48
|
+
|| (value.includes('${') && /(?:px|\bh\b|años)/i.test(value));
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
function hardcodedVisibleLiterals(source: string): VisibleLiteral[] {
|
|
52
|
+
const failures: VisibleLiteral[] = [];
|
|
53
|
+
|
|
54
|
+
source.split(/\r?\n/).forEach((line, index) => {
|
|
55
|
+
if (!domTextAssignment.test(line)) return;
|
|
56
|
+
|
|
57
|
+
const assignment = line.slice(line.search(domTextAssignment));
|
|
58
|
+
for (const match of assignment.matchAll(quotedLiteral)) {
|
|
59
|
+
if (isTechnicalLiteral(match[2])) continue;
|
|
60
|
+
const words = visibleWords(match[2]);
|
|
61
|
+
if (words && /\p{L}/u.test(words)) {
|
|
62
|
+
failures.push({ line: index + 1, value: match[2] });
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
return failures;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
function runtimeSources(toolDirectory: string): string {
|
|
71
|
+
return findFiles(toolDirectory, ['.astro', '.ts', '.js'])
|
|
72
|
+
.filter((path) => !path.includes(`${join(toolDirectory, 'i18n')}`))
|
|
73
|
+
.filter((path) => basename(path) !== 'ui.ts')
|
|
74
|
+
.map(read)
|
|
75
|
+
.join('\n');
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
describe('QA: runtime copy is localized', () => {
|
|
79
|
+
const componentFiles = findFiles(join(repositoryRoot, 'src', 'tool'), ['.astro']);
|
|
80
|
+
|
|
81
|
+
it('does not write user-facing string literals directly into the DOM', () => {
|
|
82
|
+
const failures = componentFiles.flatMap((path) =>
|
|
83
|
+
hardcodedVisibleLiterals(read(path)).map(
|
|
84
|
+
({ line, value }) => `${displayPath(path)}:${line} -> ${JSON.stringify(value)}`,
|
|
85
|
+
),
|
|
86
|
+
);
|
|
87
|
+
|
|
88
|
+
expect(
|
|
89
|
+
failures,
|
|
90
|
+
`Move visible browser copy to the tool UI locale contract:\n${failures.join('\n')}`,
|
|
91
|
+
).toEqual([]);
|
|
92
|
+
});
|
|
93
|
+
|
|
94
|
+
it('uses every string declared by each UI locale contract', () => {
|
|
95
|
+
const failures: string[] = [];
|
|
96
|
+
|
|
97
|
+
for (const directory of listToolDirectories()) {
|
|
98
|
+
const uiPath = join(directory, 'ui.ts');
|
|
99
|
+
if (!existsSync(uiPath)) continue;
|
|
100
|
+
|
|
101
|
+
const keys = Array.from(read(uiPath).matchAll(/^\s*(\w+)\??:\s*string\s*;/gm), (match) => match[1]);
|
|
102
|
+
const runtime = runtimeSources(directory);
|
|
103
|
+
const unused = keys.filter((key) => !new RegExp(`\\b${key}\\b`).test(runtime));
|
|
104
|
+
|
|
105
|
+
if (unused.length > 0) {
|
|
106
|
+
failures.push(`${displayPath(uiPath)} -> unused: ${unused.join(', ')}`);
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
expect(
|
|
111
|
+
failures,
|
|
112
|
+
`Unused locale keys are dead copy or may mean the browser bypasses translations:\n${failures.join('\n')}`,
|
|
113
|
+
).toEqual([]);
|
|
114
|
+
});
|
|
115
|
+
});
|
|
@@ -67,12 +67,16 @@ function normalize(value: string): string {
|
|
|
67
67
|
}
|
|
68
68
|
|
|
69
69
|
function isTechnicalInvariant(text: string): boolean {
|
|
70
|
+
const ledUnitMatches = text.match(/\b\d+(?:-\d+)?\s*(?:w|lm)\b/g) ?? [];
|
|
70
71
|
return [
|
|
71
72
|
'data:image/svg+xml;base64',
|
|
72
73
|
'background-image: url',
|
|
73
74
|
'.layout-playground {',
|
|
74
75
|
'const samplerate =',
|
|
75
|
-
].some((pattern) => text.includes(pattern)) ||
|
|
76
|
+
].some((pattern) => text.includes(pattern)) ||
|
|
77
|
+
(text.includes('presets') && text.includes('hz')) ||
|
|
78
|
+
(text.includes('t_rectal') && text.includes('exp(-k * t)')) ||
|
|
79
|
+
(text.includes('led') && ledUnitMatches.length >= 3);
|
|
76
80
|
}
|
|
77
81
|
|
|
78
82
|
function collectString(value: string, output: string[]): void {
|
|
@@ -5,7 +5,7 @@ import { developerCategory } from '../data';
|
|
|
5
5
|
describe('Tool Validation Suite', () => {
|
|
6
6
|
describe('Library Registration', () => {
|
|
7
7
|
it('should have 28 tools in ALL_TOOLS', () => {
|
|
8
|
-
expect(ALL_TOOLS.length).toBe(
|
|
8
|
+
expect(ALL_TOOLS.length).toBe(29);
|
|
9
9
|
});
|
|
10
10
|
|
|
11
11
|
it('developerCategory should be defined', () => {
|
|
@@ -1,14 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
import { Bibliography as SharedBibliography } from '@jjlmoya/utils-shared';
|
|
3
|
-
import {
|
|
4
|
-
import type { KnownLocale } from '../../types';
|
|
5
|
-
|
|
6
|
-
interface Props {
|
|
7
|
-
locale?: KnownLocale;
|
|
8
|
-
}
|
|
9
|
-
|
|
10
|
-
const { locale = 'es' } = Astro.props;
|
|
11
|
-
const content = await aspectRatio.i18n[locale]?.();
|
|
3
|
+
import { bibliography } from './bibliography';
|
|
12
4
|
---
|
|
13
5
|
|
|
14
|
-
|
|
6
|
+
<SharedBibliography links={bibliography} />
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { BibliographyEntry } from '../../types';
|
|
2
|
+
|
|
3
|
+
export const bibliography: BibliographyEntry[] = [
|
|
4
|
+
{ name: 'MDN Web Docs: aspect-ratio (CSS)', url: 'https://developer.mozilla.org/en-US/docs/Web/CSS/aspect-ratio' },
|
|
5
|
+
{ name: 'Wikipedia: Aspect ratio', url: 'https://en.wikipedia.org/wiki/Aspect_ratio' },
|
|
6
|
+
{ name: 'W3C: CSS Box Sizing Level 4', url: 'https://www.w3.org/TR/css-sizing-4/#aspect-ratio' },
|
|
7
|
+
];
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { bibliography } from '../bibliography';
|
|
1
2
|
import type { WithContext, FAQPage, HowToThing, SoftwareApplication } from 'schema-dts';
|
|
2
3
|
import type { ToolLocaleContent } from '../../../types';
|
|
3
4
|
import type { AspectRatioUI } from '../ui';
|
|
@@ -109,20 +110,7 @@ export const content: ToolLocaleContent<AspectRatioUI> = {
|
|
|
109
110
|
faqTitle: 'Häufig gestellte Fragen',
|
|
110
111
|
faq: faqData,
|
|
111
112
|
bibliographyTitle: 'Referenzen und Dokumentation',
|
|
112
|
-
bibliography
|
|
113
|
-
{
|
|
114
|
-
name: 'MDN Web Docs: aspect-ratio (CSS)',
|
|
115
|
-
url: 'https://developer.mozilla.org/en-US/docs/Web/CSS/aspect-ratio',
|
|
116
|
-
},
|
|
117
|
-
{
|
|
118
|
-
name: 'Wikipedia: Seitenverhältnis',
|
|
119
|
-
url: 'https://de.wikipedia.org/wiki/Seitenverhältnis',
|
|
120
|
-
},
|
|
121
|
-
{
|
|
122
|
-
name: 'W3C: CSS Box Sizing Level 4',
|
|
123
|
-
url: 'https://www.w3.org/TR/css-sizing-4/#aspect-ratio',
|
|
124
|
-
},
|
|
125
|
-
],
|
|
113
|
+
bibliography,
|
|
126
114
|
howTo: howToData,
|
|
127
115
|
schemas: [faqSchema, howToSchema, appSchema],
|
|
128
116
|
seo: [
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { bibliography } from '../bibliography';
|
|
1
2
|
import type { WithContext, FAQPage, HowToThing, SoftwareApplication } from 'schema-dts';
|
|
2
3
|
import type { ToolLocaleContent } from '../../../types';
|
|
3
4
|
import type { AspectRatioUI } from '../ui';
|
|
@@ -109,20 +110,7 @@ export const content: ToolLocaleContent<AspectRatioUI> = {
|
|
|
109
110
|
faqTitle: 'Frequently Asked Questions',
|
|
110
111
|
faq: faqData,
|
|
111
112
|
bibliographyTitle: 'References and Documentation',
|
|
112
|
-
bibliography
|
|
113
|
-
{
|
|
114
|
-
name: 'MDN Web Docs: aspect-ratio (CSS)',
|
|
115
|
-
url: 'https://developer.mozilla.org/en-US/docs/Web/CSS/aspect-ratio',
|
|
116
|
-
},
|
|
117
|
-
{
|
|
118
|
-
name: 'Wikipedia: Aspect ratio',
|
|
119
|
-
url: 'https://en.wikipedia.org/wiki/Aspect_ratio',
|
|
120
|
-
},
|
|
121
|
-
{
|
|
122
|
-
name: 'W3C: CSS Box Sizing Level 4',
|
|
123
|
-
url: 'https://www.w3.org/TR/css-sizing-4/#aspect-ratio',
|
|
124
|
-
},
|
|
125
|
-
],
|
|
113
|
+
bibliography,
|
|
126
114
|
howTo: howToData,
|
|
127
115
|
schemas: [faqSchema, howToSchema, appSchema],
|
|
128
116
|
seo: [
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { bibliography } from '../bibliography';
|
|
1
2
|
import type { WithContext, FAQPage, HowToThing, SoftwareApplication } from 'schema-dts';
|
|
2
3
|
import type { ToolLocaleContent } from '../../../types';
|
|
3
4
|
import type { AspectRatioUI } from '../ui';
|
|
@@ -109,20 +110,7 @@ export const content: ToolLocaleContent<AspectRatioUI> = {
|
|
|
109
110
|
faqTitle: 'Preguntas Frecuentes',
|
|
110
111
|
faq: faqData,
|
|
111
112
|
bibliographyTitle: 'Referencias y Documentación',
|
|
112
|
-
bibliography
|
|
113
|
-
{
|
|
114
|
-
name: 'MDN Web Docs: aspect-ratio (CSS)',
|
|
115
|
-
url: 'https://developer.mozilla.org/es/docs/Web/CSS/aspect-ratio',
|
|
116
|
-
},
|
|
117
|
-
{
|
|
118
|
-
name: 'Wikipedia: Relación de aspecto',
|
|
119
|
-
url: 'https://es.wikipedia.org/wiki/Relaci%C3%B3n_de_aspecto',
|
|
120
|
-
},
|
|
121
|
-
{
|
|
122
|
-
name: 'W3C: CSS Box Sizing Level 4',
|
|
123
|
-
url: 'https://www.w3.org/TR/css-sizing-4/#aspect-ratio',
|
|
124
|
-
},
|
|
125
|
-
],
|
|
113
|
+
bibliography,
|
|
126
114
|
howTo: howToData,
|
|
127
115
|
schemas: [faqSchema, howToSchema, appSchema],
|
|
128
116
|
seo: [
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { bibliography } from '../bibliography';
|
|
1
2
|
import type { WithContext, FAQPage, HowToThing, SoftwareApplication } from 'schema-dts';
|
|
2
3
|
import type { ToolLocaleContent } from '../../../types';
|
|
3
4
|
import type { AspectRatioUI } from '../ui';
|
|
@@ -109,20 +110,7 @@ export const content: ToolLocaleContent<AspectRatioUI> = {
|
|
|
109
110
|
faqTitle: 'Questions Fréquentes',
|
|
110
111
|
faq: faqData,
|
|
111
112
|
bibliographyTitle: 'Références et Documentation',
|
|
112
|
-
bibliography
|
|
113
|
-
{
|
|
114
|
-
name: 'MDN Web Docs: aspect-ratio (CSS)',
|
|
115
|
-
url: 'https://developer.mozilla.org/fr/docs/Web/CSS/aspect-ratio',
|
|
116
|
-
},
|
|
117
|
-
{
|
|
118
|
-
name: 'Wikipedia: Format d\'image',
|
|
119
|
-
url: 'https://fr.wikipedia.org/wiki/Format_d%27image',
|
|
120
|
-
},
|
|
121
|
-
{
|
|
122
|
-
name: 'W3C: CSS Box Sizing Level 4',
|
|
123
|
-
url: 'https://www.w3.org/TR/css-sizing-4/#aspect-ratio',
|
|
124
|
-
},
|
|
125
|
-
],
|
|
113
|
+
bibliography,
|
|
126
114
|
howTo: howToData,
|
|
127
115
|
schemas: [faqSchema, howToSchema, appSchema],
|
|
128
116
|
seo: [
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { bibliography } from '../bibliography';
|
|
1
2
|
import type { WithContext, FAQPage, HowToThing, SoftwareApplication } from 'schema-dts';
|
|
2
3
|
import type { ToolLocaleContent } from '../../../types';
|
|
3
4
|
import type { AspectRatioUI } from '../ui';
|
|
@@ -109,20 +110,7 @@ export const content: ToolLocaleContent<AspectRatioUI> = {
|
|
|
109
110
|
faqTitle: 'Pertanyaan yang Sering Diajukan',
|
|
110
111
|
faq: faqData,
|
|
111
112
|
bibliographyTitle: 'Referensi dan Dokumentasi',
|
|
112
|
-
bibliography
|
|
113
|
-
{
|
|
114
|
-
name: 'MDN Web Docs: aspect-ratio (CSS)',
|
|
115
|
-
url: 'https://developer.mozilla.org/en-US/docs/Web/CSS/aspect-ratio',
|
|
116
|
-
},
|
|
117
|
-
{
|
|
118
|
-
name: 'Wikipedia: Aspect ratio',
|
|
119
|
-
url: 'https://en.wikipedia.org/wiki/Aspect_ratio',
|
|
120
|
-
},
|
|
121
|
-
{
|
|
122
|
-
name: 'W3C: CSS Box Sizing Level 4',
|
|
123
|
-
url: 'https://www.w3.org/TR/css-sizing-4/#aspect-ratio',
|
|
124
|
-
},
|
|
125
|
-
],
|
|
113
|
+
bibliography,
|
|
126
114
|
howTo: howToData,
|
|
127
115
|
schemas: [faqSchema, howToSchema, appSchema],
|
|
128
116
|
seo: [
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { bibliography } from '../bibliography';
|
|
1
2
|
import type { WithContext, FAQPage, HowToThing, SoftwareApplication } from 'schema-dts';
|
|
2
3
|
import type { ToolLocaleContent } from '../../../types';
|
|
3
4
|
import type { AspectRatioUI } from '../ui';
|
|
@@ -109,20 +110,7 @@ export const content: ToolLocaleContent<AspectRatioUI> = {
|
|
|
109
110
|
faqTitle: 'Domande frequenti',
|
|
110
111
|
faq: faqData,
|
|
111
112
|
bibliographyTitle: 'Riferimenti e documentazione',
|
|
112
|
-
bibliography
|
|
113
|
-
{
|
|
114
|
-
name: 'MDN Web Docs: aspect-ratio (CSS)',
|
|
115
|
-
url: 'https://developer.mozilla.org/en-US/docs/Web/CSS/aspect-ratio',
|
|
116
|
-
},
|
|
117
|
-
{
|
|
118
|
-
name: 'Wikipedia: Aspect ratio',
|
|
119
|
-
url: 'https://it.wikipedia.org/wiki/Rapporto_d\'aspetto',
|
|
120
|
-
},
|
|
121
|
-
{
|
|
122
|
-
name: 'W3C: CSS Box Sizing Level 4',
|
|
123
|
-
url: 'https://www.w3.org/TR/css-sizing-4/#aspect-ratio',
|
|
124
|
-
},
|
|
125
|
-
],
|
|
113
|
+
bibliography,
|
|
126
114
|
howTo: howToData,
|
|
127
115
|
schemas: [faqSchema, howToSchema, appSchema],
|
|
128
116
|
seo: [
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { bibliography } from '../bibliography';
|
|
1
2
|
import type { WithContext, FAQPage, HowToThing, SoftwareApplication } from 'schema-dts';
|
|
2
3
|
import type { ToolLocaleContent } from '../../../types';
|
|
3
4
|
import type { AspectRatioUI } from '../ui';
|
|
@@ -109,20 +110,7 @@ export const content: ToolLocaleContent<AspectRatioUI> = {
|
|
|
109
110
|
faqTitle: 'よくある質問',
|
|
110
111
|
faq: faqData,
|
|
111
112
|
bibliographyTitle: '参考文献とドキュメント',
|
|
112
|
-
bibliography
|
|
113
|
-
{
|
|
114
|
-
name: 'MDN Web Docs: aspect-ratio (CSS)',
|
|
115
|
-
url: 'https://developer.mozilla.org/en-US/docs/Web/CSS/aspect-ratio',
|
|
116
|
-
},
|
|
117
|
-
{
|
|
118
|
-
name: 'Wikipedia: アスペクト比',
|
|
119
|
-
url: 'https://ja.wikipedia.org/wiki/アスペクト比',
|
|
120
|
-
},
|
|
121
|
-
{
|
|
122
|
-
name: 'W3C: CSS Box Sizing Level 4',
|
|
123
|
-
url: 'https://www.w3.org/TR/css-sizing-4/#aspect-ratio',
|
|
124
|
-
},
|
|
125
|
-
],
|
|
113
|
+
bibliography,
|
|
126
114
|
howTo: howToData,
|
|
127
115
|
schemas: [faqSchema, howToSchema, appSchema],
|
|
128
116
|
seo: [
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { bibliography } from '../bibliography';
|
|
1
2
|
import type { WithContext, FAQPage, HowToThing, SoftwareApplication } from 'schema-dts';
|
|
2
3
|
import type { ToolLocaleContent } from '../../../types';
|
|
3
4
|
import type { AspectRatioUI } from '../ui';
|
|
@@ -109,20 +110,7 @@ export const content: ToolLocaleContent<AspectRatioUI> = {
|
|
|
109
110
|
faqTitle: '자주 묻는 질문',
|
|
110
111
|
faq: faqData,
|
|
111
112
|
bibliographyTitle: '참고 자료 및 문서',
|
|
112
|
-
bibliography
|
|
113
|
-
{
|
|
114
|
-
name: 'MDN Web Docs: aspect-ratio (CSS)',
|
|
115
|
-
url: 'https://developer.mozilla.org/en-US/docs/Web/CSS/aspect-ratio',
|
|
116
|
-
},
|
|
117
|
-
{
|
|
118
|
-
name: 'Wikipedia: Aspect ratio',
|
|
119
|
-
url: 'https://ko.wikipedia.org/wiki/가로세로비',
|
|
120
|
-
},
|
|
121
|
-
{
|
|
122
|
-
name: 'W3C: CSS Box Sizing Level 4',
|
|
123
|
-
url: 'https://www.w3.org/TR/css-sizing-4/#aspect-ratio',
|
|
124
|
-
},
|
|
125
|
-
],
|
|
113
|
+
bibliography,
|
|
126
114
|
howTo: howToData,
|
|
127
115
|
schemas: [faqSchema, howToSchema, appSchema],
|
|
128
116
|
seo: [
|