Skip to content

Commit e71c967

Browse files
committed
[breaking] v5 support
haven't managed to get the preact ones to work yet... doesn't seem like preact 10 is ready enough yet and for preact-compat the createContext implementation is actually in a separate package so not sure how to fake it being part of preact-compat
1 parent a652a08 commit e71c967

File tree

10 files changed

+289
-480
lines changed

10 files changed

+289
-480
lines changed

package.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -48,14 +48,14 @@
4848
"react-is": "^16.8.6",
4949
"react-native": "^0.59.9",
5050
"react-test-renderer": "^16.8.0",
51-
"styled-components": "^3",
51+
"styled-components": "^5.0.0-alpha.1",
5252
"typescript": "^3.0.3"
5353
},
5454
"dependencies": {
5555
"css": "^2.2.4"
5656
},
5757
"peerDependencies": {
58-
"styled-components": ">= 2"
58+
"styled-components": ">= 5.0.0-alpha.0"
5959
},
6060
"husky": {
6161
"hooks": {

src/styleSheetSerializer.js

Lines changed: 61 additions & 85 deletions
Original file line numberDiff line numberDiff line change
@@ -1,154 +1,130 @@
1-
const css = require('css')
2-
const { getCSS, getHashes } = require('./utils')
1+
const css = require('css');
2+
const { getCSS, getHashes } = require('./utils');
33

4-
const KEY = '__jest-styled-components__'
4+
const KEY = '__jest-styled-components__';
55

66
const getNodes = (node, nodes = []) => {
77
if (typeof node === 'object') {
8-
nodes.push(node)
8+
nodes.push(node);
99
}
1010

1111
if (node.children) {
12-
Array.from(node.children).forEach(child => getNodes(child, nodes))
12+
Array.from(node.children).forEach(child => getNodes(child, nodes));
1313
}
1414

15-
return nodes
16-
}
15+
return nodes;
16+
};
1717

18-
const markNodes = nodes => nodes.forEach(node => (node[KEY] = true))
18+
const markNodes = nodes => nodes.forEach(node => (node[KEY] = true));
1919

20-
const getClassNamesFromDOM = node => Array.from(node.classList)
20+
const getClassNamesFromDOM = node => Array.from(node.classList);
2121
const getClassNamesFromProps = node => {
22-
const classNameProp = node.props && (node.props.class || node.props.className)
22+
const classNameProp = node.props && (node.props.class || node.props.className);
2323

2424
if (classNameProp) {
25-
return classNameProp.trim().split(/\s+/)
25+
return classNameProp.trim().split(/\s+/);
2626
}
2727

28-
return []
29-
}
28+
return [];
29+
};
3030

3131
const getClassNames = nodes =>
3232
nodes.reduce((classNames, node) => {
33-
let newClassNames = null
33+
let newClassNames = null;
3434

3535
if (global.Element && node instanceof global.Element) {
36-
newClassNames = getClassNamesFromDOM(node)
36+
newClassNames = getClassNamesFromDOM(node);
3737
} else {
38-
newClassNames = getClassNamesFromProps(node)
38+
newClassNames = getClassNamesFromProps(node);
3939
}
4040

41-
newClassNames.forEach(className => classNames.add(className))
41+
newClassNames.forEach(className => classNames.add(className));
4242

43-
return classNames
44-
}, new Set())
43+
return classNames;
44+
}, new Set());
4545

46-
const filterClassNames = (classNames, hashes) =>
47-
classNames.filter(className => hashes.includes(className))
46+
const filterClassNames = (classNames, hashes) => classNames.filter(className => hashes.includes(className));
4847

4948
const includesClassNames = (classNames, selectors) =>
50-
classNames.some(className =>
51-
selectors.some(selector => selector.includes(className))
52-
)
49+
classNames.some(className => selectors.some(selector => selector.includes(className)));
5350

5451
const filterRules = classNames => rule =>
55-
rule.type === 'rule' &&
56-
includesClassNames(classNames, rule.selectors) &&
57-
rule.declarations.length
52+
rule.type === 'rule' && includesClassNames(classNames, rule.selectors) && rule.declarations.length;
5853

5954
const getAtRules = (ast, filter) =>
6055
ast.stylesheet.rules
6156
.filter(rule => rule.type === 'media' || rule.type === 'supports')
6257
.reduce((acc, atRule) => {
63-
atRule.rules = atRule.rules.filter(filter)
58+
atRule.rules = atRule.rules.filter(filter);
6459

65-
if (atRule.rules.length) {
66-
return acc.concat(atRule)
67-
}
68-
69-
return acc
70-
}, [])
60+
return acc.concat(atRule);
61+
}, []);
7162

