Add name validation to snippets

This commit is contained in:
Andrew Kingston 2024-03-06 18:36:22 +00:00
parent 7dc67185ed
commit 01679fbd01
1 changed files with 19 additions and 12 deletions

View File

@ -17,6 +17,7 @@
export const hide = () => drawer.hide() export const hide = () => drawer.hide()
const roughValidNameRegex = /^[_$A-Z\xA0-\uFFFF][_$A-Z0-9\xA0-\uFFFF]*$/i const roughValidNameRegex = /^[_$A-Z\xA0-\uFFFF][_$A-Z0-9\xA0-\uFFFF]*$/i
const firstCharNumberRegex = /^[0-9].*$/
let drawer let drawer
let name = "" let name = ""
@ -26,7 +27,7 @@
$: name = snippet?.name || "MySnippet" $: name = snippet?.name || "MySnippet"
$: code = snippet?.code ? encodeJSBinding(snippet.code) : "" $: code = snippet?.code ? encodeJSBinding(snippet.code) : ""
$: rawJS = decodeJSBinding(code) $: rawJS = decodeJSBinding(code)
$: nameValid = validateName(name) $: nameError = validateName(name)
const saveSnippet = async () => { const saveSnippet = async () => {
await snippetStore.saveSnippet({ await snippetStore.saveSnippet({
@ -48,14 +49,20 @@
// try executing it and see if it's valid JS. The initial regex prevents // try executing it and see if it's valid JS. The initial regex prevents
// against any potential XSS attacks here. // against any potential XSS attacks here.
const validateName = name => { const validateName = name => {
if (!name?.length) {
return "Name is required"
}
if (firstCharNumberRegex.test(name)) {
return "Can't start with a number"
}
if (!roughValidNameRegex.test(name)) { if (!roughValidNameRegex.test(name)) {
return false return "No special characters or spaces"
} }
const js = `(function ${name}(){return true})()` const js = `(function ${name}(){return true})()`
try { try {
return eval(js) === true return eval(js) === true ? null : "Invalid name"
} catch (error) { } catch (error) {
return false return "Invalid name"
} }
} }
</script> </script>
@ -65,14 +72,11 @@
{#if snippet} {#if snippet}
{snippet.name} {snippet.name}
{:else} {:else}
<div class="name" class:invalid={!nameValid}> <div class="name" class:invalid={nameError != null}>
<span>Name</span> <span>Name</span>
<Input bind:value={name} /> <Input bind:value={name} />
{#if !nameValid} {#if nameError}
<AbsTooltip <AbsTooltip text={nameError} type={TooltipType.Negative}>
text="Alphanumeric characters only, with no spaces"
type={TooltipType.Negative}
>
<Icon <Icon
name="Help" name="Help"
size="S" size="S"
@ -87,7 +91,7 @@
{#if snippet} {#if snippet}
<Button warning on:click={deleteSnippet}>Delete</Button> <Button warning on:click={deleteSnippet}>Delete</Button>
{/if} {/if}
<Button cta on:click={saveSnippet} disabled={!rawJS?.length || !nameValid}> <Button cta on:click={saveSnippet} disabled={nameError != null}>
Save Save
</Button> </Button>
</svelte:fragment> </svelte:fragment>
@ -117,9 +121,12 @@
align-items: center; align-items: center;
position: relative; position: relative;
} }
.name.invalid :global(input) { .name :global(input) {
width: 200px; width: 200px;
} }
.name.invalid :global(input) {
padding-right: 32px;
}
.name :global(.icon) { .name :global(.icon) {
position: absolute; position: absolute;
right: 10px; right: 10px;