Skip to content

Commit

Permalink
Strict null checks -- 93.2% (#8961)
Browse files Browse the repository at this point in the history
* JQueryReaderOptions

* getAllReaders

* auto-add

* Tabs.tsx

* ApiTaskOptions.tsx

* PushOptions.tsx

* ActivateModDefinitionPage.tsx

* auto-add

* DeploymentModal.tsx

* auto-add

* ListView.tsx

* test updates

* auto-add

* ConvertToModModalBody.tsx

* auto-add

* CancelPublishContent.tsx

* EditPublishContent.tsx

* PublishedContent.tsx

* PublishModContent.tsx

* auto-add

* PublishModModals.tsx

* auto-add

* ModEditorPane.tsx

* cleanup type
  • Loading branch information
grahamlangford authored Aug 1, 2024
1 parent eca5e85 commit 0c48253
Show file tree
Hide file tree
Showing 26 changed files with 179 additions and 85 deletions.
6 changes: 3 additions & 3 deletions src/bricks/readers/getAllReaders.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,8 @@ import { ImageReader } from "./ImageReader";
import { SelectionReader } from "./SelectionReader";
import { ImageExifReader } from "./ImageExifReader";
import { ElementReader } from "./ElementReader";
import { registerFactory } from "./factory";
import { frameworkReadFactory } from "./frameworkReader";
import { type Read, registerFactory } from "./factory";
import { type FrameworkConfig, frameworkReadFactory } from "./frameworkReader";
import { readJQuery } from "@/bricks/readers/jquery";
import { HtmlReader } from "./HtmlReader";
import DocumentReader from "./DocumentReader";
Expand Down Expand Up @@ -59,7 +59,7 @@ export function registerReaderFactories(): void {
registerFactory("react", frameworkReadFactory("react"));
registerFactory("vue", frameworkReadFactory("vue"));
registerFactory("vuejs", frameworkReadFactory("vue"));
registerFactory("jquery", readJQuery);
registerFactory("jquery", readJQuery as unknown as Read<FrameworkConfig>);
}

export default getAllReaders;
19 changes: 12 additions & 7 deletions src/bricks/transformers/jquery/JQueryReaderOptions.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,8 @@ import { joinName } from "@/utils/formUtils";
import { freshIdentifier } from "@/utils/variableUtils";
import useAsyncEffect from "use-async-effect";
import { inspectedTab } from "@/pageEditor/context/connection";
import { assertNotNullish } from "@/utils/nullishUtils";
import { type SetOptional } from "type-fest";

/**
* Version of SelectorConfig where fields may be expressions.
Expand Down Expand Up @@ -182,9 +184,9 @@ const SelectorCard: React.FC<{
*/
onChange: (item: SelectorItem) => void;
/**
* Delete handler, or null if selector item cannot be deleted.
* Delete handler, or undefined if selector item cannot be deleted.
*/
onDelete: (() => void) | null;
onDelete: (() => void) | undefined;
/**
* The Formik path to selector configuration.
*/
Expand Down Expand Up @@ -225,9 +227,11 @@ const SelectorCard: React.FC<{

return [];
}, [selectorDefinition.selector, rootSelector]),
[],
[] as AttributeExample[],
);

assertNotNullish(attributeExamples, "attributeExamples is nullish");

const typeOption = inferActiveTypeOption(selectorDefinition);
const typeOptions = typeOptionsFactory(attributeExamples, typeOption);

