Skip to content

Commit

Permalink
Fix: also add escaped brackets (closes #133) (#135)
Browse files Browse the repository at this point in the history
  • Loading branch information
JPeer264 authored Jun 25, 2021
1 parent 3964386 commit 992dfe7
Show file tree
Hide file tree
Showing 6 changed files with 107 additions and 57 deletions.
18 changes: 18 additions & 0 deletions __tests__/replace.css.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ const resultsCwd = '__tests__/files/results';
function replaceCssMacro(input, expected = input, options = {}): void {
rcs.fillLibraries(input, options);

rcs.optimize();

expect(rcs.replace.css(input)).toBe(expected);
expect(rcs.replace.css(Buffer.from(input))).toBe(expected);
}
Expand Down Expand Up @@ -627,3 +629,19 @@ it('should replace excluded special characters | rename-css-selectors#77', () =>
'.somediv\\:test-me{}.a{}',
);
});

it('should classes with square brackets | rcs-core#133', () => {
replaceCssMacro(
'.test\\:hello.bottom-\\[99999px\\][class="test"] {bottom: 99999px;}',
'.a.b[class="test"] {bottom: 99999px;}',
);
});

it('should classes with and ignore them | rcs-core#133', () => {
rcs.selectorsLibrary.setExclude('bottom-[99999px]');

replaceCssMacro(
'.test\\:hello.bottom-\\[99999px\\][class="test"] {bottom: 99999px;}',
'.a.bottom-\\[99999px\\][class="test"] {bottom: 99999px;}',
);
});
26 changes: 13 additions & 13 deletions __tests__/selectorsLibrary.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ const setSelectors = (): void => {
rcs.selectorsLibrary.set([
'.test',
'#id',
'.jp-selector',
'.bottom-\\[9px\\]',
]);
};

Expand Down Expand Up @@ -244,7 +244,7 @@ it('getall | should return an array with selectors', () => {
});

expect(array['.test']).toBeTruthy();
expect(array['.jp-selector']).toBeTruthy();
expect(array['.bottom-[9px]']).toBeTruthy();

expect(array['.a']).toBeFalsy();
expect(array['.b']).toBeFalsy();
Expand Down Expand Up @@ -293,7 +293,7 @@ it('getall | should return a regex of non compressed with classes', () => {
addSelectorType: true,
});

expect(regex.source).toBe('(\\#id)|(\\.jp-selector|\\.test)');
expect(regex.source).toBe('(\\#id)|(\\.bottom-\\[9px]|\\.test)');
});

