UNPKG

8.45 kBJavaScriptView Raw
1"use strict";
2Object.defineProperty(exports, "__esModule", { value: true });
3exports.createTransformer = void 0;
4const path = require("path");
5const ts = require("typescript");
6const ts_is_kind_1 = require("./ts-is-kind");
7const hash_1 = require("./hash");
8const minify_1 = require("./minify");
9/** Detects that a node represents a styled function
10 * Recognizes the following patterns:
11 *
12 * styled.tag
13 * Component.extend
14 * styled(Component)
15 * styled('tag')
16 * styledFunction.attrs(attributes)
17 */
18function isStyledFunction(node, identifiers) {
19 if ((0, ts_is_kind_1.isPropertyAccessExpression)(node)) {
20 if (isStyledObject(node.expression, identifiers)) {
21 return true;
22 }
23 if (isStyledExtendIdentifier(node.name.text, identifiers) && isValidComponent(node.expression)) {
24 return true;
25 }
26 return false;
27 }
28 if ((0, ts_is_kind_1.isCallExpression)(node) && node.arguments.length === 1) {
29 if (isStyledObject(node.expression, identifiers)) {
30 return true;
31 }
32 if (isStyledAttrs(node.expression, identifiers)) {
33 return true;
34 }
35 }
36 return false;
37}
38function isStyledObjectIdentifier(name, { styled: styledIdentifiers = ['styled'] }) {
39 return styledIdentifiers.indexOf(name) >= 0;
40}
41function isStyledObject(node, identifiers) {
42 return node && (0, ts_is_kind_1.isIdentifier)(node) && isStyledObjectIdentifier(node.text, identifiers);
43}
44function isValidComponent(node) {
45 return node && (0, ts_is_kind_1.isIdentifier)(node) && isValidComponentName(node.text);
46}
47function isLetter(ch) {
48 return ch.toLowerCase() !== ch.toUpperCase();
49}
50function isValidTagName(name) {
51 return isLetter(name[0]) && name[0] === name[0].toLowerCase();
52}
53function isValidComponentName(name) {
54 return isLetter(name[0]) && name[0] === name[0].toUpperCase();
55}
56function isStyledAttrsIdentifier(name, { attrs: attrsIdentifiers = ['attrs'] }) {
57 return attrsIdentifiers.indexOf(name) >= 0;
58}
59function isStyledAttrs(node, identifiers) {
60 return (node &&
61 (0, ts_is_kind_1.isPropertyAccessExpression)(node) &&
62 isStyledAttrsIdentifier(node.name.text, identifiers) &&
63 isStyledFunction(node.expression, identifiers));
64}
65function isStyledKeyframesIdentifier(name, { keyframes = ['keyframes'] }) {
66 return keyframes.indexOf(name) >= 0;
67}
68function isStyledCssIdentifier(name, { css = ['css'] }) {
69 return css.indexOf(name) >= 0;
70}
71function isStyledCreateGlobalStyleIdentifier(name, { createGlobalStyle = ['createGlobalStyle'] }) {
72 return createGlobalStyle.indexOf(name) >= 0;
73}
74function isStyledExtendIdentifier(name, { extend = [] }) {
75 return extend.indexOf(name) >= 0;
76}
77function isMinifyableStyledFunction(node, identifiers) {
78 return (isStyledFunction(node, identifiers) ||
79 ((0, ts_is_kind_1.isIdentifier)(node) &&
80 (isStyledKeyframesIdentifier(node.text, identifiers) ||
81 isStyledCssIdentifier(node.text, identifiers) ||
82 isStyledCreateGlobalStyleIdentifier(node.text, identifiers))));
83}
84function defaultGetDisplayName(filename, bindingName) {
85 return bindingName;
86}
87function createTransformer({ getDisplayName = defaultGetDisplayName, identifiers = {}, ssr = true, displayName = true, minify = false, componentIdPrefix = '' } = {}) {
88 /**
89 * Infers display name of a styled component.
90 * Recognizes the following patterns:
91 *
92 * (const|var|let) ComponentName = styled...
93 * export default styled...
94 */
95 function getDisplayNameFromNode(node, sourceFile) {
96 if ((0, ts_is_kind_1.isVariableDeclaration)(node) && (0, ts_is_kind_1.isIdentifier)(node.name)) {
97 return (componentIdPrefix ? componentIdPrefix + '-' : '') + getDisplayName(sourceFile.fileName, node.name.text);
98 }
99 if ((0, ts_is_kind_1.isExportAssignment)(node)) {
100 return getDisplayName(sourceFile.fileName, undefined);
101 }
102 return undefined;
103 }
104 function getIdFromNode(node, sourceRoot, position, sourceFile) {
105 if (((0, ts_is_kind_1.isVariableDeclaration)(node) && (0, ts_is_kind_1.isIdentifier)(node.name)) || (0, ts_is_kind_1.isExportAssignment)(node)) {
106 const fileName = sourceFile.fileName;
107 const filePath = sourceRoot
108 ? path.relative(sourceRoot, fileName).replace(path.sep, path.posix.sep)
109 : fileName;
110 return (componentIdPrefix || 'sc') + '-' + (0, hash_1.hash)(`${getDisplayNameFromNode(node, sourceFile)}${filePath}${position}`);
111 }
112 return undefined;
113 }
114 const transformer = (context) => {
115 const { sourceRoot } = context.getCompilerOptions();
116 return (sourceFile) => {
117 let lastComponentPosition = 0;
118 const withConfig = (node, properties) => properties.length > 0
119 ? context.factory.createCallExpression(context.factory.createPropertyAccessExpression(node, 'withConfig'), undefined, [context.factory.createObjectLiteralExpression(properties)])
120 : node;
121 const createDisplayNameConfig = (displayNameValue) => displayNameValue
122 ? [
123 context.factory.createPropertyAssignment('displayName', context.factory.createStringLiteral(displayNameValue)),
124 ]
125 : [];
126 const createIdConfig = (componentId) => componentId
127 ? [
128 context.factory.createPropertyAssignment('componentId', context.factory.createStringLiteral(componentId)),
129 ]
130 : [];
131 const transformStyledFunction = (binding, node) => withConfig(node, [
132 ...(displayName ? createDisplayNameConfig(getDisplayNameFromNode(binding, sourceFile)) : []),
133 ...(ssr
134 ? createIdConfig(getIdFromNode(binding, sourceRoot, ++lastComponentPosition, sourceFile))
135 : []),
136 ]);
137 const transformTemplateLiteral = (templateLiteral) => minify ? (0, minify_1.minifyTemplate)(templateLiteral, context.factory) : templateLiteral;
138 const transformTaggedTemplateExpression = (node) => isMinifyableStyledFunction(node.tag, identifiers)
139 ? context.factory.updateTaggedTemplateExpression(node, node.tag, node.typeArguments, transformTemplateLiteral(node.template))
140 : node;
141 const transformBindingExpression = (binding, node) => {
142 if ((0, ts_is_kind_1.isTaggedTemplateExpression)(node) && isStyledFunction(node.tag, identifiers)) {
143 return context.factory.updateTaggedTemplateExpression(node, transformStyledFunction(binding, node.tag), node.typeArguments, transformTemplateLiteral(node.template));
144 }
145 if ((0, ts_is_kind_1.isCallExpression)(node) && isStyledFunction(node.expression, identifiers)) {
146 return context.factory.updateCallExpression(node, transformStyledFunction(binding, node.expression), node.typeArguments, node.arguments);
147 }
148 };
149 const updateNode = (node, data, updateFn) => (data ? updateFn(node, data) : undefined);
150 const updateVariableDeclarationInitializer = (node, initializer) => context.factory.updateVariableDeclaration(node, node.name, node.exclamationToken, node.type, initializer);
151 const updateExportAssignmentExpression = (node, expression) => context.factory.updateExportAssignment(node, node.modifiers, expression);
152 const transformNode = (node) => (0, ts_is_kind_1.isVariableDeclaration)(node) && node.initializer
153 ? updateNode(node, transformBindingExpression(node, node.initializer), updateVariableDeclarationInitializer)
154 : (0, ts_is_kind_1.isExportAssignment)(node)
155 ? updateNode(node, transformBindingExpression(node, node.expression), updateExportAssignmentExpression)
156 : minify && (0, ts_is_kind_1.isTaggedTemplateExpression)(node)
157 ? transformTaggedTemplateExpression(node)
158 : undefined;
159 const visitNode = (node) => transformNode(node) || ts.visitEachChild(node, visitNode, context);
160 return ts.visitNode(sourceFile, visitNode);
161 };
162 };
163 return transformer;
164}
165exports.createTransformer = createTransformer;
166exports.default = createTransformer;