-
Notifications
You must be signed in to change notification settings - Fork 4
BBD-451: Update URL beautifiers to support full URL spec #199
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: develop
Are you sure you want to change the base?
Changes from all commits
aa827b9
134988c
c0607b7
d679796
94f2033
e44fb84
24afb53
3d7d52a
25723f9
c8f41c5
87ef216
13691d0
9b68bb0
333816f
ce6137c
ddcece8
7e91190
7ac3de7
3b7493f
82b3c34
4160d21
e989141
5cc4d2c
5d9a161
751ff44
75b87ee
933fa08
806012a
2f6b854
3d92713
1177fac
7b0f697
c9f09de
664a448
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
This file was deleted.
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,112 @@ | ||
| import { Beautifier, BeautifierConfig, Detail } from './interfaces'; | ||
| import { SelectedValueRefinement } from 'groupby-api'; | ||
|
|
||
| export class DetailUrlGenerator { | ||
| config: BeautifierConfig; | ||
|
|
||
| constructor({ config }: Beautifier) { | ||
| this.config = config; | ||
| } | ||
|
|
||
| build(detail: Detail): string { | ||
| let paths = [detail.productTitle]; | ||
|
|
||
| if (detail.refinements.length !== 0) { | ||
| if (this.config.useReferenceKeys) { | ||
| let referenceKeys = ''; | ||
| const refinementsToKeys = this.config.refinementMapping.reduce((map, mapping) => { | ||
| const key = Object.keys(mapping)[0]; | ||
| map[mapping[key]] = key; | ||
| return map; | ||
| }, {}); | ||
|
|
||
| detail.refinements.sort(DetailUrlGenerator.refinementsComparator) | ||
| .forEach((refinement) => { | ||
| if (!(refinement.navigationName in refinementsToKeys)) { | ||
| throw new Error(`no mapping found for navigation '${refinement.navigationName}'`); | ||
| } | ||
|
|
||
| paths.push(refinement.value); | ||
| referenceKeys += refinementsToKeys[refinement.navigationName]; | ||
| }); | ||
|
|
||
| paths.push(referenceKeys); | ||
| } else { | ||
| detail.refinements.forEach(({ value, navigationName }) => paths.push(value, navigationName)); | ||
| } | ||
| } | ||
|
|
||
| paths.push(detail.productId); | ||
| return `/${paths.map((path) => encodeURIComponent(path.replace(/\s/g, '-'))).join('/')}`; | ||
| } | ||
|
|
||
| static refinementsComparator(refinement1: SelectedValueRefinement, refinement2: SelectedValueRefinement): number { | ||
| let comparison = refinement1.navigationName.localeCompare(refinement2.navigationName); | ||
| if (comparison === 0) { | ||
| comparison = refinement1.value.localeCompare(refinement2.value); | ||
| } | ||
| return comparison; | ||
| } | ||
| } | ||
|
|
||
| export class DetailUrlParser { | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. make an interface |
||
| config: BeautifierConfig; | ||
|
|
||
| constructor({ config }: Beautifier) { | ||
| this.config = config; | ||
| } | ||
|
|
||
| parse(url: { path: string, query: string}): Detail { | ||
| const paths = url.path.split('/').filter((val) => val).map((val) => decodeURIComponent(val).replace(/-/g, ' ')); | ||
|
|
||
| if (paths.length < 2) { | ||
| throw new Error('path has less than two parts'); | ||
| } | ||
|
|
||
| const name = paths.shift(); | ||
| const id = paths.pop(); | ||
|
|
||
| const refinements = []; | ||
|
|
||
| if (paths.length !== 0) { | ||
| if (!this.config.useReferenceKeys) { | ||
| if (paths.length % 2 !== 0) { | ||
| throw new Error('path has an odd number of parts'); | ||
| } | ||
|
|
||
| while (paths.length !== 0) { | ||
| const value = paths.shift(); | ||
| const navigationName = paths.shift(); | ||
| refinements.push({ navigationName, value, type: 'Value' }); | ||
| } | ||
| } else { | ||
| if (paths.length < 2) { | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. couldn't it have multiple sets of refinements? |
||
| throw new Error('path has wrong number of parts'); | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I would say "path has too few parts" or "path has fewer than two parts"
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I don't think it needs to be changed because the paths in this context excluded productId and productTiltle, so the actual path length is longer than 2. |
||
| } | ||
|
|
||
| const referenceKeys = paths.pop().split(''); | ||
| const keysToRefinements = this.config.refinementMapping.reduce((map, mapping) => { | ||
| const key = Object.keys(mapping)[0]; | ||
| map[key] = mapping[key]; | ||
| return map; | ||
| }, {}); | ||
|
|
||
| if (paths.length !== referenceKeys.length) { | ||
| throw new Error('token reference is invalid'); | ||
| } | ||
|
|
||
| paths.forEach((value) => refinements.push({ | ||
| value, | ||
| navigationName: keysToRefinements[referenceKeys.shift()], | ||
| type: 'Value' | ||
| })); | ||
| } | ||
| } | ||
|
|
||
| return { | ||
| productTitle: name, | ||
| productId: id, | ||
| refinements | ||
| }; | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,17 @@ | ||
| import { DetailUrlGenerator, DetailUrlParser } from './detail-url-beautifier'; | ||
| import { BeautifierConfig, Detail } from './interfaces'; | ||
| import { NavigationUrlGenerator, NavigationUrlParser } from './navigation-url-beautifier'; | ||
| import { QueryUrlGenerator, QueryUrlParser } from './query-url-beautifier'; | ||
| import { UrlBeautifier } from './url-beautifier'; | ||
|
|
||
| export { | ||
| BeautifierConfig, | ||
| Detail, | ||
| DetailUrlGenerator, | ||
| DetailUrlParser, | ||
| NavigationUrlGenerator, | ||
| NavigationUrlParser, | ||
| QueryUrlGenerator, | ||
| QueryUrlParser, | ||
| UrlBeautifier | ||
| }; |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,34 @@ | ||
| import { SearchandiserConfig } from '../../searchandiser'; | ||
| import { SelectedValueRefinement } from 'groupby-api'; | ||
|
|
||
| export interface Beautifier { | ||
| config: BeautifierConfig; | ||
| searchandiserConfig: SearchandiserConfig; | ||
| parse(rawUrl: string): any; | ||
| build(query: any): string; | ||
| } | ||
|
|
||
| export interface BeautifierConfig { | ||
| refinementMapping?: any[]; | ||
| params?: { | ||
| page?: string; | ||
| pageSize?: string; | ||
| refinements?: string; | ||
| sort?: string; | ||
| }; | ||
| queryToken?: string; | ||
| suffix?: string; | ||
| useReferenceKeys?: boolean; | ||
| navigations?: any; | ||
| routes: { | ||
| query: string, | ||
| detail: string, | ||
| navigation: string | ||
| }; | ||
| } | ||
|
|
||
| export interface Detail { | ||
| productTitle: string; | ||
| productId: string; | ||
| refinements: SelectedValueRefinement[]; | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
make an interface