@websolutespa/bom-core 0.1.2 → 0.2.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/CHANGELOG.md CHANGED
@@ -1,26 +1,32 @@
1
- # @websolutespa/bom-core
2
-
3
- ## 0.1.2
4
-
5
- ### Patch Changes
6
-
7
- - Modified: MockMenuService.
8
-
9
- ## 0.1.1
10
-
11
- ### Patch Changes
12
-
13
- - Modified: ILocalizable.
14
-
15
- ## 0.1.0
16
-
17
- ### Minor Changes
18
-
19
- - Added: splat routes.
20
- - Added: variants.
21
-
22
- ## 0.0.1
23
-
24
- ### Patch Changes
25
-
26
- - Added: first release.
1
+ # @websolutespa/bom-core
2
+
3
+ ## 0.2.0
4
+
5
+ ### Minor Changes
6
+
7
+ - Modified routes, added redirects.
8
+
9
+ ## 0.1.2
10
+
11
+ ### Patch Changes
12
+
13
+ - Modified: MockMenuService.
14
+
15
+ ## 0.1.1
16
+
17
+ ### Patch Changes
18
+
19
+ - Modified: ILocalizable.
20
+
21
+ ## 0.1.0
22
+
23
+ ### Minor Changes
24
+
25
+ - Added: splat routes.
26
+ - Added: variants.
27
+
28
+ ## 0.0.1
29
+
30
+ ### Patch Changes
31
+
32
+ - Added: first release.
package/dist/index.d.ts CHANGED
@@ -95,8 +95,8 @@ type ICategory = IEntity & {
95
95
  id: IEquatable;
96
96
  media?: IMedia;
97
97
  order?: number;
98
- slug?: ILocalizable;
99
- title?: ILocalizable;
98
+ slug: ILocalizable;
99
+ title: ILocalizable;
100
100
  };
