Skip to content

Commit

Permalink
feat(ESLint): enforce conditional rules
Browse files Browse the repository at this point in the history
The following rules are now reported as errors:
- nullish coalescing
- optional chaining

This aligns us closer to the Guardian’s house rules
  • Loading branch information
mxdvl committed Jan 19, 2023
1 parent 018a9f4 commit 605a5f6
Show file tree
Hide file tree
Showing 82 changed files with 207 additions and 236 deletions.
7 changes: 1 addition & 6 deletions dotcom-rendering/.eslintrc.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,13 +23,8 @@ const rulesToOverrideGuardianConfig = {
},
],

// This is not safe to remove whilst we have noUncheckedIndexedAccess
'@typescript-eslint/no-unnecessary-condition': 'warn',

// use `foo ?? 'a string'` instead of `foo !== null && foo !== undefined ? foo : 'a string'`
'@typescript-eslint/prefer-nullish-coalescing': 'warn',

// use `a?.b` instead of `a && a.b`
'@typescript-eslint/prefer-optional-chain': 'warn',
};

/** @TODO Review these */
Expand Down
2 changes: 1 addition & 1 deletion dotcom-rendering/scripts/jest/setup.ts
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ const localStorageMock = (function () {
} = {};
return {
getItem(key: string) {
return store[key] || null;
return store[key] ?? null;
},
setItem(key: string, value: string) {
store[key] = value.toString();
Expand Down
2 changes: 1 addition & 1 deletion dotcom-rendering/src/amp/components/Blocks.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -152,7 +152,7 @@ export const Blocks = ({
>
<RegionalAd
editionId={editionId}
section={section || ''}
section={section ?? ''}
contentType={contentType}
config={adConfig}
commercialProperties={commercialProperties}
Expand Down
4 changes: 2 additions & 2 deletions dotcom-rendering/src/amp/components/BodyArticle.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -160,7 +160,7 @@ export const Body = ({ data, config }: Props) => {
>
<RegionalAd
editionId={data.editionId}
section={data.sectionName || ''}
section={data.sectionName ?? ''}
contentType={adInfo.contentType}
config={adConfig}
commercialProperties={
Expand Down Expand Up @@ -213,7 +213,7 @@ export const Body = ({ data, config }: Props) => {

<StickyAd
editionId={data.editionId}
section={data.sectionName || ''}
section={data.sectionName ?? ''}
contentType={adInfo.contentType}
config={adConfig}
commercialProperties={adInfo.commercialProperties}
Expand Down
6 changes: 3 additions & 3 deletions dotcom-rendering/src/amp/components/Caption.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { css } from '@emotion/react';
import { text, textSans } from '@guardian/source-foundations';
import { neutral, textSans } from '@guardian/source-foundations';
import React from 'react';
import { pillarPalette_DO_NOT_USE } from '../../lib/pillars';
import TriangleIcon from '../../static/icons/triangle.svg';
Expand All @@ -11,7 +11,7 @@ const captionStyle = css`
padding-top: 10px;
${textSans.xxsmall()};
word-wrap: break-word;
color: ${text.supporting};
color: ${neutral[46]};
`;

const captionPadding = css`
Expand Down Expand Up @@ -57,7 +57,7 @@ export const Caption = ({
<span
css={captionLink}
dangerouslySetInnerHTML={{
__html: captionText || '',
__html: captionText ?? '',
}}
key="caption"
/>
Expand Down
2 changes: 1 addition & 1 deletion dotcom-rendering/src/amp/components/KeyEvents.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ export const KeyEvents = ({ events, url }: Props) => {
<li css={listItemStyle} key={event.id}>
<a css={eventLinkStyle} href={blockLink(url, event.id)}>
<span css={timeStyle}>{event.blockCreatedOnDisplay}</span>
<span css={listTitleStyle}>{event.title || ''}</span>
<span css={listTitleStyle}>{event.title ?? ''}</span>
</a>
</li>
));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ export const ImageBlockComponent = ({ element, pillar }: Props) => {
<span
css={captionLink}
dangerouslySetInnerHTML={{
__html: element.data.caption || '',
__html: element.data.caption ?? '',
}}
key="caption"
/>{' '}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ export const TimelineBlockComponent = ({
pillar,
}: Props) => (
<Expandable id={id} type="Timeline" title={title} pillar={pillar}>
{description || ''}
{description ?? ''}
<ul css={eventsWrapper}>
{events.map((e) => (
<li css={eventStyle} key={e.title}>
Expand All @@ -67,7 +67,7 @@ export const TimelineBlockComponent = ({
<h3 css={headingStyle}>{e.title}</h3>
<div
dangerouslySetInnerHTML={{
__html: e.body || '',
__html: e.body ?? '',
}}
/>
</div>
Expand Down
2 changes: 1 addition & 1 deletion dotcom-rendering/src/amp/lib/get-video-id.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ export const getIdFromUrl = (

if (!id) {
return logErr(
id || ids.join(', '),
id ?? ids.join(', '),
`Value(s) didn't match regexFormat ${regexFormat}`,
);
}
Expand Down
2 changes: 1 addition & 1 deletion dotcom-rendering/src/amp/lib/image-fit.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ export const bestFitImage = (
.sort((a, b) => a.width - b.width)
.find((img) => img.width >= containerWidth);

return bestFit || srcSets[srcSets.length - 1];
return bestFit ?? srcSets[srcSets.length - 1];
};

// AMP images need their height set explicitly, but
Expand Down
2 changes: 1 addition & 1 deletion dotcom-rendering/src/lib/ad-targeting.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ export const buildAdTargeting = ({
const customParams = {
sens: isSensitive ? ('t' as const) : ('f' as const),
si: 'f',
vl: videoDuration || 0,
vl: videoDuration ?? 0,
cc: edition,
s: section,
inskin: 'f',
Expand Down
4 changes: 2 additions & 2 deletions dotcom-rendering/src/lib/articleCount.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,8 +45,8 @@ export const getArticleCounts = async (
}

return {
weeklyArticleHistory: window.guardian.weeklyArticleCount || [],
dailyArticleHistory: window.guardian.dailyArticleCount || [],
weeklyArticleHistory: window.guardian.weeklyArticleCount ?? [],
dailyArticleHistory: window.guardian.dailyArticleCount ?? [],
};
};

Expand Down
2 changes: 1 addition & 1 deletion dotcom-rendering/src/model/enhance-dividers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ const isDinkus = (element: CAPIElement): boolean => {
return false;

const frag = JSDOM.fragment(element.html);
if (!frag || !frag.firstChild) return false;
if (!frag.firstChild) return false;
// A dinkus is can be spaced or unspaced
return (
frag.textContent === '***' ||
Expand Down
10 changes: 5 additions & 5 deletions dotcom-rendering/src/model/enhance-numbered-lists.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ const isFalseH3 = (element: CAPIElement): boolean => {
return false;
}
const frag = JSDOM.fragment(element.html);
if (!frag || !frag.firstElementChild) return false;
if (!frag.firstElementChild) return false;
const html = frag.firstElementChild.outerHTML;
// The following things must be true for an element to be a faux H3
const hasPwrapper = frag.firstElementChild.nodeName === 'P';
Expand Down Expand Up @@ -45,7 +45,7 @@ const extractH3 = (element: CAPIElement): string => {
.split('<strong>')
.join('')
.split('</strong>')
.join('') || ''
.join('') ?? ''
);
}
return '';
Expand All @@ -62,7 +62,7 @@ const isStarRating = (element: CAPIElement): boolean => {
return false;
const frag = JSDOM.fragment(element.html);
const hasPTags = frag.firstElementChild?.nodeName === 'P';
const text = frag.textContent || '';
const text = frag.textContent ?? '';
// Loop the string making sure each letter is a star
for (const letter of text) {
if (!isStar(letter)) return false;
Expand All @@ -78,7 +78,7 @@ const extractStarCount = (element: CAPIElement): number => {
// Returns the count of stars
const textElement = element as TextBlockElement;
const frag = JSDOM.fragment(textElement.html);
const text = frag.textContent || '';
const text = frag.textContent ?? '';
// Loop the string counting selected stars
let starCount = 0;
for (const letter of text) {
Expand Down Expand Up @@ -190,7 +190,7 @@ const isItemLink = (element: CAPIElement): boolean => {
return false;
}
const frag = JSDOM.fragment(element.html);
if (!frag || !frag.firstElementChild) return false;
if (!frag.firstElementChild) return false;

const hasULWrapper = frag.firstElementChild.nodeName === 'UL';
const hasOnlyOneChild = frag.firstElementChild.childElementCount === 1;
Expand Down
6 changes: 3 additions & 3 deletions dotcom-rendering/src/model/enhanceCards.ts
Original file line number Diff line number Diff line change
Expand Up @@ -86,8 +86,8 @@ const enhanceSupportingContent = (

return {
format: presentationFormat,
headline: subLink.header?.headline || '',
url: subLink.properties.href || subLink.header?.url,
headline: subLink.header?.headline ?? '',
url: subLink.properties.href ?? subLink.header?.url,
kickerText: supportingContentIsLive
? 'Live'
: subLink.header?.kicker?.item?.properties.kickerText,
Expand Down Expand Up @@ -168,7 +168,7 @@ export const enhanceCards = (
collections.map((faciaCard, index) => {
// Snap cards may not have a format, default to a standard format if that's the case.
const format = decideFormat(
faciaCard.format || {
faciaCard.format ?? {
design: 'ArticleDesign',
theme: 'NewsPillar',
display: 'StandardDisplay',
Expand Down
7 changes: 4 additions & 3 deletions dotcom-rendering/src/model/extract-ga.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

import type { FEArticleType } from '../types/frontend';
import type { TagType } from '../types/tag';
import { EditionId } from '../web/lib/edition';
import type { EditionId } from '../web/lib/edition';

const filterTags = (
tags: FEArticleType['tags'],
Expand All @@ -16,6 +16,7 @@ const filterTags = (
[],
);

// eslint-disable-next-line @typescript-eslint/prefer-optional-chain -- this code is cursed
return (arrOfvalues && arrOfvalues.join(',')) || '';
};

Expand All @@ -26,7 +27,7 @@ const getCommissioningDesk = (
const tag = tags.find((thisTag) =>
thisTag.id.includes('tracking/commissioningdesk'),
);
return (tag && tag.title) || '';
return tag?.title ?? '';
};

const convertToLegacyPillar = (theme: CAPITheme): LegacyPillar => {
Expand Down Expand Up @@ -70,7 +71,7 @@ export const extractGA = ({
}): GADataType => ({
webTitle,
pillar: convertToLegacyPillar(format.theme),
section: sectionName || '',
section: sectionName ?? '',
contentType: formatStringForGa(contentType),
commissioningDesks: formatStringForGa(getCommissioningDesk(tags)),
contentId: pageId,
Expand Down
8 changes: 5 additions & 3 deletions dotcom-rendering/src/model/find-pillar.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,12 @@ export const findPillar: (
tags?: TagType[],
) => ArticleTheme | undefined = (name, tags?) => {
// Flag paid content for Labs pillar (for styling purposes)
const isPaidContent = (tag: TagType) =>
tag.type === 'Tone' && tag.id === 'tone/advertisement-features';
const hasPaidContent = !!tags?.some(
({ type, id }) =>
type === 'Tone' && id === 'tone/advertisement-features',
);

if (tags && tags.some(isPaidContent)) {
if (hasPaidContent) {
return ArticleSpecial.Labs;
}

Expand Down
2 changes: 1 addition & 1 deletion dotcom-rendering/src/model/insertPromotedNewsletter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -161,7 +161,7 @@ const findInsertPosition = (elements: CAPIElement[]): number | null => {
.sort(sortPlaces);

// Return the position to insert the embed or null if none was found
return suitablePlacesInOrderOfPrefence[0]?.position || null;
return suitablePlacesInOrderOfPrefence[0]?.position ?? null;
};

/**
Expand Down
2 changes: 1 addition & 1 deletion dotcom-rendering/src/model/unwrapHtml.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ export const unwrapHtml = ({
: html;

/** `p` is the default unwrappedElement */
const unwrappedElement = matchingFix?.unwrappedElement || 'p';
const unwrappedElement = matchingFix?.unwrappedElement ?? 'p';

return {
unwrappedHtml,
Expand Down
2 changes: 1 addition & 1 deletion dotcom-rendering/src/server/prod-server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -133,7 +133,7 @@ export const prodServer = (): void => {
}, 10 * 1000);
}

const port = process.env.PORT || 9000;
const port = process.env.PORT ?? 9000;
app.listen(port);

console.log(`Started production server on port ${port}\nready`);
Expand Down
13 changes: 7 additions & 6 deletions dotcom-rendering/src/web/browser/bootCmp/init.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,8 @@ const trackPerformance = (
return;
}

if (window.performance && window.performance.now) {
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition -- not supported in all browsers
if (window.performance?.now) {
ga(
'allEditorialPropertyTracker.send',
'timing',
Expand Down Expand Up @@ -79,7 +80,7 @@ const init = async (): Promise<void> => {

const decideConsentCarrierLabels = () => {
if (consentState.tcfv2) {
const consentUUID = getCookie({ name: 'consentUUID' }) || '';
const consentUUID = getCookie({ name: 'consentUUID' }) ?? '';
const consentString = consentState.tcfv2.tcString;
return [
'01:TCF.v2',
Expand All @@ -88,14 +89,14 @@ const init = async (): Promise<void> => {
];
}
if (consentState.ccpa) {
const ccpaUUID = getCookie({ name: 'ccpaUUID' }) || '';
const ccpaUUID = getCookie({ name: 'ccpaUUID' }) ?? '';
const flag = consentState.ccpa.doNotSell ? 'true' : 'false';
return ['01:CCPA', `04:${ccpaUUID}`, `05:${flag}`];
}
if (consentState.aus) {
const ccpaUUID = getCookie({ name: 'ccpaUUID' }) || '';
const ccpaUUID = getCookie({ name: 'ccpaUUID' }) ?? '';
const consentStatus =
getCookie({ name: 'consentStatus' }) || '';
getCookie({ name: 'consentStatus' }) ?? '';
const personalisedAdvertising = consentState.aus
.personalisedAdvertising
? 'true'
Expand Down Expand Up @@ -165,7 +166,7 @@ const init = async (): Promise<void> => {
browserId: browserId ?? undefined,
pageViewId,
},
country: (await getLocaleCode()) || undefined,
country: (await getLocaleCode()) ?? undefined,
});
log('dotcom', 'CMP initialised');

Expand Down
2 changes: 1 addition & 1 deletion dotcom-rendering/src/web/browser/ga/ga.ts
Original file line number Diff line number Diff line change
Expand Up @@ -127,7 +127,7 @@ export const sendPageView = (): void => {
const NG_STORAGE_KEY = 'gu.analytics.referrerVars';
const referrerVarsData = window.sessionStorage.getItem(NG_STORAGE_KEY);
const referrerVars: { [key: string]: any } = JSON.parse(
referrerVarsData || '{}',
referrerVarsData ?? '{}',
);
if (referrerVars.value) {
const value = referrerVars.value as {
Expand Down
2 changes: 1 addition & 1 deletion dotcom-rendering/src/web/browser/initDiscussion/init.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ const init = (): Promise<void> => {
*
*/
const hashLink = window.location.hash;
if (hashLink && hashLink.includes('comment')) forceHydration();
if (hashLink.includes('comment')) forceHydration();

return Promise.resolve();
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,10 @@ const init = (): Promise<void> => {
// Otherwise, earlier resize events might be missed
// So we don't have to load this script as a priority on each load
allIframes.forEach((iframe) => {
if (iframe && iframe.contentWindow)
iframe.contentWindow.postMessage(
'resize',
'https://www.theguardian.com',
);
iframe.contentWindow?.postMessage(
'resize',
'https://www.theguardian.com',
);
});

window.addEventListener('message', (event) => {
Expand Down
2 changes: 1 addition & 1 deletion dotcom-rendering/src/web/browser/ophan/ophan.ts
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ export const sendOphanComponentEvent = (
componentType,
products,
campaignCode,
id: testMeta.campaignId || testMeta.campaignCode,
id: testMeta.campaignId ?? testMeta.campaignCode,
labels,
},
abTest: {
Expand Down
2 changes: 1 addition & 1 deletion dotcom-rendering/src/web/browser/updateIframeHeight.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ export const updateIframeHeight = (queryString: string): Promise<void> => {
});

iframes.forEach((iframe) => {
const src = (iframe.getAttribute('srcdoc') || '')
const src = (iframe.getAttribute('srcdoc') ?? '')
.replace(/<gu-script>/g, '<script>')

.replace(/<\/gu-script>/g, '<' + '/script>');
Expand Down
Loading

0 comments on commit 605a5f6

Please sign in to comment.