Skip to content

Commit

Permalink
Merge pull request #46 from ony3000/ensure-consistency
Browse files Browse the repository at this point in the history
Makes output consistent for attribute type class names
  • Loading branch information
ony3000 authored Mar 17, 2024
2 parents 551a0ce + 113ffe8 commit 25f6876
Show file tree
Hide file tree
Showing 13 changed files with 913 additions and 60 deletions.
5 changes: 5 additions & 0 deletions src/packages/core-parts/finder.ts
Original file line number Diff line number Diff line change
Expand Up @@ -168,6 +168,9 @@ export function findTargetClassNameNodes(
line: z.unknown(),
}),
}),
name: z.object({
name: z.string(),
}),
}),
) &&
parentNode.type === 'JSXOpeningElement' &&
Expand Down Expand Up @@ -206,6 +209,8 @@ export function findTargetClassNameNodes(
parentNodeStartLineNumber === currentNodeStartLineNumber
? ClassNameType.ASL
: ClassNameType.AOL;
// eslint-disable-next-line no-param-reassign
classNameNode.elementName = parentNode.name.name;
}
}
});
Expand Down
169 changes: 119 additions & 50 deletions src/packages/core-parts/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,7 @@ function sha1(input: string): string {
return createHash('sha1').update(input).digest('hex');
}