101
101
  type ICategoryItem = ICategory & {
102
102
  items: ICategory[];
@@ -110,10 +110,12 @@ type ICategorized = {
110
110
  media?: IMedia;
111
111
  order?: number;
112
112
  schema?: string;
113
- slug?: ILocalizable;
113
+ slug: ILocalizable;
114
114
  template?: string;
115
- title?: ILocalizable;
115
+ title: ILocalizable;
116
116
  useSplat?: boolean;
117
+ createdAt?: Date;
118
+ updatedAt?: Date;
117
119
  };
118
120
 
119
121
  type IClassNameValue = string | boolean | number | null | undefined;
@@ -148,16 +150,18 @@ type ILocale = IEntity & {
148
150
  title?: string;
149
151
  isActive?: boolean;
150
152
  isDefault?: boolean;
153
+ isHidden?: boolean;
151
154
  };
152
155
 
153
156
  type IMarket = IEntity & {
154
157
  id: string;
155
158
  title?: string;
156
- isActive?: boolean;
157
- isDefault?: boolean;
158
159
  countries?: string[];
159
160
  languages?: string[];
160
161
  defaultLanguage?: string;
162
+ isActive?: boolean;
163
+ isDefault?: boolean;
164
+ isHidden?: boolean;
161
165
  };
162
166
 
163
167
  type IMeta = {
@@ -178,7 +182,12 @@ type IRoute = {
178
182
  schema: string;
179
183
  template?: string;
180
184
  title: string;
185
+ media?: IMedia;
181
186
  useSplat?: boolean;
187
+ updatedAt?: Date;
188
+ };
189
+ type IRouteCanonical = IRoute & {
190
+ alternates: IRoute[];
182
191
  };
183
192
  type IRouteLink = {
184
193
  href: string;
@@ -194,18 +203,18 @@ type IRouteParams = Record<string, any> & {
194
203
  };
195
204
 
196
205
  type IPage = Record<string, any> & ICategorized & {
197
- slug?: string;
198
- href: string;
206
+ abstract?: string;
199
207
  alternates: IRoute[];
200
208
  breadcrumb: IRouteLink[];
201
- parentRoute?: IRouteLink;
202
- title?: string;
203
- abstract?: string;
204
- description?: string;
205
209
  content?: string;
206
- createdAt?: Date;
207
- updatedAt?: Date;
210
+ description?: string;
211
+ href: string;
212
+ locale: string;
213
+ market: string;
208
214
  meta?: IMeta;
215
+ parentRoute?: IRouteLink;
216
+ slug: string;
217
+ title: string;
209
218
  };
210
219
  type IPageRelation = {
211
220
  relationTo: string;
@@ -382,7 +391,24 @@ type FindWhereParams = {
382
391
  };
383
392
  declare function toFindParams(idOrParams: IEquatable | FindWhereParams): FindWhereParams;
384
393
 
385
- type IMemoryStore = Record<string, IEntity[]>;
394
+ declare enum RedirectReason {
395
+ MovedPermanently = "301",
396
+ Found = "302",
397
+ TemporaryRedirect = "307",
398
+ PermanentRedirect = "308",
399
+ Gone = "410"
400
+ }
401
+ type IRedirect = {
402
+ id: IEquatable;
403
+ status: RedirectReason;
404
+ from: string;
405
+ to?: string;
406
+ name?: string;
407
+ order?: number;
408
+ isActive: boolean;
409
+ };
410
+
411
+ type IMemoryStore<T extends IEntity = IEntity> = Record<string, T[]>;
386
412
  type IStore = Record<string, IQuerable<IEntity>>;
387
413
  type IConfig = {
388
414
  collections: string[];
@@ -416,6 +442,12 @@ type ITemplate = {
416
442
  collections: string[];
417
443
  };
418
444
 
445
+ declare function isCategory(value?: ICategory | IEquatable): value is ICategory;
446
+ declare function asCategoryId(value?: ICategory | IEquatable): string | undefined;
447
+ declare function getParentCategoriesById(id: string | undefined, categories: ICategory[]): ICategory[];
448
+ declare function getCategorySegments(item: ICategorized, categories: ICategory[]): ICategory[];
449
+ declare function getCategorySegmentsByCategory(item: ICategory, categories: ICategory[]): ICategory[];
450
+
419
451
  declare function getClassNames(...props: Array<IClassName>): string;
420
452
 
421
453
  declare function getCollectionDescription(text: string): ICollectionDescription;
@@ -465,6 +497,7 @@ declare class JsonService<T extends IEntity = IEntity> implements IQuerable<T> {
465
497
 
466
498
  declare function isLocalizedString(value: any): value is ILocalizedString;
467
499
  declare function localizedToString(json: ILocalizedString, locale?: string, defaultLocale?: string): string;
500
+ declare function localize(value: ILocalizable, locale?: string, defaultLocale?: string): string;
468
501
  declare function localizeValue(value: any, locale?: string, defaultLocale?: string): any;
469
502
  declare function localizeItem(item: any, locale?: string, defaultLocale?: string): any;
470
503
 
@@ -474,10 +507,23 @@ declare function deserializeValue(value: string): string | boolean | number;
474
507
  declare function deserializeKey(value: string): string | number;
475
508
  declare function qsDeserialize(query?: string, deserializedParams?: {}): QueryParams;
476
509
 
477
- declare function titleToSlug(title: string): string;
510
+ declare function collectRoutes(store: IMemoryStore<ICategorized>, categories: ICategory[], markets: IMarket[], locales: ILocale[]): IRoute[];
511
+ declare function eachMarketLocale(markets: IMarket[], locales: ILocale[], callback: (market: IMarket, locale: ILocale, markets: IMarket[], locales: ILocale[]) => void): void;
512
+ declare function eachCategorized(store: IMemoryStore<ICategorized>, callback: (item: ICategorized, key: string) => void): void;
513
+ declare enum RouteStrategy {
514
+ Auto = "auto",
515
+ Default = "default",
516
+ Manual = "manual"
517
+ }
518
+ declare function getRouteHref(segments: ICategory[], market: IMarket, locale: ILocale, markets: IMarket[], locales: ILocale[]): string;
519
+
520
+ declare function textToSlug(title: string): string;
478
521
 
479
522
  declare function getIsDevelopment(): boolean;
523
+ declare function getIsProduction(): boolean;
480
524
  declare const isDevelopment: boolean;
525
+ declare const isProduction: boolean;
526
+ declare const isStage: boolean;
481
527
  declare const isBrowser: boolean;
482
528
  declare function withSchema<Component extends {}, Schema>(component: Component, schema: Schema): Component & Schema;
483
529
  declare function asServerProps(props: any): any;
@@ -485,4 +531,4 @@ declare function awaitAll(array: any, callback: (item: any, index: number) => Pr
485
531
  declare function merge(target: any, source: any): any;
486
532
  declare function deepCopy<T>(source: T): T;
487
533
 
488
- export { FetchRequestOptions, FetchService, FindParams, FindWhereParams, ICategorized, ICategory, ICategoryItem, IClassName, IClassNameCollection, IClassNameValue, ICollectionDescription, IConfig, IContextBaseParams, IContextParams, IEntity, IEquatable, ILabel, ILayout, ILocale, ILocalizable, ILocalized, ILocalizedString, IMarket, IMedia, IMediaType, IMemoryStore, IMenu, IMenuBase, IMenuCategory, IMenuCustom, IMenuGroup, IMenuItem, IMenuLink, IMenuPage, IMenuRoute, INamedEntity, IOption, IOverride, IPackages, IPage, IPageRelation, IPageResult, IPartial, IPrettify, IQuerable, IRoute, IRouteLink, IRouteParams, ISchema, ISerializedCollection, ISerializedStore, IServerSideContext, IServerSideSplatContext, IStaticContext, IStore, ITemplate, ITitledEntity, IUndecoratedMenu, IUndecoratedMenuBase, IUndecoratedMenuCategory, IUndecoratedMenuCustom, IUndecoratedMenuGroup, IUndecoratedMenuItem, IUndecoratedMenuLink, IUndecoratedMenuPage, Json, JsonService, LiteralUnion, NextApiRequestCookies, Operator, PageProps, Pagination, PreviewData, QueryParams, SchemaType, ServerSidePropsContext, StateValue, StaticPropsContext, ValueOf, Where, WhereAndOr, WhereBase, WhereField, asEquatable, asServerProps, awaitAll, camelToSnakeCase, consoleWarn, deepCopy, deserializeKey, deserializeValue, getClassNames, getCollectionDescription, getIsDevelopment, httpDelete, httpFetch, httpGet, httpPatch, httpPost, httpPut, isBrowser, isDevelopment, isLocalizedString, isValidCollectionDescription, localizeItem, localizeValue, localizedToString, merge, qsDeserialize, qsSerialize, titleToSlug, toDisplayName, toFindParams, toPluralName, toTitleCase, toValidCollectionName, withSchema };
534
+ export { FetchRequestOptions, FetchService, FindParams, FindWhereParams, ICategorized, ICategory, ICategoryItem, IClassName, IClassNameCollection, IClassNameValue, ICollectionDescription, IConfig, IContextBaseParams, IContextParams, IEntity, IEquatable, ILabel, ILayout, ILocale, ILocalizable, ILocalized, ILocalizedString, IMarket, IMedia, IMediaType, IMemoryStore, IMenu, IMenuBase, IMenuCategory, IMenuCustom, IMenuGroup, IMenuItem, IMenuLink, IMenuPage, IMenuRoute, INamedEntity, IOption, IOverride, IPackages, IPage, IPageRelation, IPageResult, IPartial, IPrettify, IQuerable, IRedirect, IRoute, IRouteCanonical, IRouteLink, IRouteParams, ISchema, ISerializedCollection, ISerializedStore, IServerSideContext, IServerSideSplatContext, IStaticContext, IStore, ITemplate, ITitledEntity, IUndecoratedMenu, IUndecoratedMenuBase, IUndecoratedMenuCategory, IUndecoratedMenuCustom, IUndecoratedMenuGroup, IUndecoratedMenuItem, IUndecoratedMenuLink, IUndecoratedMenuPage, Json, JsonService, LiteralUnion, NextApiRequestCookies, Operator, PageProps, Pagination, PreviewData, QueryParams, RedirectReason, RouteStrategy, SchemaType, ServerSidePropsContext, StateValue, StaticPropsContext, ValueOf, Where, WhereAndOr, WhereBase, WhereField, asCategoryId, asEquatable, asServerProps, awaitAll, camelToSnakeCase, collectRoutes, consoleWarn, deepCopy, deserializeKey, deserializeValue, eachCategorized, eachMarketLocale, getCategorySegments, getCategorySegmentsByCategory, getClassNames, getCollectionDescription, getIsDevelopment, getIsProduction, getParentCategoriesById, getRouteHref, httpDelete, httpFetch, httpGet, httpPatch, httpPost, httpPut, isBrowser, isCategory, isDevelopment, isLocalizedString, isProduction, isStage, isValidCollectionDescription, localize, localizeItem, localizeValue, localizedToString, merge, qsDeserialize, qsSerialize, textToSlug, toDisplayName, toFindParams, toPluralName, toTitleCase, toValidCollectionName, withSchema };
package/dist/index.js CHANGED
@@ -31,17 +31,28 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
31
31
  var src_exports = {};
32
32
  __export(src_exports, {
33
33
  JsonService: () => JsonService,
34
+ RedirectReason: () => RedirectReason,
35
+ RouteStrategy: () => RouteStrategy,
36
+ asCategoryId: () => asCategoryId,
34
37
  asEquatable: () => asEquatable,
35
38
  asServerProps: () => asServerProps,
36
39
  awaitAll: () => awaitAll,
37
40
  camelToSnakeCase: () => camelToSnakeCase,
41
+ collectRoutes: () => collectRoutes,
38
42
  consoleWarn: () => consoleWarn,
39
43
  deepCopy: () => deepCopy,
40
44
  deserializeKey: () => deserializeKey,
41
45
  deserializeValue: () => deserializeValue,
46
+ eachCategorized: () => eachCategorized,
47
+ eachMarketLocale: () => eachMarketLocale,
48
+ getCategorySegments: () => getCategorySegments,
49
+ getCategorySegmentsByCategory: () => getCategorySegmentsByCategory,
42
50
  getClassNames: () => getClassNames,
43
51
  getCollectionDescription: () => getCollectionDescription,
44
52
  getIsDevelopment: () => getIsDevelopment,
53
+ getIsProduction: () => getIsProduction,
54
+ getParentCategoriesById: () => getParentCategoriesById,
55
+ getRouteHref: () => getRouteHref,
45
56
  httpDelete: () => httpDelete,
46
57
  httpFetch: () => httpFetch,
47
58
  httpGet: () => httpGet,
@@ -49,16 +60,20 @@ __export(src_exports, {
49
60
  httpPost: () => httpPost,
50
61
  httpPut: () => httpPut,
51
62
  isBrowser: () => isBrowser,
63
+ isCategory: () => isCategory,
52
64
  isDevelopment: () => isDevelopment,
53
65
  isLocalizedString: () => isLocalizedString,
66
+ isProduction: () => isProduction,
67
+ isStage: () => isStage,
54
68
  isValidCollectionDescription: () => isValidCollectionDescription,
69
+ localize: () => localize,
55
70
  localizeItem: () => localizeItem,
56
71
  localizeValue: () => localizeValue,
57
72
  localizedToString: () => localizedToString,
58
73
  merge: () => merge,
59
74
  qsDeserialize: () => qsDeserialize,
60
75
  qsSerialize: () => qsSerialize,
61
- titleToSlug: () => titleToSlug,
76
+ textToSlug: () => textToSlug,
62
77
  toDisplayName: () => toDisplayName,
63
78
  toFindParams: () => toFindParams,
64
79
  toPluralName: () => toPluralName,
@@ -68,6 +83,65 @@ __export(src_exports, {
68
83
  });
69
84
  module.exports = __toCommonJS(src_exports);
70
85
 
86
+ // src/category/category.ts
87
+ function isCategory(value) {
88
+ return Boolean(value) && typeof value === "object";
89
+ }
90
+ function asCategoryId(value) {
91
+ return isCategory(value) ? value.id : value;
92
+ }
93
+ function getParentCategoriesById(id, categories) {
94
+ const routeCategories = [];
95
+ const segments = [];
96
+ let parentId = id || null;
97
+ while (parentId != null) {
98
+ const parentCategory = categories.find((c) => c.id === parentId);
99
+ if (parentCategory) {
100
+ if (parentCategory.slug) {
101
+ const segment = { ...parentCategory };
102
+ segments.unshift(segment);
103
+ }
104
+ parentId = asCategoryId(parentCategory.category) || null;
105
+ if (parentId) {
106
+ if (routeCategories.includes(parentId)) {
107
+ console.log("ICategory.getParentCategoriesById", "circular reference found", parentId);
108
+ parentId = null;
109
+ } else {
110
+ routeCategories.push(parentId);
111
+ }
112
+ }
113
+ } else {
114
+ parentId = null;
115
+ }
116
+ }
117
+ return segments;
118
+ }
119
+ function getCategorySegments(item, categories) {
120
+ const categoryId = asCategoryId(item.category);
121
+ const segments = getParentCategoriesById(categoryId, categories);
122
+ [];
123
+ if (item.isDefault !== true) {
124
+ const category = categories.find((x) => x.id === item.category);
125
+ if (category) {
126
+ const segment = {
127
+ id: item.id,
128
+ title: item.title,
129
+ slug: item.slug,
130
+ media: item.media || category.media,
131
+ category
132
+ };
133
+ segments.push(segment);
134
+ }
135
+ }
136
+ return segments;
137
+ }
138
+ function getCategorySegmentsByCategory(item, categories) {
139
+ const categoryId = asCategoryId(item.category);
140
+ const segments = getParentCategoriesById(categoryId, categories);
141
+ segments.push(item);
142
+ return segments;
143
+ }
144
+
71
145
  // src/classNames/classNames.ts
72
146
  function isClassNameCollection(value) {
73
147
  return typeof value === "object" && !Array.isArray(value);
@@ -169,7 +243,12 @@ function consoleWarn(message, component) {
169
243
  function getIsDevelopment() {
170
244
  return process && (!process.env.NODE_ENV || process.env.NODE_ENV === "development");
171
245
  }
246
+ function getIsProduction() {
247
+ return process && process.env && String(process.env.PRODUCTION) === "true";
248
+ }
172
249
  var isDevelopment = getIsDevelopment();
250
+ var isProduction = getIsProduction();
251
+ var isStage = !isProduction && !isDevelopment;
173
252
  var isBrowser = typeof window !== "undefined";
174
253
  function withSchema(component, schema) {
175
254
  return Object.assign(component, schema);
@@ -445,14 +524,14 @@ var JsonService = class {
445
524
  const key = sort.replace(/^-/, "");
446
525
  items = [...items];
447
526
  items.sort((a, b) => {
448
- const aValue = String(a[key]);
449
- const bValue = String(b[key]);
450
- if (aValue.localeCompare(bValue) < 0) {
451
- return -1 * reverse;
452
- } else if (aValue.localeCompare(bValue) > 0) {
453
- return 1 * reverse;
527
+ const aValue = a[key];
528
+ const bValue = b[key];
529
+ if (typeof aValue === "number" && typeof bValue === "number") {
530
+ return (aValue - bValue) * reverse;
454
531
  }
455
- return 0;
532
+ const aStringValue = String(aValue);
533
+ const bStringValue = String(bValue);
534
+ return aStringValue.localeCompare(bStringValue) * reverse;
456
535
  });
457
536
  }
458
537
  return items;
@@ -501,6 +580,9 @@ function localizedToString(json, locale = "en", defaultLocale = "en") {
501
580
  const localizedString = json[locale] || json[defaultLocale] || Object.values(json)[0];
502
581
  return localizedString;
503
582
  }
583
+ function localize(value, locale = "en", defaultLocale = "en") {
584
+ return isLocalizedString(value) ? localizedToString(value, locale, defaultLocale) : value;
585
+ }
504
586
  function localizeValue(value, locale = "en", defaultLocale = "en") {
505
587
  if (value) {
506
588
  if (isLocalizedString(value)) {
@@ -622,8 +704,124 @@ function qsDeserialize(query = "", deserializedParams = {}) {
622
704
  return deserializedParams;
623
705
  }
624
706
 
707
+ // src/route/route.ts
708
+ function collectRoutes(store, categories, markets, locales) {
709
+ const routes = [];
710
+ if (locales.length > 0 && markets.length > 0) {
711
+ const firstTopCategory = categories.find((x) => x.category === void 0);
712
+ eachCategorized(store, (item, key) => {
713
+ const segments = getCategorySegments(item, categories);
714
+ eachMarketLocale(markets, locales, (market, locale, markets2, locales2) => {
715
+ if (!item.markets || item.markets.includes(market.id)) {
716
+ const title = localize(item.title, locale.id);
717
+ const id = getRouteHref(segments, market, locale, markets2, locales2);
718
+ const route = {
719
+ id,
720
+ market: market.id,
721
+ locale: locale.id,
722
+ category: item.category,
723
+ page: item.id,
724
+ schema: key,
725
+ template: item.template,
726
+ title,
727
+ isDefault: item.isDefault,
728
+ order: item.order,
729
+ useSplat: item.useSplat,
730
+ updatedAt: item.updatedAt
731
+ };
732
+ routes.push(route);
733
+ }
734
+ });
735
+ if (firstTopCategory && item.category === firstTopCategory.id) {
736
+ const defaultLocale = locales.find((x) => x.isDefault) || locales[0];
737
+ const defaultMarket = markets.find((x) => x.isDefault) || markets[0];
738
+ const defaultMarketLocale = defaultMarket && defaultMarket.defaultLanguage ? defaultMarket.defaultLanguage : defaultLocale.id;
739
+ const title = localize(item.title, defaultMarketLocale);
740
+ const route = {
741
+ id: "/",
742
+ market: defaultMarket.id,
743
+ locale: defaultMarketLocale,
744
+ category: item.category,
745
+ page: item.id,
746
+ schema: key,
747
+ template: item.template,
748
+ title,
749
+ isDefault: item.isDefault,
750
+ order: item.order,
751
+ useSplat: item.useSplat,
752
+ updatedAt: item.updatedAt
753
+ };
754
+ routes.push(route);
755
+ }
756
+ });
757
+ }
758
+ return routes;
759
+ }
760
+ function eachMarketLocale(markets, locales, callback) {
761
+ locales = locales.filter((x) => x.isActive !== false);
762
+ markets = markets.filter((x) => x.isActive !== false);
763
+ markets.forEach((market) => {
764
+ const marketLocales = market.languages && market.languages.length > 0 ? market.languages.map((id) => locales.find((x) => x.id === id)).filter((x) => x !== void 0) : locales;
765
+ marketLocales.forEach((locale) => {
766
+ callback(market, locale, markets, locales);
767
+ });
768
+ });
769
+ }
770
+ function eachCategorized(store, callback) {
771
+ const keys = Object.keys(store);
772
+ for (const key of keys) {
773
+ const items = store[key];
774
+ for (const item of items) {
775
+ callback(item, key);
776
+ }
777
+ }
778
+ }
779
+ var RouteStrategy = /* @__PURE__ */ ((RouteStrategy2) => {
780
+ RouteStrategy2["Auto"] = "auto";
781
+ RouteStrategy2["Default"] = "default";
782
+ RouteStrategy2["Manual"] = "manual";
783
+ return RouteStrategy2;
784
+ })(RouteStrategy || {});
785
+ var ROUTE_STRATEGY = process.env.ROUTE_STRATEGY || "auto" /* Auto */;
786
+ function getRouteHref(segments, market, locale, markets, locales) {
787
+ const href = segments.reduce((p, c, i) => {
788
+ let slug = localize(c.slug || "", locale.id);
789
+ slug = `${p}/${slug}`;
790
+ return slug === "/" ? "" : slug;
791
+ }, "");
792
+ const prefixes = [];
793
+ switch (ROUTE_STRATEGY) {
794
+ case "auto" /* Auto */:
795
+ if (locales.length > 1 || markets.length > 1) {
796
+ prefixes.push(locale.id);
797
+ }
798
+ if (markets.length > 1) {
799
+ prefixes.push(market.id);
800
+ }
801
+ break;
802
+ case "default" /* Default */:
803
+ if (locale.isDefault !== true) {
804
+ prefixes.push(locale.id);
805
+ }
806
+ if (market.isDefault !== true) {
807
+ prefixes.push(market.id);
808
+ }
809
+ break;
810
+ case "manual" /* Manual */:
811
+ if (locale.isHidden !== true) {
812
+ prefixes.push(locale.id);
813
+ }
814
+ if (market.isHidden !== true) {
815
+ prefixes.push(market.id);
816
+ }
817
+ break;
818
+ }
819
+ const prefix = prefixes.length ? `/${prefixes.join("-")}` : "";
820
+ return `${prefix}${href}`;
821
+ }
822
+
625
823
  // src/slug/slug.ts
626
- function titleToSlug(title) {
824
+ function textToSlug(title) {
627
825
  return title.toString().normalize("NFD").replace(/[\u0300-\u036f]/g, "").toLowerCase().replace(/\s+/g, "-").replace(/&/g, "-and-").replace(/[^\w-]+/g, "").replace(/--+/g, "-").replace(/^-+/, "").replace(/-+$/, "");
628
826
  }
629
827
 
@@ -635,20 +833,41 @@ function toFindParams(idOrParams) {
635
833
  return idOrParams;
636
834
  }
637
835
  }
836
+
837
+ // src/types/redirect.ts
838
+ var RedirectReason = /* @__PURE__ */ ((RedirectReason2) => {
839
+ RedirectReason2["MovedPermanently"] = "301";
840
+ RedirectReason2["Found"] = "302";
841
+ RedirectReason2["TemporaryRedirect"] = "307";
842
+ RedirectReason2["PermanentRedirect"] = "308";
843
+ RedirectReason2["Gone"] = "410";
844
+ return RedirectReason2;
845
+ })(RedirectReason || {});
638
846
  // Annotate the CommonJS export names for ESM import in node:
639
847
  0 && (module.exports = {
640
848
  JsonService,
849
+ RedirectReason,
850
+ RouteStrategy,
851
+ asCategoryId,
641
852
  asEquatable,
642
853
  asServerProps,
643
854
  awaitAll,
644
855
  camelToSnakeCase,
856
+ collectRoutes,
645
857
  consoleWarn,
646
858
  deepCopy,
647
859
  deserializeKey,
648
860
  deserializeValue,
861
+ eachCategorized,
862
+ eachMarketLocale,
863
+ getCategorySegments,
864
+ getCategorySegmentsByCategory,
649
865
  getClassNames,
650
866
  getCollectionDescription,
651
867
  getIsDevelopment,
868
+ getIsProduction,
869
+ getParentCategoriesById,
870
+ getRouteHref,
652
871
  httpDelete,
653
872
  httpFetch,
654
873
  httpGet,
@@ -656,16 +875,20 @@ function toFindParams(idOrParams) {
656
875
  httpPost,
657
876
  httpPut,
658
877
  isBrowser,
878
+ isCategory,
659
879
  isDevelopment,
660
880
  isLocalizedString,
881
+ isProduction,
882
+ isStage,
661
883
  isValidCollectionDescription,
884
+ localize,
662
885
  localizeItem,
663
886
  localizeValue,
664
887
  localizedToString,
665
888
  merge,
666
889
  qsDeserialize,
667
890
  qsSerialize,
668
- titleToSlug,
891
+ textToSlug,
669
892
  toDisplayName,
670
893
  toFindParams,
671
894
  toPluralName,
package/dist/index.mjs CHANGED
@@ -1,3 +1,62 @@
1
+ // src/category/category.ts
2
+ function isCategory(value) {
3
+ return Boolean(value) && typeof value === "object";
4
+ }
5
+ function asCategoryId(value) {
6
+ return isCategory(value) ? value.id : value;
7
+ }
8
+ function getParentCategoriesById(id, categories) {
9
+ const routeCategories = [];
10
+ const segments = [];
11
+ let parentId = id || null;
12
+ while (parentId != null) {
13
+ const parentCategory = categories.find((c) => c.id === parentId);
14
+ if (parentCategory) {
15
+ if (parentCategory.slug) {
16
+ const segment = { ...parentCategory };
17
+ segments.unshift(segment);
18
+ }
19
+ parentId = asCategoryId(parentCategory.category) || null;
20
+ if (parentId) {
21
+ if (routeCategories.includes(parentId)) {
22
+ console.log("ICategory.getParentCategoriesById", "circular reference found", parentId);
23
+ parentId = null;
24
+ } else {
25
+ routeCategories.push(parentId);
26
+ }
27
+ }
28
+ } else {
29
+ parentId = null;
30
+ }
31
+ }
32
+ return segments;
33
+ }
34
+ function getCategorySegments(item, categories) {
35
+ const categoryId = asCategoryId(item.category);
36
+ const segments = getParentCategoriesById(categoryId, categories);
37
+ [];
38
+ if (item.isDefault !== true) {
39
+ const category = categories.find((x) => x.id === item.category);
40
+ if (category) {
41
+ const segment = {
42
+ id: item.id,
43
+ title: item.title,
44
+ slug: item.slug,
45
+ media: item.media || category.media,
46
+ category
47
+ };
48
+ segments.push(segment);
49
+ }
50
+ }
51
+ return segments;
52
+ }
53
+ function getCategorySegmentsByCategory(item, categories) {
54
+ const categoryId = asCategoryId(item.category);
55
+ const segments = getParentCategoriesById(categoryId, categories);
56
+ segments.push(item);
57
+ return segments;
58
+ }
59
+
1
60
  // src/classNames/classNames.ts
2
61
  function isClassNameCollection(value) {
3
62
  return typeof value === "object" && !Array.isArray(value);
@@ -99,7 +158,12 @@ function consoleWarn(message, component) {
99
158
  function getIsDevelopment() {
100
159
  return process && (!process.env.NODE_ENV || process.env.NODE_ENV === "development");
101
160
  }
161
+ function getIsProduction() {
162
+ return process && process.env && String(process.env.PRODUCTION) === "true";
163
+ }
102
164
  var isDevelopment = getIsDevelopment();
165
+ var isProduction = getIsProduction();
166
+ var isStage = !isProduction && !isDevelopment;
103
167
  var isBrowser = typeof window !== "undefined";
104
168
  function withSchema(component, schema) {
105
169
  return Object.assign(component, schema);
@@ -375,14 +439,14 @@ var JsonService = class {
375
439
  const key = sort.replace(/^-/, "");
376
440
  items = [...items];
377
441
  items.sort((a, b) => {
378
- const aValue = String(a[key]);
379
- const bValue = String(b[key]);
380
- if (aValue.localeCompare(bValue) < 0) {
381
- return -1 * reverse;
382
- } else if (aValue.localeCompare(bValue) > 0) {
383
- return 1 * reverse;
442
+ const aValue = a[key];
443
+ const bValue = b[key];
444
+ if (typeof aValue === "number" && typeof bValue === "number") {
445
+ return (aValue - bValue) * reverse;
384
446
  }
385
- return 0;
447
+ const aStringValue = String(aValue);
448
+ const bStringValue = String(bValue);
449
+ return aStringValue.localeCompare(bStringValue) * reverse;
386
450
  });
387
451
  }
388
452
  return items;
@@ -431,6 +495,9 @@ function localizedToString(json, locale = "en", defaultLocale = "en") {
431
495
  const localizedString = json[locale] || json[defaultLocale] || Object.values(json)[0];
432
496
  return localizedString;
433
497
  }
498
+ function localize(value, locale = "en", defaultLocale = "en") {
499
+ return isLocalizedString(value) ? localizedToString(value, locale, defaultLocale) : value;
500
+ }
434
501
  function localizeValue(value, locale = "en", defaultLocale = "en") {
435
502
  if (value) {
436
503
  if (isLocalizedString(value)) {
@@ -552,8 +619,124 @@ function qsDeserialize(query = "", deserializedParams = {}) {
552
619
  return deserializedParams;
553
620
  }
554
621
 
622
+ // src/route/route.ts
623
+ function collectRoutes(store, categories, markets, locales) {
624
+ const routes = [];
625
+ if (locales.length > 0 && markets.length > 0) {
626
+ const firstTopCategory = categories.find((x) => x.category === void 0);
627
+ eachCategorized(store, (item, key) => {
628
+ const segments = getCategorySegments(item, categories);
629
+ eachMarketLocale(markets, locales, (market, locale, markets2, locales2) => {
630
+ if (!item.markets || item.markets.includes(market.id)) {
631
+ const title = localize(item.title, locale.id);
632
+ const id = getRouteHref(segments, market, locale, markets2, locales2);
633
+ const route = {
634
+ id,
635
+ market: market.id,
636
+ locale: locale.id,
637
+ category: item.category,
638
+ page: item.id,
639
+ schema: key,
640
+ template: item.template,
641
+ title,
642
+ isDefault: item.isDefault,
643
+ order: item.order,
644
+ useSplat: item.useSplat,
645
+ updatedAt: item.updatedAt
646
+ };
647
+ routes.push(route);
648
+ }
649
+ });
650
+ if (firstTopCategory && item.category === firstTopCategory.id) {
651
+ const defaultLocale = locales.find((x) => x.isDefault) || locales[0];
652
+ const defaultMarket = markets.find((x) => x.isDefault) || markets[0];
653
+ const defaultMarketLocale = defaultMarket && defaultMarket.defaultLanguage ? defaultMarket.defaultLanguage : defaultLocale.id;
654
+ const title = localize(item.title, defaultMarketLocale);
655
+ const route = {
656
+ id: "/",
657
+ market: defaultMarket.id,
658
+ locale: defaultMarketLocale,
659
+ category: item.category,
660
+ page: item.id,
661
+ schema: key,
662
+ template: item.template,
663
+ title,
664
+ isDefault: item.isDefault,
665
+ order: item.order,
666
+ useSplat: item.useSplat,
667
+ updatedAt: item.updatedAt
668
+ };
669
+ routes.push(route);
670
+ }
671
+ });
672
+ }
673
+ return routes;
674
+ }
675
+ function eachMarketLocale(markets, locales, callback) {
676
+ locales = locales.filter((x) => x.isActive !== false);
677
+ markets = markets.filter((x) => x.isActive !== false);
678
+ markets.forEach((market) => {
679
+ const marketLocales = market.languages && market.languages.length > 0 ? market.languages.map((id) => locales.find((x) => x.id === id)).filter((x) => x !== void 0) : locales;
680
+ marketLocales.forEach((locale) => {
681
+ callback(market, locale, markets, locales);
682
+ });
683
+ });
684
+ }
685
+ function eachCategorized(store, callback) {
686
+ const keys = Object.keys(store);
687
+ for (const key of keys) {
688
+ const items = store[key];
689
+ for (const item of items) {
690
+ callback(item, key);
691
+ }
692
+ }
693
+ }
694
+ var RouteStrategy = /* @__PURE__ */ ((RouteStrategy2) => {
695
+ RouteStrategy2["Auto"] = "auto";
696
+ RouteStrategy2["Default"] = "default";
697
+ RouteStrategy2["Manual"] = "manual";
698
+ return RouteStrategy2;
699
+ })(RouteStrategy || {});
700
+ var ROUTE_STRATEGY = process.env.ROUTE_STRATEGY || "auto" /* Auto */;
701
+ function getRouteHref(segments, market, locale, markets, locales) {
702
+ const href = segments.reduce((p, c, i) => {
703
+ let slug = localize(c.slug || "", locale.id);
704
+ slug = `${p}/${slug}`;
705
+ return slug === "/" ? "" : slug;
706
+ }, "");
707
+ const prefixes = [];
708
+ switch (ROUTE_STRATEGY) {
709
+ case "auto" /* Auto */:
710
+ if (locales.length > 1 || markets.length > 1) {
711
+ prefixes.push(locale.id);
712
+ }
713
+ if (markets.length > 1) {
714
+ prefixes.push(market.id);
715
+ }
716
+ break;
717
+ case "default" /* Default */:
718
+ if (locale.isDefault !== true) {
719
+ prefixes.push(locale.id);
720
+ }
721
+ if (market.isDefault !== true) {
722
+ prefixes.push(market.id);
723
+ }
724
+ break;
725
+ case "manual" /* Manual */:
726
+ if (locale.isHidden !== true) {
727
+ prefixes.push(locale.id);
728
+ }
729
+ if (market.isHidden !== true) {
730
+ prefixes.push(market.id);
731
+ }
732
+ break;
733
+ }
734
+ const prefix = prefixes.length ? `/${prefixes.join("-")}` : "";
735
+ return `${prefix}${href}`;
736
+ }
737
+
555
738
  // src/slug/slug.ts
556
- function titleToSlug(title) {
739
+ function textToSlug(title) {
557
740
  return title.toString().normalize("NFD").replace(/[\u0300-\u036f]/g, "").toLowerCase().replace(/\s+/g, "-").replace(/&/g, "-and-").replace(/[^\w-]+/g, "").replace(/--+/g, "-").replace(/^-+/, "").replace(/-+$/, "");
558
741
  }
559
742
 
@@ -565,19 +748,40 @@ function toFindParams(idOrParams) {
565
748
  return idOrParams;
566
749
  }
567
750
  }
751
+
752
+ // src/types/redirect.ts
753
+ var RedirectReason = /* @__PURE__ */ ((RedirectReason2) => {
754
+ RedirectReason2["MovedPermanently"] = "301";
755
+ RedirectReason2["Found"] = "302";
756
+ RedirectReason2["TemporaryRedirect"] = "307";
757
+ RedirectReason2["PermanentRedirect"] = "308";
758
+ RedirectReason2["Gone"] = "410";
759
+ return RedirectReason2;
760
+ })(RedirectReason || {});
568
761
  export {
569
762
  JsonService,
763
+ RedirectReason,
764
+ RouteStrategy,
765
+ asCategoryId,
570
766
  asEquatable,
571
767
  asServerProps,
572
768
  awaitAll,
573
769
  camelToSnakeCase,
770
+ collectRoutes,
574
771
  consoleWarn,
575
772
  deepCopy,
576
773
  deserializeKey,
577
774
  deserializeValue,
775
+ eachCategorized,
776
+ eachMarketLocale,
777
+ getCategorySegments,
778
+ getCategorySegmentsByCategory,
578
779
  getClassNames,
579
780
  getCollectionDescription,
580
781
  getIsDevelopment,
782
+ getIsProduction,
783
+ getParentCategoriesById,
784
+ getRouteHref,
581
785
  httpDelete,
582
786
  httpFetch,
583
787
  httpGet,
@@ -585,16 +789,20 @@ export {
585
789
  httpPost,
586
790
  httpPut,
587
791
  isBrowser,
792
+ isCategory,
588
793
  isDevelopment,
589
794
  isLocalizedString,
795
+ isProduction,
796
+ isStage,
590
797
  isValidCollectionDescription,
798
+ localize,
591
799
  localizeItem,
592
800
  localizeValue,
593
801
  localizedToString,
594
802
  merge,
595
803
  qsDeserialize,
596
804
  qsSerialize,
597
- titleToSlug,
805
+ textToSlug,
598
806
  toDisplayName,
599
807
  toFindParams,
600
808
  toPluralName,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@websolutespa/bom-core",
3
- "version": "0.1.2",
3
+ "version": "0.2.0",
4
4
  "description": "Core module of the BOM Repository",
5
5
  "keywords": [
6
6
  "bom",
@@ -22,9 +22,11 @@
22
22
  "prepack": "bom prepack",
23
23
  "postpack": "bom postpack"
24
24
  },
25
+ "dependencies": {
26
+ "pluralize": "latest"
27
+ },
25
28
  "peerDependencies": {
26
- "next": ">= 12.3.2",
27
- "pluralize": ">= 8.0.0"
29
+ "next": ">= 12.3.2"
28
30
  },
29
31
  "devDependencies": {
30
32
  "@websolutespa/bom-cli": "*",