Skip to content

Commit

Permalink
Enable TypeScript strictNullChecks across the codebase
Browse files Browse the repository at this point in the history
  • Loading branch information
petebacondarwin committed Jan 12, 2022
1 parent fff0e13 commit c7aa4ae
Show file tree
Hide file tree
Showing 18 changed files with 287 additions and 245 deletions.
14 changes: 12 additions & 2 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,22 @@
"esbuild",
"estree",
"execa",
"extensionless",
"iarna",
"keyvalue",
"middlewares",
"Miniflare",
"outdir",
"outfile",
"Positionals"
]
"pgrep",
"PKCE",
"Positionals",
"undici",
"wasmvalue",
"weakmap",
"weakset",
"webassemblymemory",
"websockets"
],
"cSpell.ignoreWords": ["yxxx"]
}
16 changes: 8 additions & 8 deletions packages/wrangler/pages/functions/filepath-routing.ts
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ export async function generateConfigFromFileTree({
const declaration = node.declaration;

// `export async function onRequest() {...}`
if (declaration.type === "FunctionDeclaration") {
if (declaration.type === "FunctionDeclaration" && declaration.id) {
exportNames.push(declaration.id.name);
}

Expand Down Expand Up @@ -155,12 +155,10 @@ export async function generateConfigFromFileTree({
// more specific routes aren't occluded from matching due to
// less specific routes appearing first in the route list.
export function compareRoutes(a: string, b: string) {
function parseRoutePath(routePath: string) {
let [method, segmentedPath] = routePath.split(" ");
if (!segmentedPath) {
segmentedPath = method;
method = null;
}
function parseRoutePath(routePath: string): [string | null, string[]] {
const parts = routePath.split(" ", 2);
const segmentedPath = parts.pop() ?? "";
const method = parts.pop() ?? null;

const segments = segmentedPath.slice(1).split("/").filter(Boolean);
return [method, segments];
Expand Down Expand Up @@ -205,7 +203,9 @@ async function forEachFile<T>(
const returnValues: T[] = [];

while (searchPaths.length) {
const cwd = searchPaths.shift();
// The `searchPaths.length` check above ensures that `searchPaths.shift()` is defined
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
const cwd = searchPaths.shift()!;
const dir = await fs.readdir(cwd, { withFileTypes: true });
for (const entry of dir) {
const pathname = path.join(cwd, entry.name);
Expand Down
2 changes: 1 addition & 1 deletion packages/wrangler/pages/functions/routes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,7 @@ export function parseConfig(config: Config, baseDir: string) {
});
}

for (const [route, props] of Object.entries(config.routes)) {
for (const [route, props] of Object.entries(config.routes ?? {})) {
let [_methods, routePath] = route.split(" ");
if (!routePath) {
routePath = _methods;
Expand Down
40 changes: 17 additions & 23 deletions packages/wrangler/pages/functions/template-worker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -110,29 +110,23 @@ export default {
}

const { value } = handlerIterator.next();
if (value) {
const { handler, params } = value;
const context: EventContext<
unknown,
string,
Record<string, unknown>
> = {
request: new Request(request.clone()),
next,
params,
data,
env,
waitUntil: workerContext.waitUntil.bind(workerContext),
};

const response = await handler(context);

// https://fetch.spec.whatwg.org/#null-body-status
return new Response(
[101, 204, 205, 304].includes(response.status) ? null : response.body,
response
);
}
const { handler, params } = value;
const context: EventContext<unknown, string, Record<string, unknown>> = {
request: new Request(request.clone()),
next,
params,
data,
env,
waitUntil: workerContext.waitUntil.bind(workerContext),
};

const response = await handler(context);

// https://fetch.spec.whatwg.org/#null-body-status
return new Response(
[101, 204, 205, 304].includes(response.status) ? null : response.body,
response
);
};

try {
Expand Down
14 changes: 9 additions & 5 deletions packages/wrangler/src/__tests__/kv.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -212,7 +212,7 @@ describe("wrangler", () => {

it("should make multiple requests for paginated results", async () => {
// Create a lot of mock namespaces, so that the fetch requests will be paginated
const KVNamespaces = [];
const KVNamespaces: { title: string; id: string }[] = [];
for (let i = 0; i < 550; i++) {
KVNamespaces.push({ title: "title-" + i, id: "id-" + i });
}
Expand Down Expand Up @@ -335,8 +335,12 @@ describe("wrangler", () => {
expect(namespaceId).toEqual(expectedNamespaceId);
expect(key).toEqual(expectedKey);
expect(body).toEqual(expectedValue);
expect(query.get("expiration")).toEqual(`${expiration}`);
expect(query.get("expiration_ttl")).toEqual(`${expirationTtl}`);
if (expiration) {
expect(query.get("expiration")).toEqual(`${expiration}`);
}
if (expirationTtl) {
expect(query.get("expiration_ttl")).toEqual(`${expirationTtl}`);
}
return null;
}
);
Expand Down Expand Up @@ -681,7 +685,7 @@ describe("wrangler", () => {
if (expectedKeys.length <= keysPerRequest) {
return createFetchResult(expectedKeys);
} else {
const start = parseInt(query.get("cursor")) || 0;
const start = parseInt(query.get("cursor") ?? "0") || 0;
const end = start + keysPerRequest;
const cursor = end < expectedKeys.length ? end : undefined;
return createFetchResult(
Expand Down Expand Up @@ -778,7 +782,7 @@ describe("wrangler", () => {

it("should make multiple requests for paginated results", async () => {
// Create a lot of mock keys, so that the fetch requests will be paginated
const keys = [];
const keys: string[] = [];
for (let i = 0; i < 550; i++) {
keys.push("key-" + i);
}
Expand Down
8 changes: 4 additions & 4 deletions packages/wrangler/src/__tests__/mock-cfetch.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import type { RequestInit } from "node-fetch";
import type { URLSearchParams } from "node:url";
import { URLSearchParams } from "node:url";
import { pathToRegexp } from "path-to-regexp";
import { CF_API_BASE_URL } from "../cfetch";
import type { FetchResult } from "../cfetch";
Expand All @@ -9,8 +9,8 @@ import type { FetchResult } from "../cfetch";
*/
export type MockHandler<ResponseType> = (
uri: RegExpExecArray,
init?: RequestInit,
queryParams?: URLSearchParams
init: RequestInit,
queryParams: URLSearchParams
) => ResponseType;

type RemoveMockFn = () => void;
Expand All @@ -32,7 +32,7 @@ const mocks: MockFetch<unknown>[] = [];
export async function mockFetchInternal(
resource: string,
init: RequestInit = {},
queryParams?: URLSearchParams
queryParams: URLSearchParams = new URLSearchParams()
) {
for (const { regexp, method, handler } of mocks) {
const resourcePath = new URL(resource, CF_API_BASE_URL).pathname;
Expand Down
2 changes: 1 addition & 1 deletion packages/wrangler/src/api/form_data.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ export function toMimeType(type: CfModuleType): string {
}
}

function toModule(module: CfModule, entryType?: CfModuleType): Blob {
function toModule(module: CfModule, entryType: CfModuleType): Blob {
const { type: moduleType, content } = module;
const type = toMimeType(moduleType ?? entryType);

Expand Down
12 changes: 4 additions & 8 deletions packages/wrangler/src/cfetch/internal.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import fetch from "node-fetch";
import type { RequestInit, HeadersInit } from "node-fetch";
import fetch, { Headers } from "node-fetch";
import type { RequestInit } from "node-fetch";
import { getAPIToken, loginOrRefreshIfRequired } from "../user";

export const CF_API_BASE_URL =
Expand All @@ -21,7 +21,7 @@ export async function fetchInternal<ResponseType>(
): Promise<ResponseType> {
await requireLoggedIn();
const apiToken = requireApiToken();
const headers = cloneHeaders(init.headers);
const headers = new Headers(init.headers);
addAuthorizationHeader(headers, apiToken);

const queryString = queryParams ? `?${queryParams.toString()}` : "";
Expand Down Expand Up @@ -55,11 +55,7 @@ function requireApiToken(): string {
return apiToken;
}

function cloneHeaders(headers: HeadersInit): HeadersInit {
return { ...headers };
}

function addAuthorizationHeader(headers: HeadersInit, apiToken: string): void {
function addAuthorizationHeader(headers: Headers, apiToken: string): void {
if (headers["Authorization"]) {
throw new Error(
"The request already specifies an authorisation header - cannot add a new one."
Expand Down
50 changes: 29 additions & 21 deletions packages/wrangler/src/dev.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ function Dev(props: DevProps): JSX.Element {
"You cannot use the service worker format with a `public` directory."
);
}
const port = props.port || 8787;
const port = props.port ?? 8787;
const apiToken = getAPIToken();
const directory = useTmpDir();

Expand Down Expand Up @@ -98,7 +98,7 @@ function Dev(props: DevProps): JSX.Element {
bindings={props.bindings}
site={props.site}
public={props.public}
port={props.port}
port={port}
/>
) : (
<Remote
Expand Down Expand Up @@ -135,7 +135,7 @@ function Remote(props: {
format: CfScriptFormat;
public: undefined | string;
site: undefined | string;
port: number;
port: undefined | number;
accountId: undefined | string;
apiToken: undefined | string;
bindings: CfWorkerInit["bindings"];
Expand Down Expand Up @@ -259,11 +259,11 @@ function useLocalWorker(props: {
}
});

local.current.stdout.on("data", (data: Buffer) => {
local.current.stdout?.on("data", (data: Buffer) => {
console.log(`${data.toString()}`);
});

local.current.stderr.on("data", (data: Buffer) => {
local.current.stderr?.on("data", (data: Buffer) => {
console.error(`${data.toString()}`);
const matches =
/Debugger listening on (ws:\/\/127\.0\.0\.1:9229\/[A-Za-z0-9-]+)/.exec(
Expand Down Expand Up @@ -357,7 +357,7 @@ function useCustomBuild(
): undefined | string {
const [entry, setEntry] = useState<string | undefined>(
// if there's no build command, just return the expected entry
props.command ? null : expectedEntry
props.command ? undefined : expectedEntry
);
const { command, cwd, watch_dir } = props;
useEffect(() => {
Expand Down Expand Up @@ -461,25 +461,35 @@ function useEsbuild(props: {
else {
// nothing really changes here, so let's increment the id
// to change the return object's identity
setBundle((previousBundle) => ({
...previousBundle,
id: previousBundle.id + 1,
}));
setBundle((previousBundle) => {
if (previousBundle === undefined) {
throw new Error(
"Rebuild triggered with no previous build available"
);
}
return { ...previousBundle, id: previousBundle.id + 1 };
});
}
},
},
});

const chunks = Object.entries(result.metafile.outputs).find(
// result.metafile is defined because of the `metafile: true` option above.
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
const outputEntry = Object.entries(result.metafile!.outputs).find(
([_path, { entryPoint }]) => entryPoint === entry
); // assumedly only one entry point

if (outputEntry === undefined) {
throw new Error(
`Cannot find entry-point "${entry}" in generated bundle.`
);
}
setBundle({
id: 0,
entry,
path: chunks[0],
type: chunks[1].exports.length > 0 ? "esm" : "commonjs",
exports: chunks[1].exports,
path: outputEntry[0],
type: outputEntry[1].exports.length > 0 ? "esm" : "commonjs",
exports: outputEntry[1].exports,
modules: moduleCollector.modules,
});
}
Expand All @@ -489,9 +499,7 @@ function useEsbuild(props: {
// on build errors anyway
// so this is a no-op error handler
});
return () => {
result?.stop();
};
return () => result.stop?.();
}, [entry, destination, staticRoot, jsxFactory, jsxFragment]);
return bundle;
}
Expand All @@ -505,7 +513,7 @@ function useWorker(props: {
apiToken: string;
bindings: CfWorkerInit["bindings"];
sitesFolder: undefined | string;
port: number;
port: undefined | number;
compatibilityDate: string | undefined;
compatibilityFlags: string[] | undefined;
usageModel: undefined | "bundled" | "unbound";
Expand Down Expand Up @@ -631,7 +639,7 @@ function useProxy({
}: {
token: CfPreviewToken | undefined;
publicRoot: undefined | string;
port: number;
port: undefined | number;
}) {
useEffect(() => {
if (!token) return;
Expand Down Expand Up @@ -697,7 +705,7 @@ const SLEEP_DURATION = 2000;
// really need a first class api for this
const hostNameRegex = /userHostname="(.*)"/g;
async function findTunnelHostname() {
let hostName: string;
let hostName: string | undefined;
while (!hostName) {
try {
const resp = await fetch("http://localhost:8789/metrics");
Expand Down
Loading

0 comments on commit c7aa4ae

Please sign in to comment.