function freezeIndent(input: string): string {
function freezeNonClassName(input: string): string {
const charCodeForUpperCaseAlpha = 913;
const greekPlaceholder = [...Array(16)].map((_, index) =>
String.fromCharCode(charCodeForUpperCaseAlpha + index),
Expand All @@ -122,7 +122,7 @@ function freezeIndent(input: string): string {
return `${prefix}${rest}`;
}

function freezeString(input: string): string {
function freezeClassName(input: string): string {
const charCodeForLowerCaseAlpha = 945;
const greekPlaceholder = [...Array(16)].map((_, index) =>
String.fromCharCode(charCodeForLowerCaseAlpha + index),
Expand All @@ -139,6 +139,9 @@ function freezeString(input: string): string {
return `${prefix}${rest}`;
}

const frozenAttributeName = freezeNonClassName('attribute');
const doubleFrozenAttributeName = freezeNonClassName(frozenAttributeName);

function replaceClassName({
formattedText,
indentUnit,
Expand All @@ -162,7 +165,7 @@ function replaceClassName({
const icedFormattedText = targetClassNameNodes.reduce(
(
formattedPrevText,
{ type, range: [rangeStart, rangeEnd], startLineIndex },
{ type, range: [rangeStart, rangeEnd], startLineIndex, elementName },
classNameNodeIndex,
) => {
if (targetClassNameTypes && !targetClassNameTypes.includes(type)) {
Expand Down Expand Up @@ -258,22 +261,46 @@ function replaceClassName({
options.parser,
);

const rawIndent = indentUnit.repeat(multiLineIndentLevel);
const frozenIndent = freezeIndent(rawIndent);
const substitute = `${quoteStart}${classNameWithOriginalSpaces}${quoteEnd}`
.split(EOL)
.map((raw) => {
const frozen = freezeString(raw);

freezer.push({
type: 'string',
from: frozen,
to: raw,
});
const elementOpener = '<';
const spaceAfterElementName = ' ';
const conditionForSameLineAttribute =
isEndingPositionAbsolute &&
type === ClassNameType.ASL &&
isMultiLineClassName &&
formattedClassName.length +
options.tabWidth -
(elementName ? `${elementOpener}${elementName}${spaceAfterElementName}`.length : 0) <=
options.printWidth;
const conditionForOwnLineAttribute =
isEndingPositionAbsolute &&
type === ClassNameType.AOL &&
!isMultiLineClassName &&
classNameWithOriginalSpaces !== classNameBase &&
formattedClassName.length -
options.tabWidth +
(elementName ? `${elementOpener}${elementName}${spaceAfterElementName}`.length : 0) >
options.printWidth;

return frozen;
})
.join(`${EOL}${frozenIndent}`);
const rawIndent = indentUnit.repeat(multiLineIndentLevel);
const frozenIndent = freezeNonClassName(rawIndent);
const substitute =
`${quoteStart}${classNameWithOriginalSpaces}${quoteEnd}`
.split(EOL)
.map((raw) => {
const frozen = freezeClassName(raw);

freezer.push({
type: 'string',
from: frozen,
to: raw,
});

return frozen;
})
.join(`${EOL}${frozenIndent}`) +
(conditionForSameLineAttribute || conditionForOwnLineAttribute
? `${EOL}${frozenAttributeName}${EOL}`
: '');

if (isStartingPositionRelative && isMultiLineClassName) {
freezer.push({
Expand Down Expand Up @@ -308,13 +335,16 @@ function replaceClassName({
formattedText,
);

return freezer.reduceRight(
(prevText, { type, from, to }) =>
type === 'indent'
? prevText.replace(new RegExp(`^\\s*${from}`, 'gm'), to)
: prevText.replace(from, to),
icedFormattedText,
);
return freezer
.reduceRight(
(prevText, { type, from, to }) =>
type === 'indent'
? prevText.replace(new RegExp(`^\\s*${from}`, 'gm'), to)
: prevText.replace(from, to),
icedFormattedText,
)
.replace(new RegExp(`^\\s*${doubleFrozenAttributeName}${EOL}`, 'gm'), '')
.replace(new RegExp(`${frozenAttributeName}`, 'gm'), doubleFrozenAttributeName);
}

export function parseLineByLineAndReplace({
Expand Down Expand Up @@ -356,7 +386,7 @@ export function parseLineByLineAndReplace({

const lineNodes = parseLineByLine(formattedText, indentUnit);

return replaceClassName({
const classNameWrappedText = replaceClassName({
formattedText,
indentUnit,
targetClassNameNodes,
Expand All @@ -365,6 +395,12 @@ export function parseLineByLineAndReplace({
format,
targetClassNameTypes,
});
// Note: This is a temporary use condition. I plan to improve it in the next minor update.
const conditionForSecondFormat = targetClassNameTypes !== undefined;

return conditionForSecondFormat
? classNameWrappedText.replace(new RegExp(`^\\s*${doubleFrozenAttributeName}${EOL}`, 'gm'), '')
: classNameWrappedText;
}

async function replaceClassNameAsync({
Expand All @@ -390,7 +426,7 @@ async function replaceClassNameAsync({
const icedFormattedText = await targetClassNameNodes.reduce(
async (
formattedPrevTextPromise,
{ type, range: [rangeStart, rangeEnd], startLineIndex },
{ type, range: [rangeStart, rangeEnd], startLineIndex, elementName },
classNameNodeIndex,
) => {
if (targetClassNameTypes && !targetClassNameTypes.includes(type)) {
Expand Down Expand Up @@ -492,22 +528,46 @@ async function replaceClassNameAsync({
options.parser,
);

const rawIndent = indentUnit.repeat(multiLineIndentLevel);
const frozenIndent = freezeIndent(rawIndent);
const substitute = `${quoteStart}${classNameWithOriginalSpaces}${quoteEnd}`
.split(EOL)
.map((raw) => {
const frozen = freezeString(raw);
const elementOpener = '<';
const spaceAfterElementName = ' ';
const conditionForSameLineAttribute =
isEndingPositionAbsolute &&
type === ClassNameType.ASL &&
isMultiLineClassName &&
formattedClassName.length +
options.tabWidth -
(elementName ? `${elementOpener}${elementName}${spaceAfterElementName}`.length : 0) <=
options.printWidth;
const conditionForOwnLineAttribute =
isEndingPositionAbsolute &&
type === ClassNameType.AOL &&
!isMultiLineClassName &&
classNameWithOriginalSpaces !== classNameBase &&
formattedClassName.length -
options.tabWidth +
(elementName ? `${elementOpener}${elementName}${spaceAfterElementName}`.length : 0) >
options.printWidth;

freezer.push({
type: 'string',
from: frozen,
to: raw,
});

return frozen;
})
.join(`${EOL}${frozenIndent}`);
const rawIndent = indentUnit.repeat(multiLineIndentLevel);
const frozenIndent = freezeNonClassName(rawIndent);
const substitute =
`${quoteStart}${classNameWithOriginalSpaces}${quoteEnd}`
.split(EOL)
.map((raw) => {
const frozen = freezeClassName(raw);

freezer.push({
type: 'string',
from: frozen,
to: raw,
});

return frozen;
})
.join(`${EOL}${frozenIndent}`) +
(conditionForSameLineAttribute || conditionForOwnLineAttribute
? `${EOL}${frozenAttributeName}${EOL}`
: '');

if (isStartingPositionRelative && isMultiLineClassName) {
freezer.push({
Expand Down Expand Up @@ -542,13 +602,16 @@ async function replaceClassNameAsync({
Promise.resolve(formattedText),
);

return freezer.reduceRight(
(prevText, { type, from, to }) =>
type === 'indent'
? prevText.replace(new RegExp(`^\\s*${from}`, 'gm'), to)
: prevText.replace(from, to),
icedFormattedText,
);
return freezer
.reduceRight(
(prevText, { type, from, to }) =>
type === 'indent'
? prevText.replace(new RegExp(`^\\s*${from}`, 'gm'), to)
: prevText.replace(from, to),
icedFormattedText,
)
.replace(new RegExp(`^\\s*${doubleFrozenAttributeName}${EOL}`, 'gm'), '')
.replace(new RegExp(`${frozenAttributeName}`, 'gm'), doubleFrozenAttributeName);
}

export async function parseLineByLineAndReplaceAsync({
Expand Down Expand Up @@ -590,7 +653,7 @@ export async function parseLineByLineAndReplaceAsync({

const lineNodes = parseLineByLine(formattedText, indentUnit);

return replaceClassNameAsync({
const classNameWrappedText = await replaceClassNameAsync({
formattedText,
indentUnit,
targetClassNameNodes,
Expand All @@ -599,4 +662,10 @@ export async function parseLineByLineAndReplaceAsync({
format,
targetClassNameTypes,
});
// Note: This is a temporary use condition. I plan to improve it in the next minor update.
const conditionForSecondFormat = targetClassNameTypes !== undefined;

return conditionForSecondFormat
? classNameWrappedText.replace(new RegExp(`^\\s*${doubleFrozenAttributeName}${EOL}`, 'gm'), '')
: classNameWrappedText;
}
1 change: 1 addition & 0 deletions src/packages/core-parts/shared.ts
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,7 @@ export type ClassNameNode = {
type: ClassNameType;
range: NodeRange;
startLineIndex: number;
elementName?: string;
};

export type NarrowedParserOptions = {
Expand Down
2 changes: 1 addition & 1 deletion src/packages/v2-plugin/parsers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@ function transformParser(
targetClassNameTypes:
parserName === 'vue' || parserName === 'astro'
? [ClassNameType.ASL, ClassNameType.AOL]
: [ClassNameType.CTL, ClassNameType.TLSL],
: [ClassNameType.ASL, ClassNameType.AOL, ClassNameType.CTL, ClassNameType.TLSL],
});

return {
Expand Down
2 changes: 1 addition & 1 deletion src/packages/v3-plugin/parsers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ function transformParser(
targetClassNameTypes:
parserName === 'vue' || parserName === 'astro'
? [ClassNameType.ASL, ClassNameType.AOL]
: [ClassNameType.CTL, ClassNameType.TLSL],
: [ClassNameType.ASL, ClassNameType.AOL, ClassNameType.CTL, ClassNameType.TLSL],
});

return {
Expand Down
4 changes: 2 additions & 2 deletions tests/v2-test/babel/attribute-without-expression.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -185,8 +185,8 @@ export function Callout({ children }) {
output: `export function Callout({ children }) {
return (
<div
className="rounded-xl border border-zinc-400/30 bg-gray-100/50 px-4
py-4 dark:border-neutral-500/30 dark:bg-neutral-900/50"
className="rounded-xl border border-zinc-400/30 bg-gray-100/50 px-4 py-4
dark:border-neutral-500/30 dark:bg-neutral-900/50"
>
{children}
</div>
Expand Down
Loading

0 comments on commit 25f6876

Please sign in to comment.