You can not select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
		
			
		
			
				
					167 lines
				
				6.6 KiB
			
		
		
			
		
	
	
					167 lines
				
				6.6 KiB
			| 
											3 years ago
										 | "use strict"; | ||
|  | 
 | ||
|  | Object.defineProperty(exports, "__esModule", { | ||
|  |   value: true | ||
|  | }); | ||
|  | exports.default = void 0; | ||
|  | 
 | ||
|  | var _path = _interopRequireDefault(require("path")); | ||
|  | 
 | ||
|  | var _fs = _interopRequireDefault(require("fs")); | ||
|  | 
 | ||
|  | var _options = require("../utils/options"); | ||
|  | 
 | ||
|  | var _getName = _interopRequireDefault(require("../utils/getName")); | ||
|  | 
 | ||
|  | var _prefixDigit = _interopRequireDefault(require("../utils/prefixDigit")); | ||
|  | 
 | ||
|  | var _hash = _interopRequireDefault(require("../utils/hash")); | ||
|  | 
 | ||
|  | var _detectors = require("../utils/detectors"); | ||
|  | 
 | ||
|  | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } | ||
|  | 
 | ||
|  | const addConfig = t => (path, displayName, componentId) => { | ||
|  |   if (!displayName && !componentId) { | ||
|  |     return; | ||
|  |   } | ||
|  | 
 | ||
|  |   const withConfigProps = []; | ||
|  | 
 | ||
|  |   if (displayName) { | ||
|  |     withConfigProps.push(t.objectProperty(t.identifier('displayName'), t.stringLiteral(displayName))); | ||
|  |   } | ||
|  | 
 | ||
|  |   if (componentId) { | ||
|  |     withConfigProps.push(t.objectProperty(t.identifier('componentId'), t.stringLiteral(componentId))); | ||
|  |   } | ||
|  | 
 | ||
|  |   const existingConfig = getExistingConfig(t)(path); | ||
|  | 
 | ||
|  |   if (existingConfig && existingConfig.arguments.length && Array.isArray(existingConfig.arguments[0].properties) && !existingConfig.arguments[0].properties.some(prop => ['displayName', 'componentId'].includes(prop.key.name))) { | ||
|  |     existingConfig.arguments[0].properties.push(...withConfigProps); | ||
|  |     return; | ||
|  |   } | ||
|  | 
 | ||
|  |   if (path.node.callee && t.isMemberExpression(path.node.callee.callee) && path.node.callee.callee.property && path.node.callee.callee.property.name && path.node.callee.callee.property.name == 'withConfig' && path.node.callee.arguments.length && Array.isArray(path.node.callee.arguments[0].properties) && !path.node.callee.arguments[0].properties.some(prop => ['displayName', 'componentId'].includes(prop.key.name))) { | ||
|  |     path.node.callee.arguments[0].properties.push(...withConfigProps); | ||
|  |     return; | ||
|  |   } | ||
|  | 
 | ||
|  |   if (path.node.tag) { | ||
|  |     // Replace x`...` with x.withConfig({ })`...`
 | ||
|  |     path.node.tag = t.callExpression(t.memberExpression(path.node.tag, t.identifier('withConfig')), [t.objectExpression(withConfigProps)]); | ||
|  |   } else { | ||
|  |     path.replaceWith(t.callExpression(t.callExpression(t.memberExpression(path.node.callee, t.identifier('withConfig')), [t.objectExpression(withConfigProps)]), path.node.arguments)); | ||
|  |   } | ||
|  | }; | ||
|  | 
 | ||
|  | const getExistingConfig = t => path => { | ||
|  |   if (path.node.callee && t.isMemberExpression(path.node.callee.callee) && path.node.callee.callee.property && path.node.callee.callee.property.name && path.node.callee.callee.property.name == 'withConfig') { | ||
|  |     return path.node.callee; | ||
|  |   } | ||
|  | 
 | ||
|  |   if (path.node.callee && t.isMemberExpression(path.node.callee.callee) && path.node.callee.callee.object && path.node.callee.callee.object.callee && path.node.callee.callee.object.callee.property && path.node.callee.callee.object.callee.property.name === 'withConfig') { | ||
|  |     return path.node.callee.callee.object; | ||
|  |   } | ||
|  | }; | ||
|  | 
 | ||
|  | const getBlockName = file => { | ||
|  |   const name = _path.default.basename(file.opts.filename, _path.default.extname(file.opts.filename)); | ||
|  | 
 | ||
|  |   return name !== 'index' ? name : _path.default.basename(_path.default.dirname(file.opts.filename)); | ||
|  | }; | ||
|  | 
 | ||
|  | const getDisplayName = t => (path, state) => { | ||
|  |   const { | ||
|  |     file | ||
|  |   } = state; | ||
|  |   const componentName = (0, _getName.default)(t)(path); | ||
|  | 
 | ||
|  |   if (file) { | ||
|  |     const blockName = getBlockName(file); | ||
|  | 
 | ||
|  |     if (blockName === componentName) { | ||
|  |       return componentName; | ||
|  |     } | ||
|  | 
 | ||
|  |     return componentName ? `${(0, _prefixDigit.default)(blockName)}__${componentName}` : (0, _prefixDigit.default)(blockName); | ||
|  |   } else { | ||
|  |     return componentName; | ||
|  |   } | ||
|  | }; | ||
|  | 
 | ||