7263
const getStyle = classNames => {
73-
const ast = getCSS()
74-
const filter = filterRules(classNames)
75-
const rules = ast.stylesheet.rules.filter(filter)
76-
const atRules = getAtRules(ast, filter)
64+
const ast = getCSS();
65+
const filter = filterRules(classNames);
66+
const rules = ast.stylesheet.rules.filter(filter);
67+
const atRules = getAtRules(ast, filter);
7768

78-
ast.stylesheet.rules = rules.concat(atRules)
69+
ast.stylesheet.rules = rules.concat(atRules);
7970

80-
return css.stringify(ast)
81-
}
71+
return css.stringify(ast);
72+
};
8273

8374
const getClassNamesFromSelectorsByHashes = (classNames, hashes) => {
84-
const ast = getCSS()
85-
const filter = filterRules(classNames)
86-
const rules = ast.stylesheet.rules.filter(filter)
75+
const ast = getCSS();
76+
const filter = filterRules(classNames);
77+
const rules = ast.stylesheet.rules.filter(filter);
8778

88-
const selectors = rules.map(rule => rule.selectors)
89-
const classNamesIncludingFromSelectors = new Set(classNames)
79+
const selectors = rules.map(rule => rule.selectors);
80+
const classNamesIncludingFromSelectors = new Set(classNames);
9081
const addHashFromSelectorListToClassNames = hash =>
91-
selectors.forEach(
92-
selectorList =>
93-
selectorList[0].includes(hash) &&
94-
classNamesIncludingFromSelectors.add(hash)
95-
)
82+
selectors.forEach(selectorList => selectorList[0].includes(hash) && classNamesIncludingFromSelectors.add(hash));
9683

97-
hashes.forEach(addHashFromSelectorListToClassNames)
84+
hashes.forEach(addHashFromSelectorListToClassNames);
9885

99-
return [...classNamesIncludingFromSelectors]
100-
}
86+
return [...classNamesIncludingFromSelectors];
87+
};
10188

10289
const replaceClassNames = (result, classNames, style) =>
10390
classNames
10491
.filter(className => style.includes(className))
105-
.reduce(
106-
(acc, className, index) =>
107-
acc.replace(new RegExp(className, 'g'), `c${index++}`),
108-
result
109-
)
92+
.reduce((acc, className, index) => acc.replace(new RegExp(className, 'g'), `c${index++}`), result);
11093

11194
const replaceHashes = (result, hashes) =>
11295
hashes.reduce(
113-
(acc, className) =>
114-
acc.replace(
115-
new RegExp(`((class|className)="[^"]*?)${className}\\s?([^"]*")`, 'g'),
116-
'$1$3'
117-
),
96+
(acc, className) => acc.replace(new RegExp(`((class|className)="[^"]*?)${className}\\s?([^"]*")`, 'g'), '$1$3'),
11897
result
119-
)
98+
);
12099

121100
const styleSheetSerializer = {
122101
test(val) {
123102
return (
124103
val &&
125104
!val[KEY] &&
126-
(val.$$typeof === Symbol.for('react.test.json') ||
127-
(global.Element && val instanceof global.Element))
128-
)
105+
(val.$$typeof === Symbol.for('react.test.json') || (global.Element && val instanceof global.Element))
106+
);
129107
},
130108

131109
print(val, print) {
132-
const nodes = getNodes(val)
133-
markNodes(nodes)
110+
const nodes = getNodes(val);
111+
markNodes(nodes);
112+
113+
const hashes = getHashes();
134114

135-
const hashes = getHashes()
136-
let classNames = [...getClassNames(nodes)]
137-
classNames = filterClassNames(classNames, hashes)
115+
let classNames = [...getClassNames(nodes)];
116+
classNames = filterClassNames(classNames, hashes);
138117

139-
const style = getStyle(classNames)
140-
const classNamesToReplace = getClassNamesFromSelectorsByHashes(
141-
classNames,
142-
hashes
143-
)
144-
const code = print(val)
118+
const style = getStyle(classNames);
119+
const classNamesToReplace = getClassNamesFromSelectorsByHashes(classNames, hashes);
120+
const code = print(val);
145121

146-
let result = `${style}${style ? '\n\n' : ''}${code}`
147-
result = replaceClassNames(result, classNamesToReplace, style)
148-
result = replaceHashes(result, hashes)
122+
let result = `${style}${style ? '\n\n' : ''}${code}`;
123+
result = replaceClassNames(result, classNamesToReplace, style);
124+
result = replaceHashes(result, hashes);
149125

150-
return result
126+
return result;
151127
},
152-
}
128+
};
153129

154-
module.exports = styleSheetSerializer
130+
module.exports = styleSheetSerializer;