it('getall | should return a regex of non compressed selecotrs', () => {
Expand All @@ -311,7 +311,7 @@ it('getall | should return a regex of compressed selectors', () => {

const regex = rcs.selectorsLibrary.getAllRegex();

expect(regex.source).toBe('((\\s|\\#)(id)[\\s)])|((\\s|\\.)(jp-selector|test)[\\s)])');
expect(regex.source).toBe('((\\s|\\#)(id)[\\s)])|((\\s|\\.)(bottom-\\[9px]|test)[\\s)])');
});

it('getall | should get all setted classes', () => {
Expand All @@ -322,7 +322,7 @@ it('getall | should get all setted classes', () => {
expect(typeof array).toBe('object');
// eslint-disable-next-line @typescript-eslint/no-explicit-any
expect((array as any).test).toBe('a');
expect(array['jp-selector']).toBe('b');
expect(array['bottom-[9px]']).toBe('b');

array = rcs.selectorsLibrary.getIdSelector().getAll();
// eslint-disable-next-line @typescript-eslint/no-explicit-any
Expand All @@ -340,7 +340,7 @@ it('getall | should get all setted compressed classes', () => {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
expect((array as any).a).toBe('test');
// eslint-disable-next-line @typescript-eslint/no-explicit-any
expect((array as any).b).toBe('jp-selector');
expect((array as any).b).toBe('bottom-[9px]');

array = rcs.selectorsLibrary.getIdSelector().getAll({
getRenamedValues: true,
Expand Down Expand Up @@ -522,19 +522,19 @@ it('setAttributeSelector | should set attribute all attribute selectors', () =>
it('setAttributeSelector | attribute selector should fix previous mapping (see #96)', () => {
setSelectors();

let dotTestSelector = rcs.selectorsLibrary.get('.jp-selector');
let dotTestSelector = rcs.selectorsLibrary.get('.bottom-[9px]');
expect(dotTestSelector).toBe('b');

rcs.selectorsLibrary.getClassSelector().setAttributeSelector([
'[class^=jp-]',
'[class^=bottom-]',
]);

dotTestSelector = rcs.selectorsLibrary.get('.jp-selector');
expect(dotTestSelector).toBe('jp-t');
dotTestSelector = rcs.selectorsLibrary.get('.bottom-[9px]');
expect(dotTestSelector).toBe('bottom-t');

rcs.selectorsLibrary.set('.jp-trick');
dotTestSelector = rcs.selectorsLibrary.get('.jp-trick');
expect(dotTestSelector).toBe('jp-n');
rcs.selectorsLibrary.set('.bottom-trick');
dotTestSelector = rcs.selectorsLibrary.get('.bottom-trick');
expect(dotTestSelector).toBe('bottom-n');
});

/* ************************ *
Expand Down
32 changes: 19 additions & 13 deletions lib/attributeLibrary.ts
Original file line number Diff line number Diff line change
Expand Up @@ -173,11 +173,13 @@ export class AttributeLibrary extends BaseLibrary {
repObj: Parameters<BaseLibrary['prepareValue']>[0],
options: AttributeLibraryOptions = {},
): ReturnType<BaseLibrary['prepareValue']> {
if (!this.isValidSelector(repObj.value)) {
return false;
const replacedObject = { ...repObj };

if (!this.isValidSelector(replacedObject.value)) {
return null;
}

const escapeFreeSelector = AttributeLibrary.removePseudoElements(repObj.value);
const escapeFreeSelector = AttributeLibrary.removePseudoElements(replacedObject.value);

// checks if this value was already set
const realSelector = escapeFreeSelector.slice(1, escapeFreeSelector.length);
Expand All @@ -186,18 +188,22 @@ export class AttributeLibrary extends BaseLibrary {
const newName = this.replaceAttributeSelector(escapeFreeSelector);

if (newName) {
// eslint-disable-next-line no-param-reassign
repObj.renamedValue = newName;
replacedObject.renamedValue = newName;
}
}

if (repObj.renamedValue !== undefined && AttributeLibrary.isSelector(repObj.renamedValue)) {
// eslint-disable-next-line no-param-reassign
repObj.renamedValue = repObj.renamedValue.slice(1, repObj.renamedValue.length);
if (
replacedObject.renamedValue !== undefined
&& AttributeLibrary.isSelector(replacedObject.renamedValue)
) {
replacedObject.renamedValue = (
replacedObject.renamedValue.slice(1, replacedObject.renamedValue.length)
);
}
// eslint-disable-next-line no-param-reassign
repObj.value = realSelector;
return true;

replacedObject.value = realSelector;

return replacedObject;
}

// todo jpeer: #104 remove any
Expand Down Expand Up @@ -260,9 +266,9 @@ export class AttributeLibrary extends BaseLibrary {

if (options.regex) {
const regex = options.addSelectorType
? new RegExp(resultArray.map((v) => `\\${v}`).join('|'), 'g')
? new RegExp(resultArray.map((v) => `\\${v.replace(/\[/, '\\[')}`).join('|'), 'g')
// the next MUST be options.regex === true
: new RegExp(`(\\s|\\${this.selectorFirstChar()})(${resultArray.join('|')})[\\s)]`, 'g');
: new RegExp(`(\\s|\\${this.selectorFirstChar()})(${resultArray.map((v) => v.replace(/\[/, '\\[')).join('|')})[\\s)]`, 'g');

const regexResult = resultArray.length === 0 ? undefined : regex;

Expand Down
9 changes: 5 additions & 4 deletions lib/baseLibrary.ts
Original file line number Diff line number Diff line change
Expand Up @@ -93,8 +93,8 @@ export class BaseLibrary {
replacementObject: { value: string; renamedValue: string | undefined },
// eslint-disable-next-line no-unused-vars, @typescript-eslint/no-unused-vars
opts: BaseLibraryOptions,
): boolean {
return true;
): { value: string; renamedValue: string | undefined } | null {
return replacementObject;
}

// Transform the fetched value before returning.
Expand Down Expand Up @@ -178,8 +178,9 @@ export class BaseLibrary {
return;
}

const repObj = { value, renamedValue: thisRenamedValue };
if (!this.prepareValue(repObj, options)) {
const repObj = this.prepareValue({ value, renamedValue: thisRenamedValue }, options);

if (!repObj) {
return;
}

Expand Down
72 changes: 46 additions & 26 deletions lib/replace/css.ts
Original file line number Diff line number Diff line change
Expand Up @@ -89,16 +89,29 @@ const replaceCss = (css: string | Buffer, opts: ReplaceCssOptions = {}): string
}

// eslint-disable-next-line no-param-reassign
node.selectors = node.selectors.map((selector: string) => {
const prefixFreeSelector = selector.replace(/\\/g, '');

return prefixFreeSelector.replace(regex, (match) => (
selectorLib.get(match, {
addSelectorType: true,
source,
})
));
});
node.selectors = node.selectors.map((selector: string) => selector
// split selectors so it is easier to skip non matching selectors
.split('#')
.map((splittedSelector) => {
const splittedSelectorWithDot = `#${splittedSelector}`;
const prefixFreeSelector = splittedSelectorWithDot.replace(/\\/g, '');

// prevent returning prefixFreeSelectors
// when there is not even a match
if (!prefixFreeSelector.match(regex)) {
return splittedSelector;
}

return prefixFreeSelector
.replace(regex, (match) => (
selectorLib.get(match, {
addSelectorType: true,
source,
})
))
.slice(1);
})
.join('#'));
}
});

Expand All @@ -118,22 +131,29 @@ const replaceCss = (css: string | Buffer, opts: ReplaceCssOptions = {}): string
}

// eslint-disable-next-line no-param-reassign
node.selectors = node.selectors.map((selector: string) => {
const prefixFreeSelector = selector.replace(/\\/g, '');

// prevent returning prefixFreeSelectors
// when there is not even a match
if (!prefixFreeSelector.match(regex)) {
return selector;
}

return prefixFreeSelector.replace(regex, (match) => (
selectorLib.get(match, {
addSelectorType: true,
source,
})
));
});
node.selectors = node.selectors.map((selector: string) => selector
// split selectors so it is easier to skip non matching selectors
.split('.')
.map((splittedSelector) => {
const splittedSelectorWithDot = `.${splittedSelector}`;
const prefixFreeSelector = splittedSelectorWithDot.replace(/\\/g, '');

// prevent returning prefixFreeSelectors
// when there is not even a match
if (!prefixFreeSelector.match(regex)) {
return splittedSelector;
}

return prefixFreeSelector
.replace(regex, (match) => (
selectorLib.get(match, {
addSelectorType: true,
source,
})
))
.slice(1);
})
.join('.'));
}
});

Expand Down
7 changes: 6 additions & 1 deletion lib/replace/regex.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
/* eslint-disable max-len */
export default {
selectors: /(#|\.)[^\s.{)[>+,~"]+/g, // matches all selectors beginning with . or # - e.g. .matching#alsomatch .matchmetoo
// - matches all selectors beginning with . or # - e.g. .matching#alsomatch .matchmetoo
// | - matches backslash and something after
// | | - matches everything after AGAIN, basically a copy from the beginning
// ( v )( v )( v )
selectors: /(#|\.)[^\s.{)>+,~")[\\]+(\\.)?[^\s.{)>+,~")[]+/g,
strings: /"\s*[\S\s]*?\s*"|'\s*[\S\s]*?\s*'/g, // matches strings such as: 'hello' or "hello"
classAttributeSelectors: /\[\s*(class)\s*([*^$|~]?)=\s*("[^\]]*?"|'[^\]]*?'|[^\]]*)[^\]]*?\]/g, // matches attribute selectors of html just with class in it with `$=`, `^=` or `*=`, e.g.: [class*="selector"]. 3 group matches, first `class`, second regex operator, third the string
idAttributeSelectors: /\[\s*(id|for)\s*([*^$|~]?)=\s*("[^\]]*?"|'[^\]]*?'|[^\]]*)[^\]]*?\]/g, // matches attribute selectors of html just with 'for' or 'id' in it with `$=`, `^=` or `*=`, e.g.: [id*="selector"]. 3 group matches, first `for` or `id`, second regex operator, third the string
Expand Down

0 comments on commit 992dfe7

Please sign in to comment.