Skip to content
This repository has been archived by the owner on Jun 29, 2023. It is now read-only.

Commit

Permalink
fix: Give better feedback validating the module name (#2686)
Browse files Browse the repository at this point in the history
  • Loading branch information
bastilian authored Feb 13, 2023
1 parent 5d876e6 commit 81467cf
Show file tree
Hide file tree
Showing 3 changed files with 60 additions and 26 deletions.
48 changes: 22 additions & 26 deletions islands/AddModule.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,12 @@
import { useEffect, useRef, useState } from "preact/hooks";
import { IS_BROWSER } from "$fresh/runtime.ts";
import * as Icons from "@/components/Icons.tsx";
import { getVersionList } from "@/utils/registry_utils.ts";
import confetti from "$canvas-confetti";

const NAME_REGEX = /^[a-z0-9_]{3,40}$/;
import { getVersionList, validateModuleName } from "@/utils/registry_utils.ts";

interface ModuleState {
name: string;
available: boolean | "pending";
available: boolean | "pending" | "invalid";
registered: boolean;
}

Expand Down Expand Up @@ -42,35 +40,22 @@ export default function AddModule() {
const controller = new AbortController();

(async () => {
if (name === "" || !NAME_REGEX.test(name)) {
const available = await validateModuleName(name, controller);

if (!controller.signal.aborted) {
setModuleStateIfSameName({
name,
available: false,
available,
registered,
});
} else {
await getVersionList(name, controller.signal)
.then((e) => !e)
.catch(() => false)
.then((e) => {
if (controller.signal.aborted) {
return;
}

setModuleStateIfSameName({
name,
available: e,
registered,
});
});
}
})();

return () => controller.abort();
}, [name]);

useEffect(() => {
if (available === "pending" || !available) {
if (available === "pending" || available === false) {
return;
}

Expand Down Expand Up @@ -144,11 +129,22 @@ export default function AddModule() {
}}
disabled={!IS_BROWSER}
/>
{name && !available && (
{name && available === false && (
<p class="mt-1.5 text-danger text-sm">
Invalid Name/Name has been taken!
This name has already been taken!
</p>
)}
{name && available === "invalid" && (
<div>
<p class="mt-1.5 text-danger text-sm">
This module name is invalid.
</p>
<p class="text-sm text-[#6C6E78] mb-4">
A valid name can be 3-40 characters and only contain lower case
characters, numbers and `_`.
</p>
</div>
)}
</div>
</div>

Expand Down Expand Up @@ -188,7 +184,7 @@ export default function AddModule() {
<div>
<h2 class="text-default font-semibold text-xl leading-none">
Add the webhook
{available && !registered &&
{available === true && !registered &&
(
<div class="inline-flex ml-2 py-1 px-3 bg-[#4B505A] rounded-md text-white text-sm leading-tight font-medium items-center">
<Icons.Spinner />
Expand All @@ -214,7 +210,7 @@ export default function AddModule() {
{urlValue}
</span>
</div>
{available &&
{available === true &&
(
<button
class="rounded p-1.5 border border-[#D2D2DC] hover:bg-border"
Expand Down
14 changes: 14 additions & 0 deletions utils/registry_utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import type { DocNode } from "deno_doc/types";
import type { LibDocPage, ModuleEntry } from "$apiland_types";

const NAME_REGEX = /^[a-z0-9_]{3,40}$/;
export const CDN_ENDPOINT = "https://cdn.deno.land/";

export interface CommonProps<T> {
Expand Down Expand Up @@ -358,3 +359,16 @@ export function getDocAsDescription(
}
}
}

export async function validateModuleName(
name: string,
controller: AbortController,
) {
if (name === "" || !NAME_REGEX.test(name)) {
return "invalid";
} else {
return await getVersionList(name, controller.signal)
.then((e) => !e)
.catch(() => false);
}
}
24 changes: 24 additions & 0 deletions utils/registry_utils_test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import {
fileTypeFromURL,
getSourceURL,
getVersionList,
validateModuleName,
} from "./registry_utils.ts";
import { assert, assertEquals } from "$std/testing/asserts.ts";

Expand Down Expand Up @@ -113,3 +114,26 @@ Deno.test("extractLinkUrl", () => {
undefined,
);
});

Deno.test("validateModuleName", async () => {
const controller = new AbortController();
controller.abort();

assertEquals(
await validateModuleName("hello-world", controller),
"invalid",
);

assertEquals(
await validateModuleName("hello", controller),
false,
);

assertEquals(
await validateModuleName(
"defuniq" + parseInt(`${Math.random() * 1000}`),
new AbortController(),
),
true,
);
});

0 comments on commit 81467cf

Please sign in to comment.