lix-website/themes/lix/assets/bootstrap/node_modules/@stylelint/postcss-css-in-js/extract.js

489 lines
12 KiB
JavaScript
Raw Normal View History

2024-04-27 03:39:10 +00:00
'use strict';
const getTemplate = require('./get-template');
const loadSyntax = require('postcss-syntax/load-syntax');
const { parse, types, traverse, loadOptions } = require('@babel/core');
const isStyleSheetCreate = expectAdjacentSibling(['create']);
const supports = {
// import styled from '@emotion/styled'
// import { styled } from 'glamor/styled'
// import { styled } from "styletron-react";
// import { styled } from 'linaria/react';
// import { styled } from '@material-ui/styles'
styled: true,
// import { style } from "typestyle";
style: true,
// import { StyleSheet, css } from 'aphrodite';
// import styled, { css } from 'astroturf';
// import { css } from 'lit-css';
// import { css } from 'glamor'
// require('css-light').css({color: 'red'});
// import { css } from 'linaria';
css: true,
// import { StyleSheet, css } from 'aphrodite';
// import { AppRegistry, StyleSheet, Text, View } from 'react-native';
StyleSheet: isStyleSheetCreate,
// import styled, { css } from 'astroturf';
astroturf: true,
// require('csjs')`css`;
csjs: true,
// require('cssobj')({color: 'red'})
cssobj: true,
// require('electron-css')({color: 'red'})
'electron-css': true,
// import styled from "react-emotion";
'react-emotion': true,
// import styled from 'vue-emotion';
// Also see:
// - https://github.com/stylelint/stylelint/issues/4247
// - https://github.com/gucong3000/postcss-jsx/issues/63
// - https://github.com/stylelint/postcss-css-in-js/issues/22
'vue-emotion': true,
// import styled from 'preact-emotion'
'preact-emotion': true,
// https://github.com/streamich/freestyler
freestyler: true,
// https://github.com/paypal/glamorous
glamorous: true,
// https://github.com/irom-io/i-css
// "i-css": (i, nameSpace) => nameSpace[i + 1] === "addStyles" && nameSpace[i + 2] === "wrapper",
// https://github.com/j2css/j2c
j2c: expectAdjacentSibling(['inline', 'sheet']),
// var styles = StyleSheet.create({color: 'red'})
'react-inline': isStyleSheetCreate,
'react-style': isStyleSheetCreate,
// import reactCSS from 'reactcss'
reactcss: true,
// const StyledButton = injectSheet(styles)(Button)
'react-jss': true,
// import styled from 'styled-components';
'styled-components': true,
// import {withStyle} from "styletron-react";
'styletron-react': expectAdjacentSibling(['withStyle']),
styling: true,
// const rule = superstyle({ color: 'blue' })
superstyle: true,
// import { makeStyles } from '@material-ui/styles'
styles: expectAdjacentSibling(['makeStyles']),
};
const plugins = [
'jsx',
'typescript',
'objectRestSpread',
['decorators', { decoratorsBeforeExport: false }],
'classProperties',
'exportExtensions',
'asyncGenerators',
'functionBind',
'functionSent',
'dynamicImport',
'optionalCatchBinding',
];
function expectAdjacentSibling(names) {
return (i, nameSpace) => names.some((name) => nameSpace[i + 1] === name);
}
function loadBabelOpts(opts) {
const filename = opts.from && opts.from.replace(/\?.*$/, '');
opts = {
filename,
parserOpts: {
plugins,
sourceFilename: filename,
sourceType: filename && /\.m[tj]sx?$/.test(filename) ? 'module' : 'unambiguous',
allowImportExportEverywhere: true,
allowAwaitOutsideFunction: true,
allowReturnOutsideFunction: true,
allowSuperOutsideMethod: true,
},
};
let fileOpts;
try {
fileOpts =
filename &&
loadOptions({
filename,
});
} catch (ex) {
//
}
for (const key in fileOpts) {
if (Array.isArray(fileOpts[key]) && !fileOpts[key].length) {
continue;
}
opts[key] = fileOpts[key];
if (Array.isArray(fileOpts[key]) && Array.isArray(opts.parserOpts[key])) {
// combine arrays for plugins
// plugins in fileOpts could be string, array or object
for (const plugin of fileOpts[key]) {
const option =
Array.isArray(plugin) || typeof plugin === 'string'
? plugin
: [plugin.key, plugin.options];
opts.parserOpts[key] = [...opts.parserOpts[key], option];
}
} else {
// because some options need to be passed to parser also
opts.parserOpts[key] = fileOpts[key];
}
}
return opts;
}
function literalParser(source, opts, styles) {
let ast;
try {
ast = parse(source, loadBabelOpts(opts));
} catch (ex) {
// console.error(ex);
return styles || [];
}
const specifiers = new Map();
const variableDeclarator = new Map();
const objLiteral = new Set();
const tplLiteral = new Set();
const tplCallee = new Set();
const jobs = [];
function addObjectJob(path) {
jobs.push(() => {
addObjectValue(path);
});
}
function addObjectValue(path) {
if (path.isIdentifier()) {
const identifier = path.scope.getBindingIdentifier(path.node.name);
if (identifier) {
path = variableDeclarator.get(identifier);
if (path) {
variableDeclarator.delete(identifier);
path.forEach(addObjectExpression);
}
}
} else {
addObjectExpression(path);
}
}
function addObjectExpression(path) {
if (path.isObjectExpression()) {
path.get('properties').forEach((prop) => {
if (prop.isSpreadElement()) {
addObjectValue(prop.get('argument'));
}
});
objLiteral.add(path.node);
return path;
}
// If this is not an object but a function returning an object, we want to parse the
// object that is in the body of the function. We will only parse it if the body only
// consist of an object and nothing else.
if (path.isArrowFunctionExpression()) {
const body = path.get('body');
if (body) {
addObjectExpression(body);
}
}
}
function setSpecifier(id, nameSpace) {
nameSpace.unshift(
...nameSpace
.shift()
.replace(/^\W+/, '')
.split(/[/\\]+/g),
);
if (types.isIdentifier(id)) {
specifiers.set(id.name, nameSpace);
specifiers.set(id, nameSpace);
} else if (types.isObjectPattern(id)) {
id.properties.forEach((property) => {
if (types.isObjectProperty(property)) {
const key = property.key;
nameSpace = nameSpace.concat(key.name || key.value);
id = property.value;
} else {
id = property.argument;
}
setSpecifier(id, nameSpace);
});
} else if (types.isArrayPattern(id)) {
id.elements.forEach((element, i) => {
setSpecifier(element, nameSpace.concat(String(i)));
});
}
}
function getNameSpace(path, nameSpace) {
let node = path.node;
if (path.isIdentifier() || path.isJSXIdentifier()) {
node = path.scope.getBindingIdentifier(node.name) || node;
const specifier = specifiers.get(node) || specifiers.get(node.name);
if (specifier) {
nameSpace.unshift(...specifier);
} else {
nameSpace.unshift(node.name);
}
} else {
['name', 'property', 'object', 'callee'].forEach((prop) => {
node[prop] && getNameSpace(path.get(prop), nameSpace);
});
}
return nameSpace;
}
function isStylePath(path) {
return getNameSpace(path, []).some(function (name, ...args) {
const result =
name &&
((Object.prototype.hasOwnProperty.call(supports, name) && supports[name]) ||
(Object.prototype.hasOwnProperty.call(opts.syntax.config, name) &&
opts.syntax.config[name]));
switch (typeof result) {
case 'function': {
return result.apply(this, args);
}
case 'boolean': {
return result;
}
default: {
return undefined;
}
}
});
}
const visitor = {
ImportDeclaration: (path) => {
const moduleId = path.node.source.value;
path.node.specifiers.forEach((specifier) => {
const nameSpace = [moduleId];
if (specifier.imported) {
nameSpace.push(specifier.imported.name);
}
setSpecifier(specifier.local, nameSpace);
});
},
JSXAttribute: (path) => {
if (/^(?:css|style)$/.test(path.node.name.name)) {
addObjectJob(path.get('value.expression'));
}
},
VariableDeclarator: (path) => {
variableDeclarator.set(path.node.id, path.node.init ? [path.get('init')] : []);
},
AssignmentExpression: (path) => {
if (types.isIdentifier(path.node.left) && types.isObjectExpression(path.node.right)) {
const identifier = path.scope.getBindingIdentifier(path.node.left.name);
const variable = variableDeclarator.get(identifier);
const valuePath = path.get('right');
if (variable) {
variable.push(valuePath);
} else {
variableDeclarator.set(identifier, [valuePath]);
}
}
},
CallExpression: (path) => {
const callee = path.node.callee;
if (
types.isIdentifier(callee, { name: 'require' }) &&
!path.scope.getBindingIdentifier(callee.name)
) {
path.node.arguments.filter(types.isStringLiteral).forEach((arg) => {
const moduleId = arg.value;
const nameSpace = [moduleId];
let currPath = path;
do {
let id = currPath.parent.id;
if (!id) {
id = currPath.parent.left;
if (id) {
id = path.scope.getBindingIdentifier(id.name) || id;
} else {
if (types.isIdentifier(currPath.parent.property)) {
nameSpace.push(currPath.parent.property.name);
}
currPath = currPath.parentPath;
continue;
}
}
setSpecifier(id, nameSpace);
break;
} while (currPath);
});
} else if (!tplCallee.has(callee) && isStylePath(path.get('callee'))) {
path.get('arguments').forEach((arg) => {
addObjectJob(arg.isFunction() ? arg.get('body') : arg);
});
}
},
TaggedTemplateExpression: (path) => {
if (isStylePath(path.get('tag'))) {
tplLiteral.add(path.node.quasi);
if (path.node.tag.callee) {
tplCallee.add(path.node.tag.callee);
}
}
},
};
traverse(ast, visitor);
jobs.forEach((job) => job());
const objLiteralStyles = Array.from(objLiteral).map((endNode) => {
const objectSyntax = require('./object-syntax');
let startNode = endNode;
if (startNode.leadingComments && startNode.leadingComments.length) {
startNode = startNode.leadingComments[0];
}
let startIndex = startNode.start;
const before = source.slice(startNode.start - startNode.loc.start.column, startNode.start);
if (/^\s+$/.test(before)) {
startIndex -= before.length;
}
return {
startIndex,
endIndex: endNode.end,
skipConvert: true,
content: source,
opts: {
node: endNode,
},
syntax: objectSyntax,
lang: 'object-literal',
};
});
const tplLiteralStyles = [];
Array.from(tplLiteral).forEach((node) => {
if (
objLiteralStyles.some((style) => style.startIndex <= node.end && node.start < style.endIndex)
) {
return;
}
const quasis = node.quasis.map((quasiNode) => ({
start: quasiNode.start,
end: quasiNode.end,
}));
const style = {
startIndex: quasis[0].start,
endIndex: quasis[quasis.length - 1].end,
content: getTemplate(node, source),
};
if (node.expressions.length) {
const expressions = node.expressions.map((expressionNode) => ({
start: expressionNode.start,
end: expressionNode.end,
}));
style.syntax = loadSyntax(opts, __dirname);
style.lang = 'template-literal';
style.opts = {
quasis,
expressions,
};
} else {
style.lang = 'css';
}
let parent = null;
let targetStyles = tplLiteralStyles;
while (targetStyles) {
const target = targetStyles.find(
(targetStyle) =>
targetStyle.opts &&
targetStyle.opts.expressions.some(
(expr) => expr.start <= style.startIndex && style.endIndex < expr.end,
),
);
if (target) {
parent = target;
targetStyles = target.opts.templateLiteralStyles;
} else {
break;
}
}
if (parent) {
const templateLiteralStyles =
parent.opts.templateLiteralStyles || (parent.opts.templateLiteralStyles = []);
templateLiteralStyles.push(style);
} else {
tplLiteralStyles.push(style);
}
});
return (styles || []).concat(objLiteralStyles).concat(tplLiteralStyles);
}
module.exports = literalParser;