From 04e7407a874adf018d286daaa8aff7436caf03d9 Mon Sep 17 00:00:00 2001 From: Thorsten Kober Date: Wed, 11 Oct 2023 09:58:31 -0400 Subject: [PATCH] add script types and a simple type guard (#27) --- src/index.ts | 2 + src/third-parties/google-analytics/data.json | 2 +- src/types/index.ts | 39 +--------------- src/types/type-declarations.ts | 49 ++++++++++++++++++++ src/types/type-guards.ts | 5 ++ src/utils/index.test.ts | 4 +- src/utils/index.ts | 14 +++++- 7 files changed, 73 insertions(+), 42 deletions(-) create mode 100644 src/types/type-declarations.ts create mode 100644 src/types/type-guards.ts diff --git a/src/index.ts b/src/index.ts index f1bf24c..c78930a 100644 --- a/src/index.ts +++ b/src/index.ts @@ -15,3 +15,5 @@ export { GoogleAnalytics } from './third-parties/google-analytics'; export { GoogleMapsEmbed } from './third-parties/google-maps-embed'; export { YouTubeEmbed } from './third-parties/youtube-embed'; + +export * from './types'; diff --git a/src/third-parties/google-analytics/data.json b/src/third-parties/google-analytics/data.json index c11ad06..7b9d149 100644 --- a/src/third-parties/google-analytics/data.json +++ b/src/third-parties/google-analytics/data.json @@ -11,7 +11,7 @@ "action": "append" }, { - "code": "window.dataLayer=window.dataLayer||[];window.gtag=function gtag(){window.dataLayer.push(arguments);};gtag('js',new Date());gtag('config','${args.id}')", + "code": "window.dataLayer=window.dataLayer||[];window.gtag=function gtag(){window.dataLayer.push(arguments);};gtag('js',new Date());gtag('config','{{id}}')", "strategy": "worker", "location": "head", "action": "append" diff --git a/src/types/index.ts b/src/types/index.ts index e8ed16f..13509c7 100644 --- a/src/types/index.ts +++ b/src/types/index.ts @@ -1,37 +1,2 @@ -type ScriptStrategy = 'server' | 'client' | 'idle' | 'worker'; -type ScriptLocation = 'head' | 'body'; -type ScriptAction = 'append' | 'prepend'; -export type SrcVal = { - url: string; - slugParam?: string; - params?: Array; -}; - -export type AttributeVal = string | null | SrcVal | boolean | undefined; - -export type HtmlAttributes = { - src?: SrcVal; - [key: string]: AttributeVal; -}; - -export interface Data { - id: string; - description: string; - website?: string; - html?: { - element: string; - attributes: HtmlAttributes; - }; - stylesheets?: Array; - scripts?: Array<{ - url: string; - params?: Array; - strategy: ScriptStrategy; - location: ScriptLocation; - action: ScriptAction; - }>; -} - -export interface Inputs { - [key: string]: any; -} +export * from './type-declarations'; +export * from './type-guards'; diff --git a/src/types/type-declarations.ts b/src/types/type-declarations.ts new file mode 100644 index 0000000..469d8f0 --- /dev/null +++ b/src/types/type-declarations.ts @@ -0,0 +1,49 @@ +type ScriptStrategy = 'server' | 'client' | 'idle' | 'worker'; +type ScriptLocation = 'head' | 'body'; +type ScriptAction = 'append' | 'prepend'; +export type SrcVal = { + url: string; + slugParam?: string; + params?: Array; +}; + +export type AttributeVal = string | null | SrcVal | boolean | undefined; + +export type HtmlAttributes = { + src?: SrcVal; + [key: string]: AttributeVal; +}; + +type ScriptBase = { + params?: Array; + strategy: ScriptStrategy; + location: ScriptLocation; + action: ScriptAction; +}; + +export type ExternalScript = ScriptBase & { + url: string; +}; + +export type CodeBlock = ScriptBase & { + code: string; +}; + +export type Script = ExternalScript | CodeBlock; +export type Scripts = Script[]; + +export interface Data { + id: string; + description: string; + website?: string; + html?: { + element: string; + attributes: HtmlAttributes; + }; + stylesheets?: Array; + scripts?: Scripts; +} + +export interface Inputs { + [key: string]: any; +} diff --git a/src/types/type-guards.ts b/src/types/type-guards.ts new file mode 100644 index 0000000..5c6bb25 --- /dev/null +++ b/src/types/type-guards.ts @@ -0,0 +1,5 @@ +import { Script, ExternalScript } from '.'; + +export function isExternalScript(script: Script): script is ExternalScript { + return (script as ExternalScript).url !== undefined; +} diff --git a/src/utils/index.test.ts b/src/utils/index.test.ts index 823ba89..acf8edf 100644 --- a/src/utils/index.test.ts +++ b/src/utils/index.test.ts @@ -1,5 +1,5 @@ import { formatUrl, createHtml, formatData } from '.'; -import type { Data } from '../types'; +import type { Data, ExternalScript } from '../types'; describe('Utils', () => { describe('formatUrl', () => { @@ -143,7 +143,7 @@ describe('Utils', () => { expect(result.html).toEqual(''); expect(result.scripts).not.toEqual(null); expect(result.scripts!.length).toEqual(1); - expect(result.scripts![0].url).toEqual( + expect((result.scripts![0] as ExternalScript).url).toEqual( 'https://www.example.com/?id=userDefinedId', ); }); diff --git a/src/utils/index.ts b/src/utils/index.ts index 177dd89..6acb2ed 100644 --- a/src/utils/index.ts +++ b/src/utils/index.ts @@ -1,4 +1,5 @@ import type { Data, Inputs, AttributeVal, HtmlAttributes } from '../types'; +import { isExternalScript } from '../types'; function filterArgs( args: Inputs, @@ -38,6 +39,12 @@ export function formatUrl( return newUrl.toString(); } +export function formatCode(code: string, args?: Inputs) { + return code.replace(/{{(.*?)}}/g, (match) => { + return args?.[match.split(/{{|}}/).filter(Boolean)[0]]; + }); +} + // Construct HTML element and include all default attributes and user-inputted attributes export function createHtml( element: string, @@ -127,12 +134,15 @@ export function formatData(data: Data, args: Inputs) { // Pass any required query params with user values for relevant scripts scripts: data.scripts ? data.scripts.map((script) => { - return script.url + return isExternalScript(script) ? { ...script, url: formatUrl(script.url, script.params, scriptUrlParamInputs), } - : script; + : { + ...script, + code: formatCode(script.code, scriptUrlParamInputs), + }; }) : null, };