Skip to content

Commit

Permalink
infra: enable strictNullChecks in tsconfig (#2435)
Browse files Browse the repository at this point in the history
  • Loading branch information
ST-DDT authored Nov 14, 2023
1 parent 36fc517 commit 7e3c92e
Show file tree
Hide file tree
Showing 25 changed files with 239 additions and 131 deletions.
2 changes: 1 addition & 1 deletion cypress/e2e/api.cy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ describe('API Test', () => {
cy.get('.api-group li').each(($el) => {
const anchor = $el.find('a');
const text = anchor.text();
const link = anchor.attr('href').split('#')[0];
const link = anchor.attr('href')?.split('#')[0] ?? 'MISSING';
if (checked.has(link)) {
return;
}
Expand Down
13 changes: 8 additions & 5 deletions docs/.vitepress/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -121,11 +121,14 @@ const config = defineConfig({
{ icon: 'github', link: 'https://github.com/faker-js/faker' },
],

algolia: {
apiKey: process.env.API_KEY,
appId: process.env.APP_ID,
indexName: 'fakerjs',
},
algolia:
process.env.API_KEY == null || process.env.APP_ID == null
? undefined
: {
apiKey: process.env.API_KEY,
appId: process.env.APP_ID,
indexName: 'fakerjs',
},

footer: {
message: 'Released under the MIT License.',
Expand Down
21 changes: 13 additions & 8 deletions docs/.vitepress/versions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,18 +14,23 @@ function readOtherLatestReleaseTagNames(): string[] {
.toString('utf8')
.split('\n')
.filter((tag) => semver.valid(tag))
.reduce<Record<number, string[]>>((acc, tag) => {
const majorVersion = semver.major(tag);
.filter((tag) => {
// Only consider tags for our deployed website versions,
// excluding the current major version.
if (majorVersion >= 6 && majorVersion !== currentMajorVersion) {
(acc[majorVersion] = acc[majorVersion] ?? []).push(tag);
const majorVersion = semver.major(tag);
return majorVersion >= 6 && majorVersion !== currentMajorVersion;
})
.reduce<Record<number, string>>((latestTagByMajor, tag) => {
const majorVersion = semver.major(tag);

const latestTag = latestTagByMajor[majorVersion];
if (latestTag == null || semver.lt(latestTag, tag)) {
latestTagByMajor[majorVersion] = tag;
}
return acc;

return latestTagByMajor;
}, {});
return Object.entries(latestReleaseTagNames)
.map(([major, tags]) => semver.maxSatisfying(tags, `^${major}`))
.sort(semver.rcompare);
return Object.values(latestReleaseTagNames).sort(semver.rcompare);
}

// Set by netlify
Expand Down
6 changes: 5 additions & 1 deletion scripts/apidoc/faker-class.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,10 @@ export async function processFakerRandomizer(
.getChildrenByKind(ReflectionKind.Interface)
.find((clazz) => clazz.name === 'Randomizer');

if (randomizerClass == null) {
throw new Error('Randomizer class not found');
}

return processClass(randomizerClass);
}

Expand Down Expand Up @@ -63,7 +67,7 @@ async function processClass(
function hasConstructor(clazz: DeclarationReflection): boolean {
return clazz
.getChildrenByKind(ReflectionKind.Constructor)
.some((constructor) => constructor.signatures.length > 0);
.some((constructor) => (constructor.signatures?.length ?? 0) > 0);
}

async function processConstructor(
Expand Down
2 changes: 1 addition & 1 deletion scripts/apidoc/signature.ts
Original file line number Diff line number Diff line change
Expand Up @@ -305,7 +305,7 @@ async function signatureTypeToText(
await Promise.all(
signature.parameters?.map(
async (p) => `${p.name}: ${await typeToText(p.type)}`
)
) ?? []
)
).join(', ')}) => ${await typeToText(signature.type)}`;
}
Expand Down
3 changes: 2 additions & 1 deletion src/definitions/date.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,9 @@ export interface DateEntryDefinition {

/**
* The short name/abbreviation of the entry.
* If null, the locale does not support a short name/abbreviation for the entry.
*/
abbr: string[];
abbr: string[] | null;

/**
* The wide name of the entry when used in context. If absent wide will be used instead.
Expand Down
2 changes: 1 addition & 1 deletion src/definitions/definitions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -50,4 +50,4 @@ export type LocaleDefinition = {
system?: SystemDefinition;
vehicle?: VehicleDefinition;
word?: WordDefinition;
} & Record<string, Record<string, unknown> | undefined>;
} & Record<string, Record<string, unknown>>;
40 changes: 27 additions & 13 deletions src/locale-proxy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,30 @@ export function createLocaleProxy(locale: LocaleDefinition): LocaleProxy {
}) as LocaleProxy;
}

/**
* Checks that the value is not null or undefined and throws an error if it is.
*
* @param value The value to check.
* @param path The path to the locale data.
*/
export function assertLocaleData<T>(
value: T,
...path: string[]
): asserts value is NonNullable<T> {
if (value === null) {
throw new FakerError(
`The locale data for '${path.join('.')}' aren't applicable to this locale.
If you think this is a bug, please report it at: https://github.com/faker-js/faker`
);
} else if (value === undefined) {
throw new FakerError(
`The locale data for '${path.join('.')}' are missing in this locale.
Please contribute the missing data to the project or use a locale/Faker instance that has these data.
For more information see https://fakerjs.dev/guide/localization.html`
);
}
}

/**
* Creates a proxy for a category that throws an error when accessing an undefined property.
*
Expand All @@ -79,20 +103,10 @@ function createCategoryProxy<
const value = target[entryName];
if (typeof entryName === 'symbol' || entryName === 'nodeType') {
return value;
} else if (value === null) {
throw new FakerError(
`The locale data for '${categoryName}.${entryName.toString()}' aren't applicable to this locale.
If you think this is a bug, please report it at: https://github.com/faker-js/faker`
);
} else if (value === undefined) {
throw new FakerError(
`The locale data for '${categoryName}.${entryName.toString()}' are missing in this locale.
Please contribute the missing data to the project or use a locale/Faker instance that has these data.
For more information see https://fakerjs.dev/guide/localization.html`
);
} else {
return value;
}

assertLocaleData(value, categoryName, entryName.toString());
return value;
},

set: throwReadOnlyError,
Expand Down
2 changes: 1 addition & 1 deletion src/modules/airline/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -155,7 +155,7 @@ export class AirlineModule extends ModuleBase {
): string {
const { allowNumerics = false, allowVisuallySimilarCharacters = false } =
options;
const excludedChars = [];
const excludedChars: string[] = [];
if (!allowNumerics) {
excludedChars.push(...numerics);
}
Expand Down
37 changes: 20 additions & 17 deletions src/modules/color/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -47,17 +47,19 @@ export type Casing = 'lower' | 'upper' | 'mixed';
*
* @param hexColor Hex color string to be formatted.
* @param options Options object.
* @param options.prefix Prefix of the generated hex color. Defaults to `'0x'`.
* @param options.casing Letter type case of the generated hex color. Defaults to `'mixed'`.
* @param options.prefix Prefix of the generated hex color.
* @param options.casing Letter type case of the generated hex color.
*/
function formatHexColor(
hexColor: string,
options?: {
prefix?: string;
casing?: Casing;
options: {
prefix: string;
casing: Casing;
}
): string {
switch (options?.casing) {
const { prefix, casing } = options;

switch (casing) {
case 'upper':
hexColor = hexColor.toUpperCase();
break;
Expand All @@ -68,8 +70,8 @@ function formatHexColor(
// Do nothing
}

if (options?.prefix) {
hexColor = options.prefix + hexColor;
if (prefix) {
hexColor = prefix + hexColor;
}

return hexColor;
Expand Down Expand Up @@ -360,27 +362,28 @@ export class ColorModule extends ModuleBase {
*/
includeAlpha?: boolean;
}): string | number[];
rgb(options?: {
prefix?: string;
casing?: Casing;
format?: 'hex' | ColorFormat;
includeAlpha?: boolean;
}): string | number[] {
rgb(
options: {
prefix?: string;
casing?: Casing;
format?: 'hex' | ColorFormat;
includeAlpha?: boolean;
} = {}
): string | number[] {
const {
format = 'hex',
includeAlpha = false,
prefix = '#',
casing = 'lower',
} = options || {};
options = { format, includeAlpha, prefix, casing };
} = options;
let color: string | number[];
let cssFunction: CssFunctionType = 'rgb';
if (format === 'hex') {
color = this.faker.string.hexadecimal({
length: includeAlpha ? 8 : 6,
prefix: '',
});
color = formatHexColor(color, options);
color = formatHexColor(color, { prefix, casing });
return color;
}

Expand Down
10 changes: 9 additions & 1 deletion src/modules/commerce/index.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { FakerError } from '../../errors/faker-error';
import { deprecated } from '../../internal/deprecated';
import { ModuleBase } from '../../internal/module-base';

Expand Down Expand Up @@ -401,7 +402,14 @@ export class CommerceModule extends ModuleBase {

const registrantLength = groupRules.find(
([rangeMaximum]) => elementValue <= rangeMaximum
)[1];
)?.[1];

if (!registrantLength) {
// This can only happen if the ISBN_LENGTH_RULES are corrupted
throw new FakerError(
`Unable to find a registrant length for the group ${group}`
);
}

const registrant = element.slice(0, registrantLength);
const publication = element.slice(registrantLength);
Expand Down
51 changes: 27 additions & 24 deletions src/modules/date/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import type { DateEntryDefinition } from '../../definitions';
import { FakerError } from '../../errors/faker-error';
import { deprecated } from '../../internal/deprecated';
import { SimpleModuleBase } from '../../internal/module-base';
import { assertLocaleData } from '../../locale-proxy';

/**
* Converts date passed as a string, number or Date to a Date object.
Expand All @@ -15,6 +16,10 @@ function toDate(
date: string | Date | number | undefined,
fallback: () => Date
): Date {
if (date == null) {
return fallback();
}

date = new Date(date);
if (Number.isNaN(date.valueOf())) {
date = fallback();
Expand Down Expand Up @@ -383,14 +388,15 @@ export class SimpleDateModule extends SimpleModuleBase {
},
legacyTo?: string | Date | number
): Date {
if (typeof options !== 'object' || options instanceof Date) {
if (options instanceof Date || typeof options !== 'object') {
deprecated({
deprecated: 'faker.date.between(from, to)',
proposed: 'faker.date.between({ from, to })',
since: '8.0',
until: '9.0',
});
options = { from: options, to: legacyTo };
// We use options as fallback for legacyTo avoid TS errors for unintended usage.
options = { from: options, to: legacyTo ?? options };
}

const { from, to } = options;
Expand Down Expand Up @@ -559,14 +565,15 @@ export class SimpleDateModule extends SimpleModuleBase {
legacyTo?: string | Date | number,
legacyCount: number = 3
): Date[] {
if (typeof options !== 'object' || options instanceof Date) {
if (options instanceof Date || typeof options !== 'object') {
deprecated({
deprecated: 'faker.date.betweens(from, to, count)',
proposed: 'faker.date.betweens({ from, to, count })',
since: '8.0',
until: '9.0',
});
options = { from: options, to: legacyTo, count: legacyCount };
// We use options as fallback for legacyTo avoid TS errors for unintended usage.
options = { from: options, to: legacyTo ?? options, count: legacyCount };
}

const { from, to, count = 3 } = options;
Expand Down Expand Up @@ -864,12 +871,6 @@ export class SimpleDateModule extends SimpleModuleBase {
refDate?: string | Date | number;
} = {}
): Date {
if (options.max < options.min) {
throw new FakerError(
`Max ${options.max} should be larger than or equal to min ${options.min}.`
);
}

const mode = options.mode === 'age' ? 'age' : 'year';
const refDate = toDate(options.refDate, this.faker.defaultRefDate);
const refYear = refDate.getUTCFullYear();
Expand All @@ -894,6 +895,12 @@ export class SimpleDateModule extends SimpleModuleBase {
);
}

if (max < min) {
throw new FakerError(
`Max ${options.max} should be larger than or equal to min ${options.min}.`
);
}

return new Date(this.faker.number.int({ min, max }));
}
}
Expand Down Expand Up @@ -1074,12 +1081,8 @@ export class DateModule extends SimpleDateModule {
context?: boolean;
} = {}
): string {
const {
// eslint-disable-next-line deprecation/deprecation
abbr,
abbreviated = abbr ?? false,
context = false,
} = options;
// eslint-disable-next-line deprecation/deprecation
const { abbr, abbreviated = abbr ?? false, context = false } = options;

if (abbr != null) {
deprecated({
Expand All @@ -1100,7 +1103,9 @@ export class DateModule extends SimpleDateModule {
type = useContext ? 'wide_context' : 'wide';
}

return this.faker.helpers.arrayElement(source[type]);
const values = source[type];
assertLocaleData(values, 'date.month', type);
return this.faker.helpers.arrayElement(values);
}

/**
Expand Down Expand Up @@ -1260,12 +1265,8 @@ export class DateModule extends SimpleDateModule {
context?: boolean;
} = {}
): string {
const {
// eslint-disable-next-line deprecation/deprecation
abbr,
abbreviated = abbr ?? false,
context = false,
} = options;
// eslint-disable-next-line deprecation/deprecation
const { abbr, abbreviated = abbr ?? false, context = false } = options;

if (abbr != null) {
deprecated({
Expand All @@ -1286,6 +1287,8 @@ export class DateModule extends SimpleDateModule {
type = useContext ? 'wide_context' : 'wide';
}

return this.faker.helpers.arrayElement(source[type]);
const values = source[type];
assertLocaleData(values, 'date.weekday', type);
return this.faker.helpers.arrayElement(values);
}
}
Loading

0 comments on commit 7e3c92e

Please sign in to comment.