@jjlmoya/utils-cooking 1.14.0 → 1.18.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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jjlmoya/utils-cooking",
3
- "version": "1.14.0",
3
+ "version": "1.18.0",
4
4
  "type": "module",
5
5
  "main": "./src/index.ts",
6
6
  "types": "./src/index.ts",
package/src/index.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  export { cookingCategory, cookingCategory as templateCategory } from './category';
2
- export { default as CookingCategorySEO } from './category/seo.astro';
2
+ export const CookingCategorySEO = () => import('./category/seo.astro').then((m) => m.default);
3
3
 
4
4
  export { AMERICAN_KITCHEN_CONVERTER_TOOL } from './tool/american-kitchen-converter';
5
5
  export { MERENGUE_CALCULATOR_TOOL } from './tool/meringue-peak';
@@ -28,5 +28,5 @@ export type {
28
28
  ToolDefinition,
29
29
  } from './types';
30
30
 
31
- export { ALL_TOOLS } from './tools';
31
+ export { ALL_ENTRIES, ALL_TOOLS } from './tools';
32
32
 
@@ -14,7 +14,8 @@ import type { UtilitySEOContent } from "@jjlmoya/utils-shared";
14
14
  export async function getStaticPaths() {
15
15
  const paths = [];
16
16
 
17
- for (const { entry, Component } of ALL_TOOLS) {
17
+ for (const { entry, Component: lazyComp } of ALL_TOOLS) {
18
+ const { default: Component } = await lazyComp();
18
19
  const localeEntries = Object.entries(entry.i18n) as [
19
20
  KnownLocale,
20
21
  () => Promise<ToolLocaleContent>,
@@ -52,8 +53,6 @@ export async function getStaticPaths() {
52
53
  return paths;
53
54
  }
54
55
 
55
- type ToolComponent = (props: { ui: Record<string, string> }) => unknown;
56
-
57
56
  interface NavItem {
58
57
  id: string;
59
58
  title: string;
@@ -62,7 +61,7 @@ interface NavItem {
62
61
  }
63
62
 
64
63
  interface Props {
65
- Component: ToolComponent;
64
+ Component: unknown;
66
65
  locale: KnownLocale;
67
66
  content: ToolLocaleContent;
68
67
  localeUrls: Partial<Record<KnownLocale, string>>;
@@ -0,0 +1,73 @@
1
+ import { describe, it, expect } from 'vitest';
2
+ import { cookingCategory as toolsCategory } from '../category/index';
3
+ import type { CategoryLocaleContent } from '../types';
4
+
5
+ const EXPECTED_LOCALES = [
6
+ 'de', 'en', 'es', 'fr', 'id', 'it', 'ja', 'ko', 'nl', 'pl', 'pt', 'ru', 'sv', 'tr', 'zh'
7
+ ];
8
+
9
+ const sharingLocales = ['ja', 'ko', 'zh'];
10
+
11
+ describe('Category Validation', () => {
12
+ it('should have all 15 required locales', () => {
13
+ const registeredLocales = Object.keys(toolsCategory.i18n);
14
+ EXPECTED_LOCALES.forEach((locale) => {
15
+ expect(
16
+ registeredLocales,
17
+ `Category is missing locale "${locale}"`,
18
+ ).toContain(locale);
19
+ });
20
+ });
21
+
22
+ describe('Category Slug Validation', () => {
23
+ it('every locale should have a unique, translated slug and follow format rules', async () => {
24
+ const slugs = new Map<string, string>();
25
+ const locales = Object.keys(toolsCategory.i18n);
26
+
27
+ let enSlug = '';
28
+ if (locales.includes('en')) {
29
+ const enLoader = toolsCategory.i18n['en' as keyof typeof toolsCategory.i18n];
30
+ const enContent = (await enLoader?.()) as CategoryLocaleContent;
31
+ enSlug = enContent.slug;
32
+ }
33
+
34
+ for (const locale of locales) {
35
+ const loader = toolsCategory.i18n[locale as keyof typeof toolsCategory.i18n];
36
+ const content = (await loader?.()) as CategoryLocaleContent;
37
+
38
+ expect(
39
+ content.slug,
40
+ `Category locale "${locale}" has an invalid slug ("${content.slug}"). Slugs must be transliterated (only a-z, 0-9, and -).`,
41
+ ).toMatch(/^[a-z0-9-]+$/);
42
+
43
+ expect(
44
+ content.slug,
45
+ `Category locale "${locale}" slug ("${content.slug}") cannot end with a 2-letter language code (e.g., -ja, -ru, -ko).`,
46
+ ).not.toMatch(/-[a-z]{2}$/);
47
+
48
+ if (locale !== 'en') {
49
+ if (sharingLocales.includes(locale)) {
50
+ expect(
51
+ content.slug,
52
+ `Category locale "${locale}" must use the same slug as "en" ("${enSlug}").`,
53
+ ).toBe(enSlug);
54
+ } else {
55
+ expect(
56
+ content.slug,
57
+ `Category locale "${locale}" has the same slug as "en" ("${enSlug}"). Cada slug tiene que estar en su propio idioma`,
58
+ ).not.toBe(enSlug);
59
+
60
+ if (slugs.has(content.slug)) {
61
+ const previousLocale = slugs.get(content.slug);
62
+ expect(
63
+ false,
64
+ `Category locales "${locale}" and "${previousLocale}" share the same slug ("${content.slug}"). Cada slug tiene que estar en su propia idioma`,
65
+ ).toBe(true);
66
+ }
67
+ slugs.set(content.slug, locale);
68
+ }
69
+ }
70
+ }
71
+ });
72
+ });
73
+ });
@@ -1,7 +1,4 @@
1
1
  import type { CookingToolEntry, ToolDefinition } from '../../types';
2
- import AmericanKitchenConverterComponent from './component.astro';
3
- import AmericanKitchenConverterSEO from './seo.astro';
4
- import AmericanKitchenConverterBibliography from './bibliography.astro';
5
2
 
6
3
  export const americanKitchenConverter: CookingToolEntry = {
7
4
  id: 'american-kitchen-converter',
@@ -30,7 +27,7 @@ export const americanKitchenConverter: CookingToolEntry = {
30
27
 
31
28
  export const AMERICAN_KITCHEN_CONVERTER_TOOL: ToolDefinition = {
32
29
  entry: americanKitchenConverter,
33
- Component: AmericanKitchenConverterComponent,
34
- SEOComponent: AmericanKitchenConverterSEO,
35
- BibliographyComponent: AmericanKitchenConverterBibliography,
30
+ Component: () => import('./component.astro'),
31
+ SEOComponent: () => import('./seo.astro'),
32
+ BibliographyComponent: () => import('./bibliography.astro'),
36
33
  };
@@ -1,7 +1,4 @@
1
1
  import type { CookingToolEntry, ToolDefinition } from '../../types';
2
- import BananaComponent from './component.astro';
3
- import BananaComponentSEO from './seo.astro';
4
- import BananaComponentBibliography from './bibliography.astro';
5
2
 
6
3
  export const bananaCare: CookingToolEntry = {
7
4
  id: 'banana-ripeness',
@@ -30,7 +27,7 @@ export const bananaCare: CookingToolEntry = {
30
27
 
31
28
  export const BANANA_CARE_TOOL: ToolDefinition = {
32
29
  entry: bananaCare,
33
- Component: BananaComponent,
34
- SEOComponent: BananaComponentSEO,
35
- BibliographyComponent: BananaComponentBibliography,
30
+ Component: () => import('./component.astro'),
31
+ SEOComponent: () => import('./seo.astro'),
32
+ BibliographyComponent: () => import('./bibliography.astro'),
36
33
  };
@@ -1,7 +1,7 @@
1
1
  import type { CookingToolEntry, ToolDefinition } from "../../types";
2
- import BrineComponent from "./component.astro";
3
- import BrineSEO from "./seo.astro";
4
- import BrineBibliography from "./bibliography.astro";
2
+
3
+
4
+
5
5
 
6
6
  export const brine: CookingToolEntry = {
7
7
  id: "brine-calculator",
@@ -28,11 +28,10 @@ export const brine: CookingToolEntry = {
28
28
  },
29
29
  };
30
30
 
31
- export { BrineComponent, BrineSEO, BrineBibliography };
32
31
 
33
32
  export const BRINE_TOOL: ToolDefinition = {
34
33
  entry: brine,
35
- Component: BrineComponent,
36
- SEOComponent: BrineSEO,
37
- BibliographyComponent: BrineBibliography,
34
+ Component: () => import('./component.astro'),
35
+ SEOComponent: () => import('./seo.astro'),
36
+ BibliographyComponent: () => import('./bibliography.astro'),
38
37
  };
@@ -1,7 +1,4 @@
1
1
  import type { CookingToolEntry, ToolDefinition } from '../../types';
2
- import CookwareGuideComponent from './component.astro';
3
- import CookwareGuideSEO from './seo.astro';
4
- import CookwareGuideBibliography from './bibliography.astro';
5
2
 
6
3
  export const cookwareGuide: CookingToolEntry = {
7
4
  id: 'cookware-guide',
@@ -30,7 +27,7 @@ export const cookwareGuide: CookingToolEntry = {
30
27
 
31
28
  export const COOKWARE_GUIDE_TOOL: ToolDefinition = {
32
29
  entry: cookwareGuide,
33
- Component: CookwareGuideComponent,
34
- SEOComponent: CookwareGuideSEO,
35
- BibliographyComponent: CookwareGuideBibliography,
30
+ Component: () => import('./component.astro'),
31
+ SEOComponent: () => import('./seo.astro'),
32
+ BibliographyComponent: () => import('./bibliography.astro'),
36
33
  };
@@ -1,7 +1,7 @@
1
1
  import type { CookingToolEntry, ToolDefinition } from "../../types";
2
- import EggTimerComponent from "./component.astro";
3
- import EggTimerSEO from "./seo.astro";
4
- import EggTimerBibliography from "./bibliography.astro";
2
+
3
+
4
+
5
5
 
6
6
  export const eggTimer: CookingToolEntry = {
7
7
  id: "egg-timer",
@@ -29,11 +29,10 @@ export const eggTimer: CookingToolEntry = {
29
29
  },
30
30
  };
31
31
 
32
- export { EggTimerComponent, EggTimerSEO, EggTimerBibliography };
33
32
 
34
33
  export const EGG_TIMER_TOOL: ToolDefinition = {
35
34
  entry: eggTimer,
36
- Component: EggTimerComponent,
37
- SEOComponent: EggTimerSEO,
38
- BibliographyComponent: EggTimerBibliography,
35
+ Component: () => import('./component.astro'),
36
+ SEOComponent: () => import('./seo.astro'),
37
+ BibliographyComponent: () => import('./bibliography.astro'),
39
38
  };
@@ -1,7 +1,4 @@
1
1
  import type { CookingToolEntry, ToolDefinition } from '../../types';
2
- import IngredientRescalerComponent from './component.astro';
3
- import IngredientRescalerSEO from './seo.astro';
4
- import IngredientRescalerBibliography from './bibliography.astro';
5
2
 
6
3
  export const ingredientRescaler: CookingToolEntry = {
7
4
  id: 'ingredient-rescaler',
@@ -30,7 +27,7 @@ export const ingredientRescaler: CookingToolEntry = {
30
27
 
31
28
  export const INGREDIENT_RESCALER_TOOL: ToolDefinition = {
32
29
  entry: ingredientRescaler,
33
- Component: IngredientRescalerComponent,
34
- SEOComponent: IngredientRescalerSEO,
35
- BibliographyComponent: IngredientRescalerBibliography,
30
+ Component: () => import('./component.astro'),
31
+ SEOComponent: () => import('./seo.astro'),
32
+ BibliographyComponent: () => import('./bibliography.astro'),
36
33
  };
@@ -1,7 +1,4 @@
1
1
  import type { CookingToolEntry, ToolDefinition } from '../../types';
2
- import KitchenTimerComponent from './component.astro';
3
- import KitchenTimerSEO from './seo.astro';
4
- import KitchenTimerBibliography from './bibliography.astro';
5
2
 
6
3
  export const kitchenTimer: CookingToolEntry = {
7
4
  id: 'kitchen-timer',
@@ -28,11 +25,10 @@ export const kitchenTimer: CookingToolEntry = {
28
25
  },
29
26
  };
30
27
 
31
- export { KitchenTimerComponent, KitchenTimerSEO, KitchenTimerBibliography };
32
28
 
33
29
  export const KITCHEN_TIMER_TOOL: ToolDefinition = {
34
30
  entry: kitchenTimer,
35
- Component: KitchenTimerComponent,
36
- SEOComponent: KitchenTimerSEO,
37
- BibliographyComponent: KitchenTimerBibliography,
31
+ Component: () => import('./component.astro'),
32
+ SEOComponent: () => import('./seo.astro'),
33
+ BibliographyComponent: () => import('./bibliography.astro'),
38
34
  };
@@ -1,7 +1,4 @@
1
1
  import type { CookingToolEntry, ToolDefinition } from '../../types';
2
- import MeringueComponent from './component.astro';
3
- import MeringueComponentSEO from './seo.astro';
4
- import MeringueComponentBibliography from './bibliography.astro';
5
2
 
6
3
  export const meringuePeak: CookingToolEntry = {
7
4
  id: 'meringue-peak',
@@ -30,7 +27,7 @@ export const meringuePeak: CookingToolEntry = {
30
27
 
31
28
  export const MERENGUE_CALCULATOR_TOOL: ToolDefinition = {
32
29
  entry: meringuePeak,
33
- Component: MeringueComponent,
34
- SEOComponent: MeringueComponentSEO,
35
- BibliographyComponent: MeringueComponentBibliography,
30
+ Component: () => import('./component.astro'),
31
+ SEOComponent: () => import('./seo.astro'),
32
+ BibliographyComponent: () => import('./bibliography.astro'),
36
33
  };
@@ -1,7 +1,4 @@
1
1
  import type { CookingToolEntry, ToolDefinition } from '../../types';
2
- import MoldScalerComponent from './component.astro';
3
- import MoldScalerSEO from './seo.astro';
4
- import MoldScalerBibliography from './bibliography.astro';
5
2
 
6
3
  export const moldScaler: CookingToolEntry = {
7
4
  id: 'mold-scaler',
@@ -28,11 +25,10 @@ export const moldScaler: CookingToolEntry = {
28
25
  },
29
26
  };
30
27
 
31
- export { MoldScalerComponent, MoldScalerSEO, MoldScalerBibliography };
32
28
 
33
29
  export const MOLD_SCALER_TOOL: ToolDefinition = {
34
30
  entry: moldScaler,
35
- Component: MoldScalerComponent,
36
- SEOComponent: MoldScalerSEO,
37
- BibliographyComponent: MoldScalerBibliography,
31
+ Component: () => import('./component.astro'),
32
+ SEOComponent: () => import('./seo.astro'),
33
+ BibliographyComponent: () => import('./bibliography.astro'),
38
34
  };
@@ -1,7 +1,7 @@
1
1
  import type { CookingToolEntry, ToolDefinition } from "../../types";
2
- import PizzaComponent from "./component.astro";
3
- import PizzaSEO from "./seo.astro";
4
- import PizzaBibliography from "./bibliography.astro";
2
+
3
+
4
+
5
5
 
6
6
  export const pizza: CookingToolEntry = {
7
7
  id: "pizza",
@@ -29,11 +29,10 @@ export const pizza: CookingToolEntry = {
29
29
  },
30
30
  };
31
31
 
32
- export { PizzaComponent, PizzaSEO, PizzaBibliography };
33
32
 
34
33
  export const PIZZA_TOOL: ToolDefinition = {
35
34
  entry: pizza,
36
- Component: PizzaComponent,
37
- SEOComponent: PizzaSEO,
38
- BibliographyComponent: PizzaBibliography,
35
+ Component: () => import('./component.astro'),
36
+ SEOComponent: () => import('./seo.astro'),
37
+ BibliographyComponent: () => import('./bibliography.astro'),
39
38
  };
@@ -1,7 +1,4 @@
1
1
  import type { CookingToolEntry, ToolDefinition } from '../../types';
2
- import RouxGuideComponent from './component.astro';
3
- import RouxGuideSEO from './seo.astro';
4
- import RouxGuideBibliography from './bibliography.astro';
5
2
 
6
3
  export const rouxGuide: CookingToolEntry = {
7
4
  id: 'roux-guide',
@@ -30,7 +27,7 @@ export const rouxGuide: CookingToolEntry = {
30
27
 
31
28
  export const ROUX_GUIDE_TOOL: ToolDefinition = {
32
29
  entry: rouxGuide,
33
- Component: RouxGuideComponent,
34
- SEOComponent: RouxGuideSEO,
35
- BibliographyComponent: RouxGuideBibliography,
30
+ Component: () => import('./component.astro'),
31
+ SEOComponent: () => import('./seo.astro'),
32
+ BibliographyComponent: () => import('./bibliography.astro'),
36
33
  };
@@ -1,7 +1,4 @@
1
1
  import type { CookingToolEntry, ToolDefinition } from '../../types';
2
- import SourdoughCalculatorComponent from './component.astro';
3
- import SourdoughCalculatorSEO from './seo.astro';
4
- import SourdoughCalculatorBibliography from './bibliography.astro';
5
2
 
6
3
  export const sourdoughCalculator: CookingToolEntry = {
7
4
  id: 'sourdough-calculator',
@@ -30,7 +27,7 @@ export const sourdoughCalculator: CookingToolEntry = {
30
27
 
31
28
  export const SOURDOUGH_CALCULATOR_TOOL: ToolDefinition = {
32
29
  entry: sourdoughCalculator,
33
- Component: SourdoughCalculatorComponent,
34
- SEOComponent: SourdoughCalculatorSEO,
35
- BibliographyComponent: SourdoughCalculatorBibliography,
30
+ Component: () => import('./component.astro'),
31
+ SEOComponent: () => import('./seo.astro'),
32
+ BibliographyComponent: () => import('./bibliography.astro'),
36
33
  };
package/src/tools.ts CHANGED
@@ -27,3 +27,5 @@ export const ALL_TOOLS: ToolDefinition[] = [
27
27
  COOKWARE_GUIDE_TOOL,
28
28
  ];
29
29
 
30
+
31
+ export const ALL_ENTRIES = ALL_TOOLS.map(t => t.entry);