src/utils.js

Lines changed: 36 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -1,88 +1,71 @@
1-
const css = require('css')
2-
const { ServerStyleSheet, isStyledComponent } = require('styled-components')
3-
4-
let StyleSheet
5-
6-
if (isStyledComponent) {
7-
const secretInternals = require('styled-components')
8-
.__DO_NOT_USE_OR_YOU_WILL_BE_HAUNTED_BY_SPOOKY_GHOSTS
9-
10-
if (
11-
secretInternals === undefined ||
12-
secretInternals.StyleSheet === undefined
13-
) {
14-
throw new Error(
15-
'Could neither find styled-components secret internals nor styled-components/lib/models/StyleSheet.js'
16-
)
17-
} else {
18-
StyleSheet = secretInternals.StyleSheet
19-
}
20-
} else {
21-
StyleSheet = require('styled-components/lib/models/StyleSheet').default // eslint-disable-line
1+
const css = require('css');
2+
const { ServerStyleSheet, __PRIVATE__ } = require('styled-components');
3+
4+
if (!__PRIVATE__) {
5+
throw new Error('Could neither find styled-components secret internals');
226
}
237

24-
const isServer = () => typeof document === 'undefined'
8+
const { masterSheet } = __PRIVATE__;
259

26-
const resetStyleSheet = () => StyleSheet.reset(isServer())
10+
const isServer = () => typeof document === 'undefined';
2711

28-
const getHTML = () =>
29-
isServer()
30-
? new ServerStyleSheet().getStyleTags()
31-
: StyleSheet.instance.toHTML()
12+
const resetStyleSheet = () => {
13+
masterSheet.names = new Map();
14+
masterSheet.clearTag();
15+
};
16+
17+
const getHTML = () => (isServer() ? new ServerStyleSheet().getStyleTags() : masterSheet.toString());
3218

3319
const extract = regex => {
34-
let style = ''
35-
let matches
20+
let style = '';
21+
let matches;
3622

3723
while ((matches = regex.exec(getHTML())) !== null) {
38-
style += `${matches[1]} `
24+
style += `${matches[1]} `;
3925
}
4026

41-
return style.trim()
42-
}
27+
return style.trim();
28+
};
4329

44-
const getStyle = () => extract(/<style[^>]*>([^<]*)</g)
30+
const getStyle = () => extract(/^(?!data-styled\.g\d+.*?\n)(.*)?\n/gm);
31+
const getCSS = () => css.parse(getStyle());
4532

46-
const getCSS = () => css.parse(getStyle())
33+
const getHashes = () => {
34+
const hashes = new Set();
4735

48-
const getClassNames = () =>
49-
extract(/data-styled(?:-components)?="([^"]*)"/g).split(/\s/)
36+
for (const [masterHash, childHashSet] of masterSheet.names) {
37+
hashes.add(masterHash);
5038

51-
const getComponentIDs = () =>
52-
extract(/sc-component-id: ([^\\*\\/]*) \*\//g).split(/\s/)
39+
for (const childHash of childHashSet) hashes.add(childHash);
40+
}
5341

54-
const getHashes = () =>
55-
getClassNames()
56-
.concat(getComponentIDs())
57-
.filter(Boolean)
42+
return Array.from(hashes);
43+
};
5844

5945
const buildReturnMessage = (utils, pass, property, received, expected) => () =>
6046
`${utils.printReceived(
61-
!received && !pass
62-
? `Property '${property}' not found in style rules`
63-
: `Value mismatch for property '${property}'`
47+
!received && !pass ? `Property '${property}' not found in style rules` : `Value mismatch for property '${property}'`
6448
)}\n\n` +
6549
'Expected\n' +
6650
` ${utils.printExpected(`${property}: ${expected}`)}\n` +
6751
'Received:\n' +
68-
` ${utils.printReceived(`${property}: ${received}`)}`
52+
` ${utils.printReceived(`${property}: ${received}`)}`;
6953

7054
const matcherTest = (received, expected) => {
7155
try {
72-
const matcher =
73-
expected instanceof RegExp ? expect.stringMatching(expected) : expected
56+
const matcher = expected instanceof RegExp ? expect.stringMatching(expected) : expected;
7457

75-
expect(received).toEqual(matcher)
76-
return true
58+
expect(received).toEqual(matcher);
59+
return true;
7760
} catch (error) {
78-
return false
61+
return false;
7962
}
80-
}
63+
};
8164

8265
module.exports = {
8366
resetStyleSheet,
8467
getCSS,
8568
getHashes,
8669
buildReturnMessage,
8770
matcherTest,
88-
}
71+
};

0 commit comments

Comments
 (0)