Skip to content

Commit

Permalink
Merge pull request #171 from nguyenyou/snapshot
Browse files Browse the repository at this point in the history
feat: refactor code for using pipe pattern for transform source
  • Loading branch information
nguyenyou authored Dec 18, 2024
2 parents fe75ca4 + 3d59135 commit d00462c
Show file tree
Hide file tree
Showing 8 changed files with 551 additions and 130 deletions.
5 changes: 5 additions & 0 deletions .changeset/ninety-windows-turn.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"scalawind": patch
---

refactor code to use pipe pattern for transform source
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
"tsup": "^6.5.0",
"turbo": "^2.0.4"
},
"packageManager": "pnpm@9.4.0",
"packageManager": "pnpm@9.15.0",
"engines": {
"node": ">=18"
}
Expand Down
2 changes: 1 addition & 1 deletion packages/scalawind/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@
"@swc/cli": "^0.1.62",
"@swc/jest": "^0.2.26",
"@swc/register": "^0.1.10",
"bun": "^1.1.11",
"bun": "^1.1.40",
"tailwindcss": "^3.4.3"
},
"engines": {
Expand Down
48 changes: 48 additions & 0 deletions packages/scalawind/src/source-transform.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
// THIS FILE IS FOR INTERNAL USAGE, PLEASE IGNORE THIS FILE

import { extractTw } from './transform';

function convertCamelCaseToSnakeCase(methodName) {
const units = ["px", "pc", "vh", "tx"];

const step1 = methodName.replace(/[A-Z]/g, match => `_${match.toLowerCase()}`);

const step2 = step1.replace(/^([:a-z]+)([0-9]+)$/g, (match, p1, p2) => {
if (units.includes(p1)) {
return match;
} else {
return `${p1}_${p2}`;
}
});

const step3 = step2.replace(/_([a-z]+)([0-9]+)/g, (match, p1, p2) => {
if (units.includes(p1)) {
return match;
} else {
return `_${p1}_${p2}`;
}
});

return step3.toLowerCase();
}

function toSnakeCase(methodName) {
if (/^px[0-9]+$/.test(methodName)) {
return `px_${methodName.substring(2)}`;
} else {
return convertCamelCaseToSnakeCase(methodName);
}
}

export function transformSource(source) {
try {
return extractTw(source, toSnakeCase);
} catch (error) {
console.error("Error transforming source:", error);
throw error;
}
}

export const scalaSourceTransform = {
scala: (content) => transformSource(content),
};
188 changes: 101 additions & 87 deletions packages/scalawind/src/transform.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,13 @@
// Utility function for pipe pattern
const pipe =
(...fns) =>
(input) =>
fns.reduce((result, fn) => fn(result), input);

// Patterns and replacements
const PATTERNS = {
TW: /tw(?:\s*\.(?:`[a-zA-Z0-9_/.]+`|[a-zA-Z0-9_¥#/\[\]§"]+)|\s*\((?:[^)(]+|\((?:[^)(]+|\((?:[^)(]+|\((?:[^)(]+|\((?:[^)(]+|\((?:[^)(]+|\([^)(]*\))*\))*\))*\))*\))*\))*\))+/g,
TW_REPLACE: /tw\.|\.|_|`|§|"/g,
TW_REPLACE: /tw\.|\.|`|§|"/g,
MULTILINE: /\n\s+(?=(?:[^"]*"[^"]*")*[^"]*$)/g,
BACKTICK: /`([^`]*)`/g,
ARBITRARY: /_\(("[^"]+")?\)/g,
Expand All @@ -10,49 +16,14 @@ const PATTERNS = {
};

const REPLACEMENTS = {
'tw.': '',
'.': ' ',
'_': '-',
'`': '',
'§': '.',
'"': '',
"tw.": "",
".": " ",
"`": "",
"§": ".",
'"': "",
};

function replaceSpecialCases(source) {
return source.replace(/_2xl/g, '2xl');
}

function handleArbitraryValues(source) {
return source.replace(PATTERNS.ARBITRARY, (match, content) => {
if (content) {
return '_¥' + content.replace(/_/g, '⌇') + '¥';
}
return match;
});
}

function handleOpacityValues(source) {
return source.replace(PATTERNS.OPACITY, (match, content) => {
if (content) {
content = content.replace(/\./g, '§');
return '/€' + content + '€';
}
return match;
});
}

function handleVariantTransform(source) {
return source.replace(PATTERNS.VARIANT_TRANSFORM, (match, selector, content) => {
const safeSelector = selector.replace(/[().]/g, char => ({
'(': '《',
')': '》',
'.': '§'
})[char]);
return `[${safeSelector}](${content})`;
});
}

function flattenClasses(twString) {
const flattenClasses = (twString) => {
const classes = [];
const stack = [];
let currentClass = "";
Expand All @@ -71,7 +42,9 @@ function flattenClasses(twString) {
stack.pop();
} else if (char === " ") {
if (currentClass) {
classes.push(stack.length ? `${stack.join(":")}:${currentClass}` : currentClass);
classes.push(
stack.length ? `${stack.join(":")}:${currentClass}` : currentClass
);
currentClass = "";
}
} else {
Expand All @@ -80,64 +53,105 @@ function flattenClasses(twString) {
}

if (currentClass) {
classes.push(stack.length ? `${stack.join(":")}:${currentClass}` : currentClass);
classes.push(
stack.length ? `${stack.join(":")}:${currentClass}` : currentClass
);
}

return classes.join(" ")
.replace(/¥([^¥]+)¥/g, '[$1]')
.replace(/([^]+)/g, '$1')
.replace(/important:|||raw:|/g, match => ({
'important:': '!',
'《': '(',
'》': ')',
'raw:': '',
'⌇': '_'
})[match])
}

function preprocessSource(source) {
try {
let processed = replaceSpecialCases(source);
processed = handleArbitraryValues(processed);
processed = handleOpacityValues(processed);
return processed;
} catch (error) {
console.error('Error preprocessing source:', error);
throw error;
}
}
return classes;
};

function extractTw(source) {
// Main function to extract and process TW
export const extractTw = (source, customClassTransformer = input => input) => {
try {
const preprocessed = preprocessSource(source);
const matches = preprocessed.match(PATTERNS.TW);

if (!matches) {
return [];
}

return matches.map(match => {
return flattenClasses(handleVariantTransform(match).replace(PATTERNS.MULTILINE, '').replace(PATTERNS.BACKTICK, (_, content) => {
return '`' + content.replace(/\./g, '§') + '`';
}).replace(PATTERNS.TW_REPLACE, match => REPLACEMENTS[match]));
});
return pipe(
(source) => source.replace(/_2xl/g, "2xl"),
(source) =>
source.replace(PATTERNS.ARBITRARY, (match, content) => {
if (content) {
return "_¥" + content.replace(/_/g, "⌇") + "¥";
}
return match;
}),
(source) =>
source.replace(PATTERNS.OPACITY, (match, content) => {
if (content) {
content = content.replace(/\./g, "§");
return "/€" + content + "€";
}
return match;
}),
(source) => source.match(PATTERNS.TW) || [],
(matches) =>
matches.flatMap((match) =>
pipe(
(source) =>
source.replace(
PATTERNS.VARIANT_TRANSFORM,
(_, selector, content) => {
const safeSelector = selector.replace(
/[().]/g,
(char) =>
({
"(": "《",
")": "》",
".": "§",
}[char])
);
return `[${safeSelector}](${content})`;
}
),
(source) => source.replace(PATTERNS.MULTILINE, ""),
(source) =>
source.replace(
PATTERNS.BACKTICK,
(_, content) => "`" + content.replace(/\./g, "§") + "`"
),
(source) =>
source.replace(PATTERNS.TW_REPLACE, (match) => REPLACEMENTS[match]),
flattenClasses
)(match)
),
(classes) => [...new Set(classes)],
(classes) => classes.map(cls => customClassTransformer(cls)),
(classes) => classes.map(cls => cls.replace(/_/g, "-")),
(classes) => classes.join(" "),
(step) => step.replace(/¥([^¥]+)¥/g, "[$1]"),
(step) => step.replace(/([^]+)/g, "$1"),
(step) =>
step.replace(
/important:|||raw:|/g,
(match) =>
({
"important:": "!",
"《": "(",
"》": ")",
"raw:": "",
"⌇": "_",
}[match])
)
)(source);
} catch (error) {
console.error('Error extracting tw:', error);
console.error("Error extracting tw:", error);
throw error;
}
}
};

export function transformSource(source) {
try {
return extractTw(source).join(" ");
return extractTw(source);
} catch (error) {
console.error('Error transforming source:', error);
console.error("Error transforming source:", error);
throw error;
}
}

export const scalaSourceTransform = {
scala: (content) => {
return transformSource(content)
}
}
const transformed = transformSource(content)
return `${content}
${transformed}
`
},
};
Loading

0 comments on commit d00462c

Please sign in to comment.