From 206322eb96ddc518f6c29e091b7546558a366e66 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rokas=20Bar=C5=A1auskas?= Date: Wed, 20 Dec 2023 16:43:13 +0200 Subject: [PATCH] Refactoe according to feedback. Reuse templates/components, generate exportables from template files. --- package.json | 1 + scripts/exportTemplates.js | 27 ++++ spec/components/Autocomplete.tsx | 162 ------------------------ spec/liquid.spec.ts | 3 +- spec/mustache.spec.ts | 2 +- spec/react.spec.ts | 2 +- spec/templates/liquid.ts | 101 --------------- spec/templates/mustache.ts | 89 -------------- src/_generated.ts | 190 +++++++++++++++++++++++++++++ src/defaults/Autocomplete.tsx | 5 +- src/defaults/autocomplete.liquid | 17 +-- src/defaults/autocomplete.mustache | 12 +- src/liquid.ts | 101 +-------------- src/mustache.ts | 108 +++------------- tsconfig.json | 1 + 15 files changed, 258 insertions(+), 563 deletions(-) create mode 100644 scripts/exportTemplates.js delete mode 100644 spec/components/Autocomplete.tsx delete mode 100644 spec/templates/liquid.ts delete mode 100644 spec/templates/mustache.ts create mode 100644 src/_generated.ts diff --git a/package.json b/package.json index 9252c59..ab93f6d 100644 --- a/package.json +++ b/package.json @@ -13,6 +13,7 @@ "type": "git", "url": "git+https://github.com/Nosto/nosto-autocomplete.git" }, + "type": "module", "license": "BSD-3-Clause", "author": "Nosto", "main": "dist/nosto-autocomplete.cjs", diff --git a/scripts/exportTemplates.js b/scripts/exportTemplates.js new file mode 100644 index 0000000..1db8f33 --- /dev/null +++ b/scripts/exportTemplates.js @@ -0,0 +1,27 @@ +import * as fs from 'fs' + +// write script that generates const variable string from /src/defaults/autocomplete.liquid +function generateAutocompleteLiquid() { + const autocompleteLiquid = fs.readFileSync('./src/defaults/autocomplete.liquid', 'utf8') + const autocompleteLiquidLines = autocompleteLiquid.split('\n') + const autocompleteLiquidLinesWithConst = `export const defaultLiquidTemplate = \`\n${autocompleteLiquidLines.map(line => ` ${line}`).join('\n')}\n\`\n` + + fs.appendFileSync('./src/_generated.ts', autocompleteLiquidLinesWithConst) +} + +function generateAutocompleteMustache() { + const autocompleteMustache = fs.readFileSync('./src/defaults/autocomplete.mustache', 'utf8') + const autocompleteMustacheLines = autocompleteMustache.split('\n') + const autocompleteMustacheLinesWithConst = `export const defaultMustacheTemplate = \`\n${autocompleteMustacheLines.map(line => ` ${line}`).join('\n')}\n\`\n` + + fs.appendFileSync('./src/_generated.ts', autocompleteMustacheLinesWithConst) +} + +(() => { + if (fs.existsSync('./src/_generated.ts')) { + fs.unlinkSync('./src/_generated.ts') + } + + generateAutocompleteLiquid() + generateAutocompleteMustache() +})() diff --git a/spec/components/Autocomplete.tsx b/spec/components/Autocomplete.tsx deleted file mode 100644 index 594d487..0000000 --- a/spec/components/Autocomplete.tsx +++ /dev/null @@ -1,162 +0,0 @@ -import { SearchKeyword, SearchProduct } from '../../src/api/search' - -interface AutocompleteProps { - response?: { - keywords: { - hits: SearchKeyword[] - } - products: { - hits: SearchProduct[] - } - } - history?: { - item: string - }[] -} - -export function Autocomplete({ response, history }: AutocompleteProps) { - const hasKeywords = !!response?.keywords?.hits?.length - const hasProducts = !!response?.products?.hits?.length - const hasHistory = !!history?.length - - if (!hasKeywords && !hasProducts && !hasHistory) { - return null - } - - return ( -
- {!hasKeywords && !hasProducts && hasHistory ? ( - - ) : hasKeywords || hasProducts ? ( - <> - {hasKeywords && ( - - )} - {hasProducts && ( - - )} -
- -
- , - - ) : null} -
- ) -} - -function History({ history }: { history: AutocompleteProps["history"] }) { - return ( - <> -
-
Recently searched
- {history?.map((hit, index) => { - return ( -
- {hit.item} - - ✕ - -
- ) - })} -
-
- -
- - ) -} - -function Keywords({ keywords }: { keywords: SearchKeyword[] }) { - return ( -
-
Keywords
- {keywords?.map((hit, index) => { - return ( -
- {hit._highlight && hit._highlight.keyword ? ( - - ) : ( - {hit.keyword} - )} -
- ) - })} -
- ) -} - -function Products({ products }: { products: SearchProduct[] }) { - return ( -
-
Products
- {products.map(hit => { - return ( - - {hit.name} -
- {hit.brand && ( -
- {hit.brand} -
- )} -
- {hit.name} -
-
- {hit.price}€ - {hit.listPrice && ( - - {hit.listPrice} - € - - )} -
-
-
- ) - })} -
- ) -} diff --git a/spec/liquid.spec.ts b/spec/liquid.spec.ts index 24cbbcf..c9eac60 100644 --- a/spec/liquid.spec.ts +++ b/spec/liquid.spec.ts @@ -1,9 +1,8 @@ import "@testing-library/jest-dom" import { - fromLiquidTemplate, fromRemoteLiquidTemplate, + fromLiquidTemplate, fromRemoteLiquidTemplate, defaultLiquidTemplate as liquidTemplate } from "../src/liquid" import { handleAutocomplete, hooks, autocompleteSuite } from './suites/autocomplete' -import liquidTemplate from './templates/liquid' import { waitFor } from '@testing-library/dom' function libraryScript() { diff --git a/spec/mustache.spec.ts b/spec/mustache.spec.ts index 5657fbf..786d6bc 100644 --- a/spec/mustache.spec.ts +++ b/spec/mustache.spec.ts @@ -2,8 +2,8 @@ import "@testing-library/jest-dom" import { fromMustacheTemplate, fromRemoteMustacheTemplate, + defaultMustacheTemplate as mustacheTemplate } from "../src/mustache" -import mustacheTemplate from "./templates/mustache" import { autocompleteSuite, handleAutocomplete, diff --git a/spec/react.spec.ts b/spec/react.spec.ts index bc0e8b6..a41f783 100644 --- a/spec/react.spec.ts +++ b/spec/react.spec.ts @@ -1,5 +1,5 @@ import "@testing-library/jest-dom" -import { Autocomplete } from "./components/Autocomplete" +import { Autocomplete } from "../src/defaults/Autocomplete" import type React from "react" import type ReactDOM from "react-dom/client" import { DefaultState } from '../src/utils/state' diff --git a/spec/templates/liquid.ts b/spec/templates/liquid.ts deleted file mode 100644 index 943d91f..0000000 --- a/spec/templates/liquid.ts +++ /dev/null @@ -1,101 +0,0 @@ -export default ` - {% assign hasKeywords = response.keywords.hits.length > 0 %} - {% assign hasProducts = response.products.hits.length > 0 %} - {% assign hasHistory = history.length > 0 %} - -
- {% if hasKeywords == false and hasProducts == false and hasHistory %} -
-
- Recently searched -
- {% for hit in history %} -
- {{ hit.item }} - - ✕ - -
- {% endfor %} -
-
- -
- {% elsif hasKeywords or hasProducts %} - {% if hasKeywords %} -
-
- Keywords -
- {% for hit in response.keywords.hits %} -
- {% if hit._highlight and hit._highlight.keyword %} - {{ hit._highlight.keyword }} - {% else %} - {{ hit.keyword }} - {% endif %} -
- {% endfor %} -
- {% endif %} - {% if hasProducts %} - - {% endif %} -
- -
- {% endif %} -
-` diff --git a/spec/templates/mustache.ts b/spec/templates/mustache.ts deleted file mode 100644 index c6c5619..0000000 --- a/spec/templates/mustache.ts +++ /dev/null @@ -1,89 +0,0 @@ -export default ` -
- {{#response.keywords.hits.length}} -
-
- Keywords -
- {{#response.keywords.hits}} -
- {{#_highlight.keyword}} - {{{.}}} - {{/_highlight.keyword}} - {{^_highlight.keyword}} - {{keyword}} - {{/_highlight.keyword}} -
- {{/response.keywords.hits}} -
- {{/response.keywords.hits.length}} - - {{#response.products.hits.length}} - - {{/response.products.hits.length}} - - {{#history.length}} -
-
- Recently searched -
- {{#history}} -
- {{item}} - - ✕ - -
- {{/history}} -
-
- -
- {{/history.length}} - - {{#response.keywords.hits.length}}{{#response.products.hits.length}} -
- -
- {{/response.products.hits.length}}{{/response.keywords.hits.length}} -
-` diff --git a/src/_generated.ts b/src/_generated.ts new file mode 100644 index 0000000..f394621 --- /dev/null +++ b/src/_generated.ts @@ -0,0 +1,190 @@ +export const defaultLiquidTemplate = ` + {% assign hasKeywords = response.keywords.hits.length > 0 %} + {% assign hasProducts = response.products.hits.length > 0 %} + {% assign hasHistory = history.length > 0 %} + {% assign imagePlaceHolder = 'https://cdn.nosto.com/nosto/9/mock' %} + +
+ {% if hasKeywords == false and hasProducts == false and hasHistory %} +
+
+ Recently searched +
+ {% for hit in history %} +
+ {{ hit.item }} + + ✕ + +
+ {% endfor %} +
+
+ +
+ {% elsif hasKeywords or hasProducts %} + {% if hasKeywords %} +
+
+ Keywords +
+ {% for hit in response.keywords.hits %} +
+ {% if hit._highlight and hit._highlight.keyword %} + {{ hit._highlight.keyword }} + {% else %} + {{ hit.keyword }} + {% endif %} +
+ {% endfor %} +
+ {% endif %} + {% if hasProducts %} + + {% endif %} +
+ +
+ {% endif %} +
+ +` +export const defaultMustacheTemplate = ` +
+ {{#response.keywords.hits.length}} +
+
+ Keywords +
+ {{#response.keywords.hits}} +
+ {{#_highlight.keyword}} + {{{.}}} + {{/_highlight.keyword}} + {{^_highlight.keyword}} + {{keyword}} + {{/_highlight.keyword}} +
+ {{/response.keywords.hits}} +
+ {{/response.keywords.hits.length}} + + {{#response.products.hits.length}} + + {{/response.products.hits.length}} + + {{#history.length}} +
+
+ Recently searched +
+ {{#history}} +
+ {{item}} + + ✕ + +
+ {{/history}} +
+
+ +
+ {{/history.length}} + + {{#response.keywords.hits.length}}{{#response.products.hits.length}} +
+ +
+ {{/response.products.hits.length}}{{/response.keywords.hits.length}} +
+ +` diff --git a/src/defaults/Autocomplete.tsx b/src/defaults/Autocomplete.tsx index 5676ddb..f9b9699 100644 --- a/src/defaults/Autocomplete.tsx +++ b/src/defaults/Autocomplete.tsx @@ -60,6 +60,7 @@ function History({ history }: { history: AutocompleteProps["history"] }) {
{hit.item} @@ -96,6 +97,7 @@ function Keywords({ keywords }: { keywords: SearchKeyword[] }) {
{hit._highlight && hit._highlight.keyword ? ( @@ -125,6 +127,7 @@ function Products({ products }: { products: SearchProduct[] }) { href="#" key={hit.productId} data-ns-hit={JSON.stringify(hit)} + data-testid="product" >
{hit.price}€ - {hit.listPrice && ( + {hit.listPrice && hit.listPrice !== hit.price && ( {hit.listPrice} € diff --git a/src/defaults/autocomplete.liquid b/src/defaults/autocomplete.liquid index de8cfac..ce80618 100644 --- a/src/defaults/autocomplete.liquid +++ b/src/defaults/autocomplete.liquid @@ -10,7 +10,7 @@ Recently searched
{% for hit in history %} - @@ -62,7 +62,7 @@ Recently searched
{{#history}} -
+
{{item}} ✕ diff --git a/src/liquid.ts b/src/liquid.ts index 67a6461..611ee12 100644 --- a/src/liquid.ts +++ b/src/liquid.ts @@ -2,6 +2,8 @@ import { DefaultState } from "./utils/state" import { AnyPromise } from "./utils/promise" import { Liquid } from "liquidjs" +export { defaultLiquidTemplate } from './_generated' + /** * Render a liquid template into a container * @@ -69,102 +71,3 @@ export function fromRemoteLiquidTemplate( }) } } - -export const defaultLiquidTemplate = ` - {% assign hasKeywords = response.keywords.hits.length > 0 %} - {% assign hasProducts = response.products.hits.length > 0 %} - {% assign hasHistory = history.length > 0 %} - {% assign imagePlaceHolder = 'https://cdn.nosto.com/nosto/9/mock' %} - -
- {% if hasKeywords == false and hasProducts == false and hasHistory %} - -
- -
- {% elsif hasKeywords or hasProducts %} - {% if hasKeywords %} -
-
- Keywords -
- {% for hit in response.keywords.hits %} -
- {% if hit._highlight and hit._highlight.keyword %} - {{ hit._highlight.keyword }} - {% else %} - {{ hit.keyword }} - {% endif %} -
- {% endfor %} -
- {% endif %} - {% if hasProducts %} - - {% endif %} -
- -
- {% endif %} -
-` diff --git a/src/mustache.ts b/src/mustache.ts index 41630df..3b0ff87 100644 --- a/src/mustache.ts +++ b/src/mustache.ts @@ -2,6 +2,8 @@ import { AnyPromise } from "./utils/promise" import { DefaultState } from "./utils/state" import Mustache from "mustache" +export { defaultMustacheTemplate } from './_generated' + /** * Render a Mustache template into a container * @@ -10,13 +12,16 @@ import Mustache from "mustache" * @group Autocomplete * @category Mustache */ -export function fromMustacheTemplate(template: string) { +export function fromMustacheTemplate(template: string, options?: { + helpers?: object +}) { if (Mustache === undefined) { throw new Error( "Mustache is not defined. Please include the Mustache dependency or library in your page." ) } + const { helpers } = options || {} return (container: HTMLElement, state: object) => { container.innerHTML = Mustache.render(template, { @@ -25,6 +30,10 @@ export function fromMustacheTemplate(template: string) { toJson: function () { return JSON.stringify(this) }, + showListPrice: function () { + return this.listPrice !== this.price + }, + ...helpers }) return AnyPromise.resolve(undefined) @@ -40,7 +49,10 @@ export function fromMustacheTemplate(template: string) { * @category Mustache */ export function fromRemoteMustacheTemplate( - url: string + url: string, + options?: { + helpers?: object + } ): (container: HTMLElement, state: State) => PromiseLike { return (container, state) => { return new AnyPromise((resolve, reject) => { @@ -48,7 +60,7 @@ export function fromRemoteMustacheTemplate( xhr.open("GET", url) xhr.onload = () => { if (xhr.status === 200) { - fromMustacheTemplate(xhr.responseText)( + fromMustacheTemplate(xhr.responseText, options)( container, state ).then(() => { @@ -73,93 +85,3 @@ export function fromRemoteMustacheTemplate( }) } } - -export const defaultMustacheTemplate = ` -
- {{#response.keywords.hits.length}} -
-
- Keywords -
- {{#response.keywords.hits}} -
- {{#_highlight.keyword}} - {{{.}}} - {{/_highlight.keyword}} - {{^_highlight.keyword}} - {{keyword}} - {{/_highlight.keyword}} -
- {{/response.keywords.hits}} -
- {{/response.keywords.hits.length}} - - {{#response.products.hits.length}} - - {{/response.products.hits.length}} - - {{#history.length}} -
-
- Recently searched -
- {{#history}} -
- {{item}} - - ✕ - -
- {{/history}} -
-
- -
- {{/history.length}} - - {{#response.keywords.hits.length}}{{#response.products.hits.length}} -
- -
- {{/response.products.hits.length}}{{/response.keywords.hits.length}} -
-` diff --git a/tsconfig.json b/tsconfig.json index 29b8886..613320c 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -1,4 +1,5 @@ { + "exclude": ["**/*.js"], "compilerOptions": { "target": "es2016", "lib": ["ES2019", "DOM"],