@jjlmoya/utils-civic 1.8.0 → 1.9.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/.github/workflows/ci.yml +103 -0
- package/.gitignore +1 -0
- package/package.json +17 -5
- package/scripts/postinstall.mjs +2 -4
- package/src/category/index.ts +2 -1
- package/src/components/ProductionBreadcrumb.astro +132 -0
- package/src/components/ProductionWidget.astro +182 -0
- package/src/entries.ts +2 -0
- package/src/i18n/header-ui.ts +15 -0
- package/src/i18n/language-ui.ts +9 -0
- package/src/i18n/languages.ts +24 -0
- package/src/identity/brands.ts +5 -0
- package/src/index.ts +1 -0
- package/src/layouts/ProductionCategoryPage.astro +184 -0
- package/src/layouts/ProductionPage.astro +209 -0
- package/src/layouts/ProductionUtilityPage.astro +235 -0
- package/src/mfe/assets.ts +15 -0
- package/src/mfe/category-ui.ts +25 -0
- package/src/mfe/routes.ts +50 -0
- package/src/pages/[locale]/[utilities]/[categories]/[category]/[slug].astro +100 -0
- package/src/pages/[locale]/[utilities]/[categories]/[category].astro +44 -0
- package/src/pages/index.astro +1 -1
- package/src/pages/utilidades/[slug].astro +90 -0
- package/src/pages/utilidades/categorias/[category].astro +38 -0
- package/src/tests/locale_completeness.test.ts +1 -1
- package/src/tests/tool_validation.test.ts +1 -1
- package/src/tool/access-to-information-request-builder/access-to-information-request-builder.css +577 -0
- package/src/tool/access-to-information-request-builder/bibliography.astro +6 -0
- package/src/tool/access-to-information-request-builder/bibliography.ts +6 -0
- package/src/tool/access-to-information-request-builder/component.astro +106 -0
- package/src/tool/access-to-information-request-builder/contract.test.ts +17 -0
- package/src/tool/access-to-information-request-builder/controller.ts +135 -0
- package/src/tool/access-to-information-request-builder/dom-views.ts +59 -0
- package/src/tool/access-to-information-request-builder/entry.ts +27 -0
- package/src/tool/access-to-information-request-builder/evaluator.ts +27 -0
- package/src/tool/access-to-information-request-builder/i18n/de.ts +52 -0
- package/src/tool/access-to-information-request-builder/i18n/en.ts +76 -0
- package/src/tool/access-to-information-request-builder/i18n/es.ts +52 -0
- package/src/tool/access-to-information-request-builder/i18n/fr.ts +50 -0
- package/src/tool/access-to-information-request-builder/i18n/id.ts +50 -0
- package/src/tool/access-to-information-request-builder/i18n/it.ts +50 -0
- package/src/tool/access-to-information-request-builder/i18n/ja.ts +50 -0
- package/src/tool/access-to-information-request-builder/i18n/ko.ts +50 -0
- package/src/tool/access-to-information-request-builder/i18n/nl.ts +49 -0
- package/src/tool/access-to-information-request-builder/i18n/pl.ts +49 -0
- package/src/tool/access-to-information-request-builder/i18n/pt.ts +49 -0
- package/src/tool/access-to-information-request-builder/i18n/ru.ts +49 -0
- package/src/tool/access-to-information-request-builder/i18n/sv.ts +49 -0
- package/src/tool/access-to-information-request-builder/i18n/tr.ts +49 -0
- package/src/tool/access-to-information-request-builder/i18n/zh.ts +49 -0
- package/src/tool/access-to-information-request-builder/index.ts +11 -0
- package/src/tool/access-to-information-request-builder/logic.test.ts +68 -0
- package/src/tool/access-to-information-request-builder/logic.ts +138 -0
- package/src/tool/access-to-information-request-builder/seo.astro +15 -0
- package/src/tool/access-to-information-request-builder/storage.ts +27 -0
- package/src/tool/access-to-information-request-builder/ui.ts +154 -0
- package/src/tool/access-to-information-request-builder/validation.ts +7 -0
- package/src/tools.ts +2 -0
- package/src/types.ts +2 -4
- package/src/worker.ts +9 -0
- package/tsconfig.json +14 -5
- package/src/pages/[locale]/[slug].astro +0 -166
- package/src/pages/[locale].astro +0 -253
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import {
|
|
2
|
+
getCategoryNamespace,
|
|
3
|
+
getCategoryPath as getSharedCategoryPath,
|
|
4
|
+
getUtilitiesPath as getSharedUtilitiesPath,
|
|
5
|
+
getUtilityNamespace,
|
|
6
|
+
getUtilityPath as getSharedUtilityPath,
|
|
7
|
+
type UtilityLocale,
|
|
8
|
+
} from "@jjlmoya/utils-shared/routing";
|
|
9
|
+
|
|
10
|
+
export type { UtilityLocale };
|
|
11
|
+
export { getCategoryNamespace, getUtilityNamespace };
|
|
12
|
+
|
|
13
|
+
export const INTERNAL_LOCALES = [
|
|
14
|
+
"en", "fr", "de", "it", "pt", "nl", "sv", "pl", "id", "tr", "ru", "ja", "ko", "zh",
|
|
15
|
+
] as const satisfies readonly UtilityLocale[];
|
|
16
|
+
|
|
17
|
+
const getDevelopmentPath = (url: string): string => {
|
|
18
|
+
if (!import.meta.env.DEV) return url;
|
|
19
|
+
try {
|
|
20
|
+
return new URL(url, "http://localhost:4324").pathname;
|
|
21
|
+
} catch {
|
|
22
|
+
return url;
|
|
23
|
+
}
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
export const getUtilitiesPath = (locale: UtilityLocale): string =>
|
|
27
|
+
getDevelopmentPath(getSharedUtilitiesPath(locale));
|
|
28
|
+
|
|
29
|
+
export const getCategoryPath = (locale: UtilityLocale, categorySlug: string): string =>
|
|
30
|
+
getDevelopmentPath(getSharedCategoryPath(locale, categorySlug));
|
|
31
|
+
|
|
32
|
+
export const getUtilityPath = (
|
|
33
|
+
locale: UtilityLocale,
|
|
34
|
+
categorySlug: string,
|
|
35
|
+
toolSlug: string,
|
|
36
|
+
): string => getDevelopmentPath(getSharedUtilityPath(locale, categorySlug, toolSlug));
|
|
37
|
+
|
|
38
|
+
export const getCategoryRoute = (locale: UtilityLocale, categorySlug: string): string =>
|
|
39
|
+
getCategoryPath(locale, categorySlug);
|
|
40
|
+
|
|
41
|
+
export const getUtilityRoute = (locale: UtilityLocale, categorySlug: string, toolSlug: string): string =>
|
|
42
|
+
getUtilityPath(locale, categorySlug, toolSlug);
|
|
43
|
+
|
|
44
|
+
export const getUtilityIndexRoute = (locale: UtilityLocale): string => getUtilitiesPath(locale);
|
|
45
|
+
|
|
46
|
+
export const getInternalCategoryRoute = (locale: Exclude<UtilityLocale, "es">, categorySlug: string): string =>
|
|
47
|
+
getCategoryPath(locale, categorySlug);
|
|
48
|
+
|
|
49
|
+
export const getInternalUtilityRoute = (locale: Exclude<UtilityLocale, "es">, categorySlug: string, toolSlug: string): string =>
|
|
50
|
+
getUtilityPath(locale, categorySlug, toolSlug);
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
---
|
|
2
|
+
import ProductionUtilityPage from "../../../../../layouts/ProductionUtilityPage.astro";
|
|
3
|
+
import { ALL_TOOLS, civicCategory } from "../../../../../index";
|
|
4
|
+
import { LANGUAGE_CODES, type Language } from "../../../../../i18n/languages";
|
|
5
|
+
import type { CategoryLocaleContent, ToolLocaleContent } from "../../../../../types";
|
|
6
|
+
import type { AstroComponentFactory } from "astro/runtime/server/index.js";
|
|
7
|
+
import { getCategoryNamespace, getCategoryPath, getUtilityNamespace, getUtilityPath } from "../../../../../mfe/routes";
|
|
8
|
+
import { getUtilityOgImage } from "../../../../../mfe/assets";
|
|
9
|
+
|
|
10
|
+
type Loader<T> = () => Promise<{ default: T }>;
|
|
11
|
+
type LoadedTool = ToolLocaleContent;
|
|
12
|
+
|
|
13
|
+
export async function getStaticPaths() {
|
|
14
|
+
const paths = [];
|
|
15
|
+
for (const { entry, Component: componentLoader, SEOComponent: seoLoader, BibliographyComponent: bibliographyLoader } of ALL_TOOLS) {
|
|
16
|
+
const contents = Object.fromEntries(await Promise.all(LANGUAGE_CODES.map(async (language) => {
|
|
17
|
+
const loader = entry.i18n[language] ?? entry.i18n.en;
|
|
18
|
+
if (!loader) throw new Error(`Missing ${language} locale for ${entry.id}`);
|
|
19
|
+
return [language, await loader()];
|
|
20
|
+
}))) as Record<Language, LoadedTool>;
|
|
21
|
+
const categories = Object.fromEntries(await Promise.all(LANGUAGE_CODES.map(async (language) => [
|
|
22
|
+
language,
|
|
23
|
+
await civicCategory.i18n[language]!(),
|
|
24
|
+
]))) as Record<Language, CategoryLocaleContent>;
|
|
25
|
+
const { default: Component } = await (componentLoader as Loader<AstroComponentFactory>)();
|
|
26
|
+
const { default: SEOComponent } = await (seoLoader as Loader<AstroComponentFactory>)();
|
|
27
|
+
const { default: BibliographyComponent } = await (bibliographyLoader as Loader<AstroComponentFactory>)();
|
|
28
|
+
for (const locale of LANGUAGE_CODES.filter((candidate) => candidate !== "es")) {
|
|
29
|
+
const content = contents[locale];
|
|
30
|
+
const category = categories[locale];
|
|
31
|
+
paths.push({
|
|
32
|
+
params: {
|
|
33
|
+
locale,
|
|
34
|
+
utilities: getUtilityNamespace(locale),
|
|
35
|
+
categories: getCategoryNamespace(locale),
|
|
36
|
+
category: category.slug,
|
|
37
|
+
slug: content.slug,
|
|
38
|
+
},
|
|
39
|
+
props: {
|
|
40
|
+
locale,
|
|
41
|
+
content,
|
|
42
|
+
englishSlug: contents.en.slug,
|
|
43
|
+
category,
|
|
44
|
+
categorySlug: category.slug,
|
|
45
|
+
Component,
|
|
46
|
+
SEOComponent,
|
|
47
|
+
BibliographyComponent,
|
|
48
|
+
alternates: LANGUAGE_CODES.map((language) => ({
|
|
49
|
+
language,
|
|
50
|
+
url: getUtilityPath(language, categories[language].slug, contents[language].slug),
|
|
51
|
+
})),
|
|
52
|
+
image: getUtilityOgImage(contents.en.slug),
|
|
53
|
+
},
|
|
54
|
+
});
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
return paths;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
const { locale, content, englishSlug, category, categorySlug, Component, SEOComponent, BibliographyComponent, relatedTools, alternates, image } = Astro.props as {
|
|
61
|
+
locale: Exclude<Language, "es">;
|
|
62
|
+
content: LoadedTool;
|
|
63
|
+
englishSlug: string;
|
|
64
|
+
category: CategoryLocaleContent;
|
|
65
|
+
categorySlug: string;
|
|
66
|
+
Component: AstroComponentFactory;
|
|
67
|
+
SEOComponent: AstroComponentFactory;
|
|
68
|
+
BibliographyComponent: AstroComponentFactory;
|
|
69
|
+
relatedTools?: { icon: string; title: string; description: string; href: string }[];
|
|
70
|
+
alternates: { language: Language; url: string }[];
|
|
71
|
+
image?: string;
|
|
72
|
+
};
|
|
73
|
+
const related = relatedTools ?? (await Promise.all(ALL_TOOLS.map(async ({ entry: relatedEntry }) => {
|
|
74
|
+
const loader = relatedEntry.i18n[locale] ?? relatedEntry.i18n.en;
|
|
75
|
+
if (!loader) return null;
|
|
76
|
+
const relatedContent = await loader();
|
|
77
|
+
if (relatedContent.slug === content.slug) return null;
|
|
78
|
+
return {
|
|
79
|
+
icon: relatedEntry.icons.fg,
|
|
80
|
+
title: relatedContent.title,
|
|
81
|
+
description: relatedContent.description,
|
|
82
|
+
href: getUtilityPath(locale, categorySlug, relatedContent.slug),
|
|
83
|
+
};
|
|
84
|
+
}))).filter((tool): tool is { icon: string; title: string; description: string; href: string } => tool !== null);
|
|
85
|
+
---
|
|
86
|
+
|
|
87
|
+
<ProductionUtilityPage
|
|
88
|
+
{locale}
|
|
89
|
+
{content}
|
|
90
|
+
{englishSlug}
|
|
91
|
+
categoryTitle={category.title}
|
|
92
|
+
{categorySlug}
|
|
93
|
+
categoryHref={getCategoryPath(locale, categorySlug)}
|
|
94
|
+
relatedTools={related}
|
|
95
|
+
{Component}
|
|
96
|
+
{SEOComponent}
|
|
97
|
+
{BibliographyComponent}
|
|
98
|
+
{alternates}
|
|
99
|
+
{image}
|
|
100
|
+
/>
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
---
|
|
2
|
+
import ProductionCategoryPage from "../../../../layouts/ProductionCategoryPage.astro";
|
|
3
|
+
import { ALL_TOOLS, civicCategory } from "../../../../index";
|
|
4
|
+
import { LANGUAGE_CODES, type Language } from "../../../../i18n/languages";
|
|
5
|
+
import { getCategoryNamespace, getCategoryPath, getUtilityNamespace, getUtilityPath } from "../../../../mfe/routes";
|
|
6
|
+
import { CATEGORY_OG_IMAGE } from "../../../../mfe/assets";
|
|
7
|
+
|
|
8
|
+
export async function getStaticPaths() {
|
|
9
|
+
const categories = Object.fromEntries(await Promise.all(
|
|
10
|
+
LANGUAGE_CODES.map(async (language) => [language, await civicCategory.i18n[language]!()]),
|
|
11
|
+
));
|
|
12
|
+
return LANGUAGE_CODES.filter((language) => language !== "es").map((locale) => {
|
|
13
|
+
const category = categories[locale]!;
|
|
14
|
+
const alternates = LANGUAGE_CODES.map((language) => ({
|
|
15
|
+
language,
|
|
16
|
+
url: getCategoryPath(language, categories[language]!.slug),
|
|
17
|
+
}));
|
|
18
|
+
return {
|
|
19
|
+
params: { locale, utilities: getUtilityNamespace(locale), categories: getCategoryNamespace(locale), category: category.slug },
|
|
20
|
+
props: { locale, category, alternates },
|
|
21
|
+
};
|
|
22
|
+
});
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
const { locale, category, alternates } = Astro.props as {
|
|
26
|
+
locale: Exclude<Language, "es">;
|
|
27
|
+
category: Awaited<ReturnType<NonNullable<(typeof civicCategory.i18n)[Language]>>>;
|
|
28
|
+
alternates: { language: Language; url: string }[];
|
|
29
|
+
};
|
|
30
|
+
const tools = await Promise.all(ALL_TOOLS.map(async ({ entry }) => {
|
|
31
|
+
const loader = entry.i18n[locale] ?? entry.i18n.en;
|
|
32
|
+
if (!loader) throw new Error(`Missing ${locale} locale for ${entry.id}`);
|
|
33
|
+
const content = await loader();
|
|
34
|
+
return {
|
|
35
|
+
id: entry.id,
|
|
36
|
+
icon: entry.icons.fg,
|
|
37
|
+
title: content.title,
|
|
38
|
+
description: content.description,
|
|
39
|
+
href: getUtilityPath(locale, category.slug, content.slug),
|
|
40
|
+
};
|
|
41
|
+
}));
|
|
42
|
+
---
|
|
43
|
+
|
|
44
|
+
<ProductionCategoryPage locale={locale} {category} {tools} {alternates} image={CATEGORY_OG_IMAGE} />
|
package/src/pages/index.astro
CHANGED
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
---
|
|
2
|
+
import ProductionUtilityPage from "../../layouts/ProductionUtilityPage.astro";
|
|
3
|
+
import { ALL_TOOLS, civicCategory } from "../../index";
|
|
4
|
+
import { LANGUAGE_CODES, type Language } from "../../i18n/languages";
|
|
5
|
+
import type { CategoryLocaleContent, ToolLocaleContent } from "../../types";
|
|
6
|
+
import type { AstroComponentFactory } from "astro/runtime/server/index.js";
|
|
7
|
+
import { getCategoryPath, getUtilityPath } from "../../mfe/routes";
|
|
8
|
+
import { getUtilityOgImage } from "../../mfe/assets";
|
|
9
|
+
|
|
10
|
+
type Loader<T> = () => Promise<{ default: T }>;
|
|
11
|
+
type LoadedTool = ToolLocaleContent;
|
|
12
|
+
|
|
13
|
+
export async function getStaticPaths() {
|
|
14
|
+
const category = await civicCategory.i18n.es!();
|
|
15
|
+
const categories = Object.fromEntries(await Promise.all(LANGUAGE_CODES.map(async (language) => [
|
|
16
|
+
language,
|
|
17
|
+
await civicCategory.i18n[language]!(),
|
|
18
|
+
]))) as Record<Language, CategoryLocaleContent>;
|
|
19
|
+
const paths = [];
|
|
20
|
+
for (const { entry, Component: componentLoader, SEOComponent: seoLoader, BibliographyComponent: bibliographyLoader } of ALL_TOOLS) {
|
|
21
|
+
const contents = Object.fromEntries(await Promise.all(LANGUAGE_CODES.map(async (language) => {
|
|
22
|
+
const loader = entry.i18n[language] ?? entry.i18n.en;
|
|
23
|
+
if (!loader) throw new Error(`Missing ${language} locale for ${entry.id}`);
|
|
24
|
+
return [language, await loader()];
|
|
25
|
+
}))) as Record<Language, LoadedTool>;
|
|
26
|
+
const { default: Component } = await (componentLoader as Loader<AstroComponentFactory>)();
|
|
27
|
+
const { default: SEOComponent } = await (seoLoader as Loader<AstroComponentFactory>)();
|
|
28
|
+
const { default: BibliographyComponent } = await (bibliographyLoader as Loader<AstroComponentFactory>)();
|
|
29
|
+
paths.push({
|
|
30
|
+
params: { slug: contents.es.slug },
|
|
31
|
+
props: {
|
|
32
|
+
locale: "es",
|
|
33
|
+
content: contents.es,
|
|
34
|
+
englishSlug: contents.en.slug,
|
|
35
|
+
category,
|
|
36
|
+
categorySlug: category.slug,
|
|
37
|
+
Component,
|
|
38
|
+
SEOComponent,
|
|
39
|
+
BibliographyComponent,
|
|
40
|
+
alternates: LANGUAGE_CODES.map((language) => ({
|
|
41
|
+
language,
|
|
42
|
+
url: getUtilityPath(language, categories[language].slug, contents[language].slug),
|
|
43
|
+
})),
|
|
44
|
+
image: getUtilityOgImage(contents.en.slug),
|
|
45
|
+
},
|
|
46
|
+
});
|
|
47
|
+
}
|
|
48
|
+
return paths;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
const { locale, content, englishSlug, category, categorySlug, Component, SEOComponent, BibliographyComponent, alternates, image } = Astro.props as {
|
|
52
|
+
locale: "es";
|
|
53
|
+
content: LoadedTool;
|
|
54
|
+
englishSlug: string;
|
|
55
|
+
category: CategoryLocaleContent;
|
|
56
|
+
categorySlug: string;
|
|
57
|
+
Component: AstroComponentFactory;
|
|
58
|
+
SEOComponent: AstroComponentFactory;
|
|
59
|
+
BibliographyComponent: AstroComponentFactory;
|
|
60
|
+
alternates: { language: Language; url: string }[];
|
|
61
|
+
image?: string;
|
|
62
|
+
};
|
|
63
|
+
const relatedTools = (await Promise.all(ALL_TOOLS.map(async ({ entry: relatedEntry }) => {
|
|
64
|
+
const loader = relatedEntry.i18n.es ?? relatedEntry.i18n.en;
|
|
65
|
+
if (!loader) return null;
|
|
66
|
+
const relatedContent = await loader();
|
|
67
|
+
if (relatedContent.slug === content.slug) return null;
|
|
68
|
+
return {
|
|
69
|
+
icon: relatedEntry.icons.fg,
|
|
70
|
+
title: relatedContent.title,
|
|
71
|
+
description: relatedContent.description,
|
|
72
|
+
href: getUtilityPath("es", categorySlug, relatedContent.slug),
|
|
73
|
+
};
|
|
74
|
+
}))).filter((tool): tool is { icon: string; title: string; description: string; href: string } => tool !== null);
|
|
75
|
+
---
|
|
76
|
+
|
|
77
|
+
<ProductionUtilityPage
|
|
78
|
+
{locale}
|
|
79
|
+
{content}
|
|
80
|
+
{englishSlug}
|
|
81
|
+
categoryTitle={category.title}
|
|
82
|
+
{categorySlug}
|
|
83
|
+
categoryHref={getCategoryPath(locale, categorySlug)}
|
|
84
|
+
{relatedTools}
|
|
85
|
+
{Component}
|
|
86
|
+
{SEOComponent}
|
|
87
|
+
{BibliographyComponent}
|
|
88
|
+
{alternates}
|
|
89
|
+
{image}
|
|
90
|
+
/>
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
---
|
|
2
|
+
import ProductionCategoryPage from "../../../layouts/ProductionCategoryPage.astro";
|
|
3
|
+
import { ALL_TOOLS, civicCategory } from "../../../index";
|
|
4
|
+
import { LANGUAGE_CODES, type Language } from "../../../i18n/languages";
|
|
5
|
+
import { getCategoryPath, getUtilityPath } from "../../../mfe/routes";
|
|
6
|
+
import { CATEGORY_OG_IMAGE } from "../../../mfe/assets";
|
|
7
|
+
|
|
8
|
+
export async function getStaticPaths() {
|
|
9
|
+
const categories = Object.fromEntries(await Promise.all(
|
|
10
|
+
LANGUAGE_CODES.map(async (language) => [language, await civicCategory.i18n[language]!()]),
|
|
11
|
+
));
|
|
12
|
+
const category = categories.es!;
|
|
13
|
+
const alternates = LANGUAGE_CODES.map((language) => ({
|
|
14
|
+
language,
|
|
15
|
+
url: getCategoryPath(language, categories[language]!.slug),
|
|
16
|
+
}));
|
|
17
|
+
return [{ params: { category: category.slug }, props: { category, alternates } }];
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
const { category, alternates } = Astro.props as {
|
|
21
|
+
category: Awaited<ReturnType<NonNullable<(typeof civicCategory.i18n)[Language]>>>;
|
|
22
|
+
alternates: { language: Language; url: string }[];
|
|
23
|
+
};
|
|
24
|
+
const tools = await Promise.all(ALL_TOOLS.map(async ({ entry }) => {
|
|
25
|
+
const loader = entry.i18n.es ?? entry.i18n.en;
|
|
26
|
+
if (!loader) throw new Error(`Missing Spanish locale for ${entry.id}`);
|
|
27
|
+
const content = await loader();
|
|
28
|
+
return {
|
|
29
|
+
id: entry.id,
|
|
30
|
+
icon: entry.icons.fg,
|
|
31
|
+
title: content.title,
|
|
32
|
+
description: content.description,
|
|
33
|
+
href: getUtilityPath("es", category.slug, content.slug),
|
|
34
|
+
};
|
|
35
|
+
}));
|
|
36
|
+
---
|
|
37
|
+
|
|
38
|
+
<ProductionCategoryPage locale="es" {category} {tools} {alternates} image={CATEGORY_OG_IMAGE} />
|
|
@@ -5,7 +5,7 @@ import { civicCategory } from '../data';
|
|
|
5
5
|
describe('Tool Validation Suite', () => {
|
|
6
6
|
describe('Library Registration', () => {
|
|
7
7
|
it('should have tools in ALL_TOOLS', () => {
|
|
8
|
-
expect(ALL_TOOLS.length).toBe(
|
|
8
|
+
expect(ALL_TOOLS.length).toBe(9);
|
|
9
9
|
});
|
|
10
10
|
|
|
11
11
|
it('civicCategory should be defined', () => {
|