Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(svelte): Track components without <script> tags #5930

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
31 changes: 31 additions & 0 deletions packages/svelte/src/preprocessors.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,31 @@ export const defaultComponentTrackingOptions: Required<ComponentTrackingInitOpti
export function componentTrackingPreprocessor(options?: ComponentTrackingInitOptions): PreprocessorGroup {
const mergedOptions = { ...defaultComponentTrackingOptions, ...options };

const visitedFilesMarkup = new Set<string>();
const visitedFiles = new Set<string>();

return {
// This preprocessor hook is called once per .svelte component file, before the `script` hook is called
// We use it to check if the passed component has a <script> tag. If it doesn't, we add one to inject our
// code later on, when the `script` hook is executed.
markup: ({ content, filename }) => {
const finalFilename = filename || 'unknown';
const shouldInject = shouldInjectFunction(mergedOptions.trackComponents, finalFilename, {}, visitedFilesMarkup);

if (shouldInject && !hasScriptTag(content)) {
// Insert a <script> tag into the component file where we can later on inject our code.
// We have to add a placeholder to the script tag because for empty script tags,
// the `script` preprocessor hook won't be called
// Note: The space between <script> and </script> is important! Without any content,
// the `script` hook wouldn't be executed for the added script tag.
const s = new MagicString(content);
s.prepend('<script> </script>\n');
return { code: s.toString(), map: s.generateMap().toString() };
}

return { code: content };
},

// This script hook is called whenever a Svelte component's <script>
// content is preprocessed.
// `content` contains the script code as a string
Expand Down Expand Up @@ -83,6 +105,15 @@ function shouldInjectFunction(
return true;
}

function hasScriptTag(content: string): boolean {
// This is not a super safe way of checking for the presence of a <script> tag in the Svelte
// component file but I think we can use it as a start.
// A case that is not covered by regex-testing HTML is e.g. nested <script> tags but I cannot
// think of why one would do this in Svelte components.
// Also, we just want to know if there is a <script> tag in the entire file content; not if
return /<script(\s+.+)?>.*<\/script>/s.test(content);

Check failure

Code scanning / CodeQL

Polynomial regular expression used on uncontrolled data

This [regular expression](1) that depends on [library input](2) may run slow on strings starting with '<script ' and with many repetitions of ' '. This [regular expression](3) that depends on [library input](2) may run slow on strings starting with '<script>' and with many repetitions of 'a>'.

Check failure

Code scanning / CodeQL

Bad HTML filtering regexp

This regular expression does not match upper case <SCRIPT> tags.
}

function getBaseName(filename: string): string {
const segments = filename.split('/');
return segments[segments.length - 1].replace('.svelte', '');
Expand Down