ReviewOS

stacks/stx

Scope registration misses every function declared after a regex literal containing a quote, so their template handlers never run

#2122
Closed glennmichael123 opened this 7 days ago ·
7 days ago

What happens

A component's top-level functions declared after a regex literal that contains a quote are not registered in its scope, so a template handler naming one of them resolves to nothing and never runs.

Seen in the Stacks dashboard (stacksjs/stacks#3008): TaxonomyEditorDialog has

function slugify(value: string): string {
  return value.normalize('NFKD').replace(/[̀-ͯ]/g, '').trim().toLowerCase()
    .replace(/['"]/g, '')            // <- the quote here
    .replace(/[^a-z0-9]+/g, '-')
}
// ...
function submit(): void { emit('submit', draft) }

and its form uses @submit.prevent="submit". The compiled scope registers open, kind, busy, error, name, slug, description, slugTouched, emit, wasOpen, slugify and stops: markSlugTouched, normalizeSlug, close and submit are missing. The form's handler never runs, nothing is emitted, and the parent's @submit listener receives the native SubmitEvent instead of the draft, so every content category and tag create posted {"isTrusted":true}.

Cause

extractVariableNames in packages/stx/src/utils.ts finds top-level declarations by scanning the transpiled script, skipping strings, template literals and comments. It has no notion of a regex literal, so the ' in /['"]/g reads as the start of a string, the scan jumps to the next quote in the file, and every declaration in between is missed. Any quote, backtick or brace inside a regex can do the same.

Fix

Recognise a regex literal the way the JS parser does: a / that follows an operator, an opening bracket, a separator, the start of the code or a keyword such as return starts one; after a name, number or closing bracket it divides. Skip it whole, honouring escapes and character classes (where / does not end it), plus its flags.

Sign in to comment on this issue.