|  | const findModuleRoot = filename => { | ||
|  |   if (!filename) { | ||
|  |     return null; | ||
|  |   } | ||
|  | 
 | ||
|  |   let dir = _path.default.dirname(filename); | ||
|  | 
 | ||
|  |   if (_fs.default.existsSync(_path.default.join(dir, 'package.json'))) { | ||
|  |     return dir; | ||
|  |   } else if (dir !== filename) { | ||
|  |     return findModuleRoot(dir); | ||
|  |   } else { | ||
|  |     return null; | ||
|  |   } | ||
|  | }; | ||
|  | 
 | ||
|  | const FILE_HASH = 'styled-components-file-hash'; | ||
|  | const COMPONENT_POSITION = 'styled-components-component-position'; | ||
|  | const separatorRegExp = new RegExp(`\\${_path.default.sep}`, 'g'); | ||
|  | 
 | ||
|  | const getFileHash = state => { | ||
|  |   const { | ||
|  |     file | ||
|  |   } = state; // hash calculation is costly due to fs operations, so we'll cache it per file.
 | ||
|  | 
 | ||
|  |   if (file.get(FILE_HASH)) { | ||
|  |     return file.get(FILE_HASH); | ||
|  |   } | ||
|  | 
 | ||
|  |   const filename = file.opts.filename; // find module root directory
 | ||
|  | 
 | ||
|  |   const moduleRoot = findModuleRoot(filename); | ||
|  | 
 | ||
|  |   const filePath = moduleRoot && _path.default.relative(moduleRoot, filename).replace(separatorRegExp, '/'); | ||
|  | 
 | ||
|  |   const moduleName = moduleRoot && JSON.parse(_fs.default.readFileSync(_path.default.join(moduleRoot, 'package.json'))).name; | ||
|  |   const code = file.code; | ||
|  |   const stuffToHash = [moduleName]; | ||
|  | 
 | ||
|  |   if (filePath) { | ||
|  |     stuffToHash.push(filePath); | ||
|  |   } else { | ||
|  |     stuffToHash.push(code); | ||
|  |   } | ||
|  | 
 | ||
|  |   const fileHash = (0, _hash.default)(stuffToHash.join('')); | ||
|  |   file.set(FILE_HASH, fileHash); | ||
|  |   return fileHash; | ||
|  | }; | ||
|  | 
 | ||
|  | const getNextId = state => { | ||
|  |   const id = state.file.get(COMPONENT_POSITION) || 0; | ||
|  |   state.file.set(COMPONENT_POSITION, id + 1); | ||
|  |   return id; | ||
|  | }; | ||
|  | 
 | ||
|  | const getComponentId = state => { | ||
|  |   // Prefix the identifier with a character because CSS classes cannot start with a number
 | ||
|  |   return `${(0, _options.useNamespace)(state)}sc-${getFileHash(state)}-${getNextId(state)}`; | ||
|  | }; | ||
|  | 
 | ||
|  | var _default = t => (path, state) => { | ||
|  |   if (path.node.tag ? (0, _detectors.isStyled)(t)(path.node.tag, state) : | ||
|  |   /* styled()`` */ | ||
|  |   (0, _detectors.isStyled)(t)(path.node.callee, state) && path.node.callee.property && path.node.callee.property.name !== 'withConfig' || // styled(x)({})
 | ||
|  |   (0, _detectors.isStyled)(t)(path.node.callee, state) && !t.isMemberExpression(path.node.callee.callee) || // styled(x).attrs()({})
 | ||
|  |   (0, _detectors.isStyled)(t)(path.node.callee, state) && t.isMemberExpression(path.node.callee.callee) && path.node.callee.callee.property && path.node.callee.callee.property.name && path.node.callee.callee.property.name !== 'withConfig' || // styled(x).withConfig({})
 | ||
|  |   (0, _detectors.isStyled)(t)(path.node.callee, state) && t.isMemberExpression(path.node.callee.callee) && path.node.callee.callee.property && path.node.callee.callee.property.name && path.node.callee.callee.property.name === 'withConfig' && path.node.callee.arguments.length && Array.isArray(path.node.callee.arguments[0].properties) && !path.node.callee.arguments[0].properties.some(prop => ['displayName', 'componentId'].includes(prop.key.name))) { | ||
|  |     const displayName = (0, _options.useDisplayName)(state) && getDisplayName(t)(path, (0, _options.useFileName)(state) && state); | ||
|  |     addConfig(t)(path, displayName && displayName.replace(/[^_a-zA-Z0-9-]/g, ''), (0, _options.useSSR)(state) && getComponentId(state)); | ||
|  |   } | ||
|  | }; | ||
|  | 
 | ||
|  | exports.default = _default; |