@nozbe/zacs
Advanced tools
Comparing version 1.1.0-8 to 1.1.0-9
{ | ||
"name": "@nozbe/zacs", | ||
"version": "1.1.0-8", | ||
"version": "1.1.0-9", | ||
"description": "Zero Abstraction Cost Styling (for React DOM and React Native)", | ||
@@ -5,0 +5,0 @@ "main": "src/index.js", |
@@ -733,6 +733,7 @@ /* eslint-disable no-use-before-define */ | ||
function isPlainObjectProperty(t, node) { | ||
function isPlainObjectProperty(t, node, allowStringLiterals) { | ||
const isAllowedKey = t.isIdentifier(node.key) || (allowStringLiterals && t.isStringLiteral(node.key)) | ||
return ( | ||
t.isObjectProperty(node) && | ||
t.isIdentifier(node.key) && | ||
isAllowedKey && | ||
!node.shorthand && | ||
@@ -751,3 +752,3 @@ !node.computed && | ||
throw styleset.buildCodeFrameError( | ||
"ZACS StyleSheets must be simple object literals, like so: `{ backgroundColor: 'red', height: 100 }`. Other syntaxes, like `foo ? {xxx} : {yyy}` or `...styles` are not allowed.", | ||
"ZACS StyleSheets must be simple object literals, like so: `text: { backgroundColor: 'red', height: 100 }`. Other syntaxes, like `foo ? {xxx} : {yyy}` or `...styles` are not allowed.", | ||
) | ||
@@ -758,12 +759,22 @@ } | ||
properties.forEach(property => { | ||
if (!isPlainObjectProperty(t, property.node)) { | ||
if (!isPlainObjectProperty(t, property.node, true)) { | ||
throw property.buildCodeFrameError( | ||
'ZACS StyleSheets style attributes must be simple strings, like so: `{ backgroundColor: \'red\', height: 100 }`. Other syntaxes, like `[propName]:`, `"backgroundColor": `, `...styles` are not allowed.', | ||
'ZACS StyleSheets style attributes must be simple strings, like so: `{ backgroundColor: \'red\', height: 100 }`. Other syntaxes, like `[propName]:`, `...styles` are not allowed.', | ||
) | ||
} | ||
const key = property.node.key.name | ||
const valuePath = property.get('value') | ||
const value = valuePath.node | ||
if (t.isStringLiteral(property.node.key)) { | ||
if (!t.isObjectExpression(value)) { | ||
throw styleset.buildCodeFrameError( | ||
"ZACS StyleSheets style attributes must be simple strings, like so: `{ backgroundColor: \'red\', height: 100 }`. Quoted keys are only allowed for web inner styles, e.g. `{ \"& > span\": { opacity: 0.5 } }`", | ||
) | ||
} | ||
validateStyleset(t, valuePath) | ||
return | ||
} | ||
const key = property.node.key.name | ||
if (key === 'css') { | ||
@@ -796,3 +807,2 @@ if (!(t.isStringLiteral(value) || isPlainTemplateLiteral(t, value))) { | ||
if (!isPlainObjectProperty(t, styleset.node)) { | ||
// TODO: We can probably allow `"name":`, no problem. | ||
throw styleset.buildCodeFrameError( | ||
@@ -802,6 +812,20 @@ 'ZACS StyleSheet stylesets must be defined as `name: {}`. Other syntaxes, like `[name]:`, `"name": `, `...styles` are not allowed', | ||
} | ||
validateStyleset(t, styleset.get('value')) | ||
const stylesetName = styleset.node.key.name | ||
if (stylesetName === 'css') { | ||
const cssValue = styleset.get('value') | ||
if (!(t.isStringLiteral(cssValue.node) || isPlainTemplateLiteral(t, cssValue.node))) { | ||
throw cssValue.buildCodeFrameError( | ||
"ZACS StyleSheet's magic css: styleset expects a simple literal string as its value. Object expressions, references, expressions in a template literal are not allowed.", | ||
) | ||
} | ||
} else { | ||
validateStyleset(t, styleset.get('value')) | ||
} | ||
}) | ||
} | ||
const strval = stringLiteralOrPlainTemplateLiteral => | ||
stringLiteralOrPlainTemplateLiteral.value || | ||
stringLiteralOrPlainTemplateLiteral.quasis[0].value.cooked | ||
const capitalRegex = /([A-Z])/g | ||
@@ -820,4 +844,9 @@ const cssCaseReplacer = (match, letter) => `-${letter.toLowerCase()}` | ||
function encodeCSSStyle(property) { | ||
function encodeCSSStyle(property, spaces = ' ') { | ||
const { value } = property | ||
if (property.key.value) { | ||
return `${spaces}${property.key.value} {\n${encodeCSSStyles(value, `${spaces} `)}\n${spaces}}` | ||
} | ||
const key = property.key.name | ||
@@ -827,3 +856,3 @@ if (key === 'native' || key === 'ios' || key === 'android') { | ||
} else if (key === 'css') { | ||
return ' ' + (value.value || value.quasis[0].value.cooked) | ||
return `${spaces}${strval(value)}` | ||
} else if (key === 'web') { | ||
@@ -833,8 +862,8 @@ return encodeCSSStyles(value) | ||
return ` ${encodeCSSProperty(key)}: ${encodeCSSValue(key, value)};` | ||
return `${spaces}${encodeCSSProperty(key)}: ${encodeCSSValue(key, value)};` | ||
} | ||
function encodeCSSStyles(styleset) { | ||
function encodeCSSStyles(styleset, spaces) { | ||
return styleset.properties | ||
.map(encodeCSSStyle) | ||
.map(style => encodeCSSStyle(style, spaces)) | ||
.filter(rule => rule !== null) | ||
@@ -846,2 +875,7 @@ .join('\n') | ||
const { name } = styleset.key | ||
if (name === 'css') { | ||
return strval(styleset.value) | ||
} | ||
return `.${name} {\n${encodeCSSStyles(styleset.value)}\n}` | ||
@@ -856,25 +890,30 @@ } | ||
function resolveRNStylesheet(platform, target, stylesheet) { | ||
stylesheet.properties.forEach(styleset => { | ||
const resolvedProperties = [] | ||
const pushFromInner = objectExpr => { | ||
objectExpr.properties.forEach(innerProperty => { | ||
resolvedProperties.push(innerProperty) | ||
}) | ||
} | ||
styleset.value.properties.forEach(property => { | ||
const key = property.key.name | ||
if (key === 'web' || key === 'css') { | ||
// do nothing | ||
} else if (key === 'native') { | ||
pushFromInner(property.value) | ||
} else if (key === 'ios' || key === 'android') { | ||
if (target === key) { | ||
stylesheet.properties = stylesheet.properties | ||
.filter(styleset => styleset.key.name !== 'css') | ||
.map(styleset => { | ||
const resolvedProperties = [] | ||
const pushFromInner = objectExpr => { | ||
objectExpr.properties.forEach(innerProperty => { | ||
resolvedProperties.push(innerProperty) | ||
}) | ||
} | ||
styleset.value.properties.forEach(property => { | ||
const key = property.key.name | ||
if (key === 'web' || key === 'css') { | ||
// do nothing | ||
} else if (property.key.value) { | ||
// css inner selector - do nothing | ||
} else if (key === 'native') { | ||
pushFromInner(property.value) | ||
} else if (key === 'ios' || key === 'android') { | ||
if (target === key) { | ||
pushFromInner(property.value) | ||
} | ||
} else { | ||
resolvedProperties.push(property) | ||
} | ||
} else { | ||
resolvedProperties.push(property) | ||
} | ||
}) | ||
styleset.value.properties = resolvedProperties | ||
return styleset | ||
}) | ||
styleset.value.properties = resolvedProperties | ||
}) | ||
@@ -898,10 +937,13 @@ return stylesheet | ||
const formattedCss = t.stringLiteral(preparedCss) | ||
// TODO: TODO | ||
formattedCss.extra = { rawValue: preparedCss, raw: `"${preparedCss.split('\n').join(' \\n\\\n')}"` } | ||
// NOTE: We can't use a template literal, because most people use a Babel transform for it, and it | ||
// doesn't spit out clean output. So we spit out an ugly string literal, but keep it multi-line | ||
// so that it's easier to view source code in case webpack fails to extract it. | ||
// TODO: Escaped characters are probably broken here, please investigate | ||
formattedCss.extra = { | ||
rawValue: preparedCss, | ||
raw: `"${preparedCss.split('\n').join(' \\n\\\n')}"`, | ||
} | ||
const magicCssExpression = t.expressionStatement( | ||
t.callExpression( | ||
t.identifier('ZACS_MAGIC_CSS_STYLESHEET_MARKER_START'), | ||
[formattedCss], | ||
), | ||
t.callExpression(t.identifier('ZACS_MAGIC_CSS_STYLESHEET_MARKER_START'), [formattedCss]), | ||
) | ||
@@ -908,0 +950,0 @@ t.addComment( |
@@ -33,7 +33,6 @@ // Inspiration: | ||
const startMarker = 'ZACS_MAGIC_CSS_STYLESHEET_MARKER_START("' | ||
const endMarker = '' | ||
const cssDisclaimer = '/* Generated CSS file (from ZACS Stylesheets) - do not edit! */\n' | ||
exports.default = function loader(source, inputSourceMap) { | ||
// TODO: Options | ||
// const options = getOptions(this) | ||
const { cacheDirectory = '.zacs-cache', extension = '.zacs.css' } = loaderUtils.getOptions(this) || {} | ||
@@ -50,12 +49,4 @@ const stylesheetMarkerPos = source.indexOf(startMarker) | ||
// const stylesheetEndPos = source.indexOf(endMarker) | ||
// if (stylesheetEndPos < stylesheetMarkerPos) { | ||
// this.emitError(`Broken ZACS stylesheet. Found the beginning of it, but the end is missing or malformed.`) | ||
// } | ||
// // NOTE: Avoiding regex for perf (probably unnecessarily :)) | ||
// const extractedStyles = source.substring(stylesheetMarkerPos, stylesheetEndPos + endMarker.length) | ||
// const cssText = source.substring(stylesheetMarkerPos + startMarker.length, stylesheetEndPos) | ||
// .replace(/ \\n\\/g, '') | ||
// NOTE: We can't use simple indexOf + substring, because some Babel plugins malform the magic markers, insterting whitespace | ||
// between end of string argument and the closing paren | ||
const match = source.match(/ZACS_MAGIC_CSS_STYLESHEET_MARKER_START\("(.*)ZACS_MAGIC_CSS_STYLESHEET_MARKER_END"\s*\)/s) | ||
@@ -67,8 +58,7 @@ if (!match) { | ||
const extractedStyles = match[0] | ||
const cssText = match[1].replace(/ \\n\\/g, '') | ||
const cssText = cssDisclaimer + match[1].replace(/ \\n\\/g, '') | ||
// TODO: Linaria checks for workspace/learna root -- see if it's needed here | ||
const root = /* workspaceRoot || lernaRoot || */ process.cwd() | ||
const cacheDirectory = '.zacs-cache' // TODO: Make configurable? | ||
const baseOutputFileName = this.resourcePath.replace(/\.[^.]+$/, '.zacs.css') | ||
const baseOutputFileName = this.resourcePath.replace(/\.[^.]+$/, extension) | ||
const outputFilename = normalize( | ||
@@ -75,0 +65,0 @@ path.join( |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
82146
1390