Skip to content

Commit 6cfbcca

Browse files
committed
Replace raw 'throw new Error' calls in client code to use project ClientScriptError class
1 parent 5af6631 commit 6cfbcca

31 files changed

Lines changed: 278 additions & 105 deletions

File tree

.vscode/settings.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,7 @@
6060
"MTTR",
6161
"nanostores",
6262
"navigations",
63+
"Neue",
6364
"Niklas",
6465
"noabbr",
6566
"octocat",
@@ -104,6 +105,7 @@
104105
"vmax",
105106
"vtbot",
106107
"WHATWG",
108+
"wordprocessingml",
107109
"wscript",
108110
"youtu",
109111
"yoyo",

src/components/Carousel/__tests__/client.spec.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -289,7 +289,7 @@ describe('CarouselManager', () => {
289289
// Mock EmblaCarousel to throw an error
290290
const EmblaCarousel = (await import('embla-carousel')).default
291291
vi.mocked(EmblaCarousel).mockImplementation(() => {
292-
throw new Error('Mock initialization error')
292+
throw new TestError('Mock initialization error')
293293
})
294294

295295
// Error handling now uses handleScriptError instead of console.error

src/components/ContactForm/email.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import {
44
minLengthEmailAddressText,
55
maxLengthEmailAddressText,
66
} from './error'
7+
import { ClientScriptError } from '@components/scripts/errors/ClientScriptError'
78
import type { ContactFormSelectors } from './selectors'
89

910
export const initEmailValidationHandler = (selector: ContactFormSelectors) => {
@@ -39,6 +40,8 @@ const getEmailErrorText = (emailInputElement: HTMLInputElement) => {
3940
/** If the data is too long, display the following error message */
4041
return maxLengthEmailAddressText(emailInputElement)
4142
} else {
42-
throw new Error()
43+
throw new ClientScriptError({
44+
message: `Unknown email validation error`
45+
})
4346
}
4447
}

src/components/ContactForm/selectors.ts

Lines changed: 22 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
/**
22
* Type-safe HTML element selectors
33
*/
4+
import { ClientScriptError } from '@components/scripts/errors/ClientScriptError'
45
import {
56
isButtonElement,
67
isDivElement,
@@ -151,7 +152,9 @@ export class ContactFormSelectors {
151152
public get contactForm(): HTMLFormElement {
152153
const formELement = document.querySelector(SELECTORS.formELement)
153154
if (!isFormElement(formELement)) {
154-
throw new Error(`Contact form is missing in document, selector: ${SELECTORS.formELement}`)
155+
throw new ClientScriptError({
156+
message: `Contact form is missing in document, selector: ${SELECTORS.formELement}`
157+
})
155158
}
156159
return formELement
157160
}
@@ -163,9 +166,9 @@ export class ContactFormSelectors {
163166
if (!this._submitButton) {
164167
const submitButton = document.querySelector(SELECTORS.submitButton)
165168
if (!isButtonElement(submitButton)) {
166-
throw new Error(
167-
`Contact form submit button is missing in document, selector: ${SELECTORS.submitButton}`
168-
)
169+
throw new ClientScriptError({
170+
message: `Contact form submit button is missing in document, selector: ${SELECTORS.submitButton}`
171+
})
169172
}
170173
this._submitButton = submitButton
171174
}
@@ -179,7 +182,9 @@ export class ContactFormSelectors {
179182
if (!this._formValidationError) {
180183
const errorValidationElement = document.querySelector(SELECTORS.formError)
181184
if (!isDivElement(errorValidationElement)) {
182-
throw new Error(`Contact form error wrapper is missing in document: ${SELECTORS.formError}`)
185+
throw new ClientScriptError({
186+
message: `Contact form error wrapper is missing in document: ${SELECTORS.formError}`
187+
})
183188
}
184189
this._formValidationError = errorValidationElement
185190
}
@@ -193,9 +198,9 @@ export class ContactFormSelectors {
193198
const elementSelector = SELECTORS[selector]
194199
const group = document.querySelector(elementSelector)
195200
if (!isDivElement(group)) {
196-
throw new Error(
197-
`Contact form input group wrapper <div> is missing in document, selector: ${elementSelector}`
198-
)
201+
throw new ClientScriptError({
202+
message: `Contact form input group wrapper <div> is missing in document, selector: ${elementSelector}`
203+
})
199204
}
200205
return group
201206
}
@@ -206,9 +211,9 @@ export class ContactFormSelectors {
206211
private getInputElement(formGroup: HTMLDivElement): HTMLInputElement {
207212
const inputElement = formGroup.querySelector(SELECTORS.inputElement)
208213
if (!isInputElement(inputElement)) {
209-
throw new Error(
210-
`Contact form input element is missing in document for input group: ${formGroup['tagName']}`
211-
)
214+
throw new ClientScriptError({
215+
message: `Contact form input element is missing in document for input group: ${formGroup['tagName']}`
216+
})
212217
}
213218
return inputElement
214219
}
@@ -219,9 +224,9 @@ export class ContactFormSelectors {
219224
private getLabelElement(formGroup: HTMLDivElement): HTMLLabelElement {
220225
const labelElement = formGroup.querySelector(SELECTORS.inputLabel)
221226
if (!isLabelElement(labelElement)) {
222-
throw new Error(
223-
`Contact form input group wrapper <div> is missing in document for input group: ${formGroup['tagName']}`
224-
)
227+
throw new ClientScriptError({
228+
message: `Contact form input group wrapper <div> is missing in document for input group: ${formGroup['tagName']}`
229+
})
225230
}
226231
return labelElement
227232
}
@@ -232,9 +237,9 @@ export class ContactFormSelectors {
232237
private getErrorValidationElement(formGroup: HTMLDivElement): HTMLDivElement {
233238
const errorValidationElement = formGroup.querySelector(SELECTORS.validationError)
234239
if (!isDivElement(errorValidationElement)) {
235-
throw new Error(
236-
`Contact form input group wrapper <div> is missing in document for input group: ${formGroup['tagName']}`
237-
)
240+
throw new ClientScriptError({
241+
message: `Contact form input group wrapper <div> is missing in document for input group: ${formGroup['tagName']}`
242+
})
238243
}
239244
return errorValidationElement
240245
}

src/components/Footer/selectors.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
/**
22
* Type-safe HTML element selectors
33
*/
4+
import { ClientScriptError } from '@components/scripts/errors/ClientScriptError'
45
import { isAnchorElement } from '@components/scripts/assertions/elements'
56

67
export const SELECTORS = {
@@ -14,7 +15,9 @@ export const SELECTORS = {
1415
export const getHireMeAnchorElement = (): HTMLAnchorElement => {
1516
const anchor = document.querySelector(SELECTORS.hireMeAnchor)
1617
if (!isAnchorElement(anchor)) {
17-
throw new Error(`Footer anchor for "Hire Me" element, selector: ${SELECTORS.hireMeAnchor}`)
18+
throw new ClientScriptError({
19+
message: `Footer anchor for "Hire Me" element, selector: ${SELECTORS.hireMeAnchor}`
20+
})
1821
}
1922
return anchor
2023
}

src/components/Footer/server.ts

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,8 @@
22
* Server-side utilities for Footer component
33
* Functions used during build process in Astro frontmatter
44
*/
5-
65
import parsePhoneNumber from 'libphonenumber-js'
6+
import { ClientScriptError } from '@components/scripts/errors/ClientScriptError'
77

88
/**
99
* Format a phone number in standard format
@@ -14,8 +14,9 @@ import parsePhoneNumber from 'libphonenumber-js'
1414
export const formatPhoneNumber = (phoneNumber: string) => {
1515
const parsedPhoneNumber = parsePhoneNumber(phoneNumber)
1616
if (!parsedPhoneNumber) {
17-
// throw new Error(`Trying to format invalid phone number: ${phoneNumber}`)
18-
return undefined
17+
throw new ClientScriptError({
18+
message: `Trying to format invalid phone number: ${phoneNumber}`
19+
})
1920
}
2021
return parsedPhoneNumber.format('NATIONAL')
2122
}

src/components/Forms/Download/client.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,9 @@ export class DownloadForm {
7979
})
8080

8181
if (!response.ok) {
82-
throw new Error('Failed to submit form')
82+
throw new ClientScriptError({
83+
message: 'Failed to submit form'
84+
})
8385
}
8486

8587
await response.json()

src/components/Forms/Download/selectors.ts

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
/**
22
* Selectors for DownloadForm component elements
33
*/
4+
import { ClientScriptError } from '@components/scripts/errors/ClientScriptError'
45

56
/**
67
* Get the download form element
@@ -9,7 +10,9 @@
910
export function getDownloadFormElement(): HTMLFormElement {
1011
const form = document.getElementById('downloadForm')
1112
if (!form || !(form instanceof HTMLFormElement)) {
12-
throw new Error('Download form element not found')
13+
throw new ClientScriptError({
14+
message: `Download form element not found`
15+
})
1316
}
1417
return form
1518
}
@@ -21,7 +24,9 @@ export function getDownloadFormElement(): HTMLFormElement {
2124
export function getDownloadSubmitButton(): HTMLButtonElement {
2225
const button = document.getElementById('downloadSubmitBtn')
2326
if (!button || !(button instanceof HTMLButtonElement)) {
24-
throw new Error('Download submit button not found')
27+
throw new ClientScriptError({
28+
message: `Download submit button not found`
29+
})
2530
}
2631
return button
2732
}
@@ -33,7 +38,9 @@ export function getDownloadSubmitButton(): HTMLButtonElement {
3338
export function getDownloadStatusDiv(): HTMLElement {
3439
const statusDiv = document.getElementById('downloadFormStatus')
3540
if (!statusDiv) {
36-
throw new Error('Download status div not found')
41+
throw new ClientScriptError({
42+
message: `Download status div not found`
43+
})
3744
}
3845
return statusDiv
3946
}
@@ -45,7 +52,9 @@ export function getDownloadStatusDiv(): HTMLElement {
4552
export function getDownloadButtonWrapper(): HTMLElement {
4653
const wrapper = document.getElementById('downloadButtonWrapper')
4754
if (!wrapper) {
48-
throw new Error('Download button wrapper not found')
55+
throw new ClientScriptError({
56+
message: `Download button wrapper not found`
57+
})
4958
}
5059
return wrapper
5160
}

src/components/GDPR/Consent/selectors.ts

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
/**
22
* DOM selectors for GDPR Consent component
33
*/
4+
import { ClientScriptError } from '@components/scripts/errors/ClientScriptError'
45

56
/**
67
* Get the consent checkbox element
@@ -10,7 +11,9 @@ export function getConsentCheckbox(containerId?: string): HTMLInputElement {
1011
const element = document.getElementById(id)
1112

1213
if (!element || !(element instanceof HTMLInputElement)) {
13-
throw new Error(`GDPR consent checkbox not found: #${id}`)
14+
throw new ClientScriptError({
15+
message: `GDPR consent checkbox not found: #${id}`
16+
})
1417
}
1518

1619
return element
@@ -24,7 +27,9 @@ export function getConsentContainer(containerId?: string): HTMLDivElement {
2427
const element = document.getElementById(id)
2528

2629
if (!element || !(element instanceof HTMLDivElement)) {
27-
throw new Error(`GDPR consent container not found: #${id}`)
30+
throw new ClientScriptError({
31+
message: `GDPR consent container not found: #${id}`
32+
})
2833
}
2934

3035
return element
@@ -38,7 +43,9 @@ export function getConsentError(containerId?: string): HTMLDivElement {
3843
const element = document.getElementById(id)
3944

4045
if (!element || !(element instanceof HTMLDivElement)) {
41-
throw new Error(`GDPR consent error element not found: #${id}`)
46+
throw new ClientScriptError({
47+
message: `GDPR consent error element not found: #${id}`
48+
})
4249
}
4350

4451
return element
@@ -52,7 +59,9 @@ export function getConsentDescription(containerId?: string): HTMLSpanElement {
5259
const element = document.getElementById(id)
5360

5461
if (!element || !(element instanceof HTMLSpanElement)) {
55-
throw new Error(`GDPR consent description not found: #${id}`)
62+
throw new ClientScriptError({
63+
message: `GDPR consent description not found: #${id}`
64+
})
5665
}
5766

5867
return element

src/components/Highlighter/selectors.ts

Lines changed: 22 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
/**
22
* Type-safe HTML element selectors
33
*/
4+
import { ClientScriptError } from '@components/scripts/errors/ClientScriptError'
45
import {
56
isBodyElement,
67
isDivElement,
@@ -12,14 +13,18 @@ import {
1213
export const queryDocument = (selector: string): Element => {
1314
const element = document.querySelector(selector)
1415
if (element === null)
15-
throw new Error(`Could not find document element for query selector ${selector}`)
16+
throw new ClientScriptError({
17+
message: `Could not find document element for query selector ${selector}`
18+
})
1619
return element
1720
}
1821

1922
export const queryAllDocument = (selector: string): NodeListOf<Element> => {
2023
const elements = document.querySelectorAll(selector)
2124
if (elements.length === 0)
22-
throw new Error(`Could not find any document elements for query selector ${selector}`)
25+
throw new ClientScriptError({
26+
message: `Could not find any document elements for query selector ${selector}`
27+
})
2328
return elements
2429
}
2530

@@ -28,7 +33,9 @@ export const queryAllDocument = (selector: string): NodeListOf<Element> => {
2833
*/
2934
export const getBodyElement = (): HTMLBodyElement => {
3035
if (!isBodyElement(document.body))
31-
throw new Error(`Page is missing a <body> element, is the document empty?`)
36+
throw new ClientScriptError({
37+
message: `Page is missing a <body> element, is the document empty?`
38+
})
3239
return document.body
3340
}
3441

@@ -37,7 +44,9 @@ export const getBodyElement = (): HTMLBodyElement => {
3744
*/
3845
export const getHtmlElement = (): HTMLHtmlElement => {
3946
if (!isHtmlElement(document.documentElement))
40-
throw new Error(`Page is missing a <html> element, is the document XML or XHTML?`)
47+
throw new ClientScriptError({
48+
message: `Page is missing a <html> element, is the document XML or XHTML?`
49+
})
4150
return document.documentElement
4251
}
4352

@@ -46,7 +55,9 @@ export const getHtmlElement = (): HTMLHtmlElement => {
4655
*/
4756
export const getSlotElement = (shadowRoot: ShadowRoot): HTMLSlotElement => {
4857
const slotElement = shadowRoot.querySelector('slot')
49-
if (!isSlotElement(slotElement)) throw new Error(`<slot> element is missing in shadow root`)
58+
if (!isSlotElement(slotElement)) throw new ClientScriptError({
59+
message: `<slot> element is missing in shadow root`
60+
})
5061
return slotElement
5162
}
5263

@@ -56,13 +67,17 @@ export const getSlotElement = (shadowRoot: ShadowRoot): HTMLSlotElement => {
5667
export const getDivElement = (selector: string): HTMLDivElement => {
5768
const element = document.querySelector(selector)
5869
if (!isDivElement(element))
59-
throw new Error(`Could not find <div> element for query selector ${selector}`)
70+
throw new ClientScriptError({
71+
message: `Could not find <div> element for query selector ${selector}`
72+
})
6073
return element
6174
}
6275

6376
export const getDivElements = (selector: string): NodeListOf<HTMLDivElement> => {
6477
const elements = document.querySelectorAll(selector)
6578
if (elements.length === 0)
66-
throw new Error(`Could not find any <div> elements for query selector ${selector}`)
79+
throw new ClientScriptError({
80+
message: `Could not find any <div> elements for query selector ${selector}`
81+
})
6782
return elements as NodeListOf<HTMLDivElement>
6883
}

0 commit comments

Comments
 (0)