Skip to content

Commit ba00cb8

Browse files
committed
perf(scripts): hoist regexes
1 parent 05ff554 commit ba00cb8

File tree

7 files changed

+83
-15
lines changed

7 files changed

+83
-15
lines changed

scripts/build-languages.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import { $ } from "bun";
22
import hljs from "highlight.js";
33
import type { ModuleNames } from "./build-styles";
44
import { createMarkdown } from "./utils/create-markdown";
5+
import { CONTAINS_DASH, STARTS_WITH_DIGIT } from "./utils/regexes";
56
import { toCamelCase } from "./utils/to-camel-case";
67
import { writeTo } from "./utils/write-to";
78

@@ -28,8 +29,8 @@ export async function buildLanguages() {
2829
for (const name of languages) {
2930
let moduleName = name;
3031

31-
if (/^[0-9]/.test(name)) moduleName = `_${name}`;
32-
if (/-/.test(name)) moduleName = toCamelCase(name);
32+
if (STARTS_WITH_DIGIT.test(name)) moduleName = `_${name}`;
33+
if (CONTAINS_DASH.test(name)) moduleName = toCamelCase(name);
3334

3435
base += `export { default as ${moduleName} } from './${name}';\n`;
3536
baseTs += `export declare const ${moduleName}: LanguageType<"${name}">;\n`;

scripts/build-styles.ts

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,13 @@ import { $, Glob } from "bun";
33
import { createMarkdown } from "./utils/create-markdown";
44
import { postcssScopedStyles } from "./utils/postcss-scoped-styles";
55
import { preprocessStyles } from "./utils/preprocess-styles";
6+
import {
7+
BACKTICK,
8+
CSS_FILE,
9+
DEFAULT_STRING,
10+
NON_MINIFIED_CSS,
11+
STARTS_WITH_DIGIT,
12+
} from "./utils/regexes";
613
import { toCamelCase } from "./utils/to-camel-case";
714
import { writeTo } from "./utils/write-to";
815

@@ -29,11 +36,14 @@ export async function buildStyles() {
2936

3037
for await (const file of glob.scan("node_modules/highlight.js/styles")) {
3138
const absPath = path.resolve("node_modules/highlight.js/styles", file);
32-
if (/(?<!\.min)\.(css)$/.test(file)) {
39+
if (NON_MINIFIED_CSS.test(file)) {
3340
let { name, dir } = path.parse(file);
3441
let moduleName = toCamelCase(name);
3542

36-
if (/^[0-9]/.test(moduleName) || /^default$/.test(moduleName)) {
43+
if (
44+
STARTS_WITH_DIGIT.test(moduleName) ||
45+
DEFAULT_STRING.test(moduleName)
46+
) {
3747
moduleName = `_${moduleName}`;
3848
}
3949

@@ -46,7 +56,7 @@ export async function buildStyles() {
4656
styles.push({ name, moduleName });
4757
cssFiles.push({ file, absPath, name, dir, moduleName });
4858
} else {
49-
if (!/\.(css)$/.test(file)) {
59+
if (!CSS_FILE.test(file)) {
5060
copyCommands.push(absPath);
5161
}
5262
}
@@ -65,7 +75,7 @@ export async function buildStyles() {
6575
const cssMinified = preprocessStyles(content, {
6676
discardComments: "preserve-license",
6777
});
68-
const contentCssForJs = cssMinified.replace(/`/g, "\\`");
78+
const contentCssForJs = cssMinified.replace(BACKTICK, "\\`");
6979

7080
const exportee = `const ${moduleName} = \`<style>${contentCssForJs}</style>\`;\n
7181
export default ${moduleName};\n`;

scripts/utils/postcss-scoped-styles.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import type { Plugin } from "postcss";
2+
import { PRE_SELECTOR } from "./regexes";
23

34
/**
45
* Scopes CSS selectors to a given module name.
@@ -16,8 +17,8 @@ export const postcssScopedStyles = (moduleName: string): Plugin => {
1617
Once(root) {
1718
root.walkRules((rule) => {
1819
rule.selectors = rule.selectors.map((selector) => {
19-
if (/^pre /.test(selector)) {
20-
selector = `pre.${moduleName}${selector.replace(/^pre /, " ")}`;
20+
if (PRE_SELECTOR.test(selector)) {
21+
selector = `pre.${moduleName}${selector.replace(PRE_SELECTOR, " ")}`;
2122
} else {
2223
selector = `.${moduleName} ${selector}`;
2324
}

scripts/utils/preprocess-styles.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import postcss, { type Plugin } from "postcss";
44
import discardDuplicates from "postcss-discard-duplicates";
55
import { inlineCssVars } from "postcss-inline-css-vars";
66
import mergeRules from "postcss-merge-rules";
7+
import { LICENSE_OR_AUTHOR } from "./regexes";
78

89
/**
910
* Raw styles from `highlight.js` are preprocessed for consistency.
@@ -32,7 +33,7 @@ export const preprocessStyles = (
3233
options?.discardComments === "preserve-license"
3334
? {
3435
remove: (comment) => {
35-
if (/(License|Author)/i.test(comment)) {
36+
if (LICENSE_OR_AUTHOR.test(comment)) {
3637
// Preserve license comments.
3738
return false;
3839
}

scripts/utils/regexes.ts

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
/**
2+
* Shared regex patterns used across build scripts
3+
*/
4+
5+
/** Matches strings that start with a digit */
6+
export const STARTS_WITH_DIGIT = /^[0-9]/;
7+
8+
/** Matches strings containing a dash */
9+
export const CONTAINS_DASH = /-/;
10+
11+
/** Matches CSS files that are not minified (negative lookbehind for .min) */
12+
export const NON_MINIFIED_CSS = /(?<!\.min)\.(css)$/;
13+
14+
/** Matches CSS files */
15+
export const CSS_FILE = /\.(css)$/;
16+
17+
/** Matches the exact string "default" */
18+
export const DEFAULT_STRING = /^default$/;
19+
20+
/** Matches backticks (for escaping in template literals) */
21+
export const BACKTICK = /`/g;
22+
23+
/** Matches dash or period (for splitting strings) */
24+
export const DASH_OR_PERIOD = /-|\./g;
25+
26+
/** Matches "License" or "Author" (case insensitive) */
27+
export const LICENSE_OR_AUTHOR = /(License|Author)/i;
28+
29+
/** Matches selectors starting with "pre " */
30+
export const PRE_SELECTOR = /^pre /;
31+
32+
/** Matches Windows line endings (CRLF) */
33+
export const WINDOWS_LINE_ENDING = /\r\n/g;
34+
35+
/** Matches trailing spaces or tabs at the end of lines */
36+
export const TRAILING_WHITESPACE = /[ \t]+$/gm;
37+
38+
/** Matches leading newlines at the start of a string */
39+
export const LEADING_NEWLINES = /^\n+/;
40+
41+
/** Matches 3 or more consecutive newlines */
42+
export const MULTIPLE_NEWLINES = /\n{3,}/g;
43+
44+
/** Matches trailing newlines at the end of a string */
45+
export const TRAILING_NEWLINES = /\n*$/;

scripts/utils/to-camel-case.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
import { DASH_OR_PERIOD } from "./regexes";
2+
13
/**
24
* Converts a dash/period separated string into pascal case
35
* @example
@@ -6,7 +8,7 @@
68
*/
79
export const toCamelCase = (str: string) =>
810
str
9-
.split(new RegExp(/-|\./g))
11+
.split(DASH_OR_PERIOD)
1012
.map((fragment, index) => {
1113
if (index === 0) return fragment;
1214
return [fragment.slice(0, 1).toUpperCase(), fragment.slice(1)].join("");

scripts/utils/write-to.ts

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,26 @@
1+
import {
2+
LEADING_NEWLINES,
3+
MULTIPLE_NEWLINES,
4+
TRAILING_NEWLINES,
5+
TRAILING_WHITESPACE,
6+
WINDOWS_LINE_ENDING,
7+
} from "./regexes";
8+
19
function formatMarkdown(content: string): string {
210
// Normalize line endings
3-
let formatted = content.replace(/\r\n/g, "\n");
11+
let formatted = content.replace(WINDOWS_LINE_ENDING, "\n");
412

513
// Remove trailing whitespace from each line
6-
formatted = formatted.replace(/[ \t]+$/gm, "");
14+
formatted = formatted.replace(TRAILING_WHITESPACE, "");
715

816
// Remove leading blank lines
9-
formatted = formatted.replace(/^\n+/, "");
17+
formatted = formatted.replace(LEADING_NEWLINES, "");
1018

1119
// Normalize blank lines: collapse 3+ consecutive newlines into exactly 2 newlines (one blank line)
12-
formatted = formatted.replace(/\n{3,}/g, "\n\n");
20+
formatted = formatted.replace(MULTIPLE_NEWLINES, "\n\n");
1321

1422
// Ensure file ends with single newline
15-
formatted = formatted.replace(/\n*$/, "\n");
23+
formatted = formatted.replace(TRAILING_NEWLINES, "\n");
1624

1725
return formatted;
1826
}

0 commit comments

Comments
 (0)