Expand Down Expand Up @@ -313,9 +317,10 @@ const SelectorCard: React.FC<{
selector: produce(selectorDefinition, (draft) => {
// `draft` is either a SingleSelector or a ChildrenSelector. Cast as intersection type so we can clean
// up the values in the alternative type.
const commonDraft = draft as SingleSelector & ChildrenSelector;
const commonDraft = draft as SingleSelector &
SetOptional<ChildrenSelector, "find">;

if (next.startsWith(ATTRIBUTE_OPTION_VALUE_PREFIX)) {
if (next?.startsWith(ATTRIBUTE_OPTION_VALUE_PREFIX)) {
const attributeName = next.slice(
ATTRIBUTE_OPTION_VALUE_PREFIX.length,
);
Expand Down Expand Up @@ -376,7 +381,7 @@ const SelectorCard: React.FC<{

const SelectorsOptions: React.FC<{
path: string;
rootSelector: string;
rootSelector: string | null;
nestingLevel: number;
}> = ({ path, rootSelector, nestingLevel }) => {
const configName = partial(joinName, path);
Expand Down Expand Up @@ -468,7 +473,7 @@ const SelectorsOptions: React.FC<{
selectorItems.filter((_, i) => i !== index),
);
}
: null
: undefined
}
path={configName(name)}
/>
Expand Down
3 changes: 2 additions & 1 deletion src/contrib/automationanywhere/RunApiTask.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,9 @@ import { type ApiTaskArgs } from "@/contrib/automationanywhere/aaTypes";
import { type BrickArgs, type BrickOptions } from "@/types/runtimeTypes";
import { BusinessError } from "@/errors/businessErrors";
import { minimalSchemaFactory } from "@/utils/schemaUtils";
import { type SetRequired } from "type-fest";

export const RUN_API_TASK_INPUT_SCHEMA: Schema = {
export const RUN_API_TASK_INPUT_SCHEMA: SetRequired<Schema, "properties"> = {
$schema: "https://json-schema.org/draft/2019-09/schema#",
type: "object",
properties: {
Expand Down
2 changes: 1 addition & 1 deletion src/contrib/zapier/PushOptions.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ function useHooks(): AsyncState<Webhook[]> {
}

const ZapField: React.FunctionComponent<
SchemaFieldProps & { hooks: Webhook[]; error: unknown }
SchemaFieldProps & { hooks?: Webhook[]; error: unknown }
> = ({ hooks, error, ...props }) => {
const options = useMemo(
() =>
Expand Down
2 changes: 1 addition & 1 deletion src/extensionConsole/pages/activateMod/ActivateModCard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ const WizardHeader: React.VoidFunctionComponent<{
const ActivateModCard: React.FC<{
modDefinition: ModDefinition;
isReactivate: boolean;
forceModComponentId: UUID;
forceModComponentId?: UUID;
}> = ({ modDefinition, isReactivate, forceModComponentId }) => {
const dispatch = useDispatch();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ import { BusinessError } from "@/errors/businessErrors";
import { DefinitionKinds } from "@/types/registryTypes";
import { truncate } from "lodash";
import { type UUID } from "@/types/stringTypes";
import { assertNotNullish } from "@/utils/nullishUtils";

/**
* Effect to automatically redirect the user to the mods screen if the mod is not found.
Expand Down Expand Up @@ -114,12 +115,13 @@ const ActivateModDefinitionPage: React.FC<{
}

const title = `${isReactivate ? "Reactivate" : "Activate"} ${truncate(
modDefinition.metadata.name,
modDefinition?.metadata.name,
{
length: 15,
},
)}`;

assertNotNullish(modDefinitionQuery.data, "modDefinition is nullish");
// Require that bricks have been fetched at least once before showing. Handles new mod activation where the bricks
// haven't been completely fetched yet.
// XXX: we might also want to enforce a full re-sync of the brick registry to ensure the latest brick
Expand Down
4 changes: 2 additions & 2 deletions src/extensionConsole/pages/deployments/DeploymentModal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -58,11 +58,11 @@ function useCurrentTime() {
*/
export const CountdownTimer: React.FunctionComponent<{
duration: number;
start: number;
start: number | null;
onFinish?: () => void;
}> = ({ duration, start, onFinish = noop }) => {
const now = useCurrentTime();
const remaining = duration - (now - start);
const remaining = duration - (now - Number(start));
const isExpired = remaining < 0;

useEffect(() => {
Expand Down
3 changes: 3 additions & 0 deletions src/extensionConsole/pages/mods/listView/ListView.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import ListGroupHeader from "@/extensionConsole/pages/mods/listView/ListGroupHea
import { uuidv4 } from "@/types/helpers";
import ListItemErrorBoundary from "@/extensionConsole/pages/mods/listView/ListItemErrorBoundary";
import { type ModsPageContentProps } from "@/extensionConsole/pages/mods/modsPageTypes";
import { assertNotNullish } from "@/utils/nullishUtils";

const ROW_HEIGHT_PX = 90;
const HEADER_ROW_HEIGHT_PX = 43;
Expand All @@ -42,6 +43,7 @@ const ListView: React.VoidFunctionComponent<ModsPageContentProps> = ({
const getItemSize = useCallback(
(index: number) => {
const row = expandedRows.at(index);
assertNotNullish(row, `Unable to find row at index ${index}`);
return row.isGrouped ? HEADER_ROW_HEIGHT_PX : ROW_HEIGHT_PX;
},
[expandedRows],
Expand All @@ -66,6 +68,7 @@ const ListView: React.VoidFunctionComponent<ModsPageContentProps> = ({
>
{({ index, style }) => {
const row = expandedRows.at(index);
assertNotNullish(row, `Unable to find row at index ${index}`);
tableInstance.prepareRow(row);

return row.isGrouped ? (
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ import { generatePackageId } from "@/utils/registryUtils";
import { FieldDescriptions } from "@/modDefinitions/modDefinitionConstants";

import { pickModDefinitionMetadata } from "@/modDefinitions/util/pickModDefinitionMetadata";
import { assertNotNullish } from "@/utils/nullishUtils";

type ConvertModFormState = {
blueprintId: RegistryId;
Expand Down Expand Up @@ -125,7 +126,7 @@ const ConvertToModModalBody: React.FunctionComponent = () => {
standaloneModDefinitions?.find((x) => x.id === modComponentId);
if (modComponent == null) {
throw new Error(
`No persisted extension exists with id: ${modComponentId}`,
`No persisted mod component exists with id: ${modComponentId}`,
);
}

Expand All @@ -136,8 +137,8 @@ const ConvertToModModalBody: React.FunctionComponent = () => {

const initialValues: ConvertModFormState = useMemo(
() => ({
blueprintId: generatePackageId(scope, modComponent.label),
name: modComponent.label,
blueprintId: generatePackageId(scope, modComponent?.label),
name: modComponent?.label ?? "",
version: normalizeSemVerString("1.0.0"),
description: "Created with the PixieBrix Page Editor",
}),
Expand All @@ -156,6 +157,7 @@ const ConvertToModModalBody: React.FunctionComponent = () => {
helpers: FormikHelpers<ConvertModFormState>,
) => {
try {
assertNotNullish(modComponent, "modComponent is nullish");
const unsavedModDefinition = mapModComponentToUnsavedModDefinition(
modComponent,
{
Expand Down Expand Up @@ -212,7 +214,7 @@ const ConvertToModModalBody: React.FunctionComponent = () => {
);
}
} catch (error) {
if (isSingleObjectBadRequestError(error) && error.response.data.config) {
if (isSingleObjectBadRequestError(error) && error.response?.data.config) {
helpers.setStatus(error.response.data.config);
return;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,14 +30,16 @@ import {
import notify from "@/utils/notify";
import { isSingleObjectBadRequestError } from "@/errors/networkErrorHelpers";
import { getErrorMessage } from "@/errors/errorHelpers";
import { assertNotNullish } from "@/utils/nullishUtils";

const CancelPublishContent: React.FunctionComponent = () => {
const [isCancelling, setCancelling] = React.useState(false);
const [error, setError] = React.useState<string | null>(null);

const { blueprintId } = useSelector(selectShowPublishContext);
const { blueprintId: modId = null } =
useSelector(selectShowPublishContext) ?? {};
const { data: modDefinition, refetch: refetchModDefinitions } =
useOptionalModDefinition(blueprintId);
useOptionalModDefinition(modId);
const { data: editablePackages, isFetching: isFetchingEditablePackages } =
useGetEditablePackagesQuery();

Expand All @@ -53,14 +55,23 @@ const CancelPublishContent: React.FunctionComponent = () => {
setError(null);

try {
assertNotNullish(
modDefinition,
`modDefinition for modId: ${modId} is nullish`,
);
const newModDefinition = produce(modDefinition, (draft) => {
draft.sharing.public = false;
});

assertNotNullish(editablePackages, "editablePackages is nullish");
const packageId = editablePackages.find(
(x) => x.name === newModDefinition.metadata.id,
)?.id;

assertNotNullish(
packageId,
`packageId for metadata id ${newModDefinition.metadata.id} is nullish`,
);
await updateModDefinition({
packageId,
modDefinition: newModDefinition,
Expand All @@ -73,9 +84,10 @@ const CancelPublishContent: React.FunctionComponent = () => {
} catch (error) {
if (
isSingleObjectBadRequestError(error) &&
error.response.data.config?.length > 0
Number(error.response?.data.config?.length) > 0
) {
setError(error.response.data.config.join(" "));
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion, @typescript-eslint/no-unnecessary-type-assertion -- See if block above
setError(error.response!.data.config!.join(" "));
} else {
const message = getErrorMessage(error);
setError(message);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ import ActivationLink from "@/activation/ActivationLink";
import PublishContentLayout from "./PublishContentLayout";

import { MARKETPLACE_URL } from "@/urlConstants";
import { assertNotNullish } from "@/utils/nullishUtils";

const EditPublishContent: React.FunctionComponent = () => {
const dispatch = useDispatch();
Expand All @@ -36,7 +37,9 @@ const EditPublishContent: React.FunctionComponent = () => {
dispatch(modModalsSlice.actions.setCancelingPublish());
};

const { blueprintId } = useSelector(selectShowPublishContext);
const { blueprintId: modId } = useSelector(selectShowPublishContext) ?? {};

assertNotNullish(modId, "modId from publish context is nullish");

return (
<PublishContentLayout title="Edit Pending Publish">
Expand All @@ -57,7 +60,7 @@ const EditPublishContent: React.FunctionComponent = () => {
</p>

<p className="mb-1">Public link to share:</p>
<ActivationLink modId={blueprintId} />
<ActivationLink modId={modId} />
</Modal.Body>
<Modal.Footer>
<Button variant="danger" onClick={cancelPublish}>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,10 +33,13 @@ import { useOptionalModDefinition } from "@/modDefinitions/modDefinitionHooks";
import PublishContentLayout from "./PublishContentLayout";

import { MARKETPLACE_URL } from "@/urlConstants";
import { assertNotNullish } from "@/utils/nullishUtils";

const PublishModContent: React.FunctionComponent = () => {
const dispatch = useDispatch();
const { blueprintId: modId } = useSelector(selectShowPublishContext);
const { blueprintId: modId } = useSelector(selectShowPublishContext) ?? {};
assertNotNullish(modId, "modId from publish context is nullish");

const [updateModDefinition] = useUpdateModDefinitionMutation();
const { data: editablePackages, isFetching: isFetchingEditablePackages } =
useGetEditablePackagesQuery();
Expand All @@ -55,14 +58,23 @@ const PublishModContent: React.FunctionComponent = () => {
setError(null);

try {
assertNotNullish(
modDefinition,
`modDefinition for modId: ${modId} is nullish`,
);
const newModDefinition = produce(modDefinition, (draft) => {
draft.sharing.public = true;
});

assertNotNullish(editablePackages, "editablePackages is nullish");
const packageId = editablePackages.find(
(x) => x.name === newModDefinition.metadata.id,
)?.id;

assertNotNullish(
packageId,
`packageId metadata id: ${newModDefinition.metadata.id} is nullish`,
);
await updateModDefinition({
packageId,
modDefinition: newModDefinition,
Expand All @@ -74,9 +86,10 @@ const PublishModContent: React.FunctionComponent = () => {
} catch (error) {
if (
isSingleObjectBadRequestError(error) &&
error.response.data.config?.length > 0
Number(error.response?.data.config?.length) > 0
) {
setError(error.response.data.config.join(" "));
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion, @typescript-eslint/no-unnecessary-type-assertion -- See if block above
setError(error.response!.data.config!.join(" "));
} else {
const message = getErrorMessage(error);
setError(message);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,10 +27,12 @@ import { useOptionalModDefinition } from "@/modDefinitions/modDefinitionHooks";
import EditPublishContent from "./EditPublishContent";
import CancelPublishContent from "./CancelPublishContent";
import PublishedContent from "./PublishedContent";
import { assertNotNullish } from "@/utils/nullishUtils";

const ModalContentSwitch: React.FunctionComponent = () => {
const showPublishContext = useSelector(selectShowPublishContext);
const { blueprintId: modId, cancelingPublish } = showPublishContext;
const { blueprintId: modId, cancelingPublish } = showPublishContext ?? {};
assertNotNullish(modId, "modId not found in showPublishContext");
const { data: listing, isLoading: isLoadingListing } =
useGetMarketplaceListingQuery({ packageId: modId });
const { data: modDefinition, isLoading: isLoadingModDefinition } =
Expand All @@ -44,7 +46,7 @@ const ModalContentSwitch: React.FunctionComponent = () => {
);
}

if (!modDefinition.sharing.public) {
if (!modDefinition?.sharing.public) {
return <PublishModContent />;
}

Expand Down
Loading

0 comments on commit 0c48253

Please sign in to comment.