hypnagaga/src/docs/utils/css-to-js/index.js
2025-02-07 12:48:42 +00:00

388 lines
10 KiB
JavaScript

/*
* Reuters Graphics browser port of:
* Copyright 2020 American Express Travel Related Services Company, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
* in compliance with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License
* is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
* or implied. See the License for the specific language governing permissions and limitations under
* the License.
*/
import css from 'css';
function _defineProperty(obj, key, value) {
if (key in obj) {
Object.defineProperty(obj, key, {
value,
enumerable: true,
configurable: true,
writable: true,
});
} else {
obj[key] = value;
}
return obj;
}
function ownKeys(object, enumerableOnly) {
const keys = Object.keys(object);
if (Object.getOwnPropertySymbols) {
let symbols = Object.getOwnPropertySymbols(object);
if (enumerableOnly) {
symbols = symbols.filter(function (sym) {
return Object.getOwnPropertyDescriptor(object, sym).enumerable;
});
}
keys.push.apply(keys, symbols);
}
return keys;
}
function _objectSpread2(target) {
for (let i = 1; i < arguments.length; i++) {
var source = arguments[i] != null ? arguments[i] : {};
if (i % 2) {
ownKeys(Object(source), true).forEach(function (key) {
_defineProperty(target, key, source[key]);
});
} else if (Object.getOwnPropertyDescriptors) {
Object.defineProperties(target, Object.getOwnPropertyDescriptors(source));
} else {
ownKeys(Object(source)).forEach(function (key) {
Object.defineProperty(
target,
key,
Object.getOwnPropertyDescriptor(source, key)
);
});
}
}
return target;
}
function _slicedToArray(arr, i) {
return (
_arrayWithHoles(arr) || _iterableToArrayLimit(arr, i) || _nonIterableRest()
);
}
function _arrayWithHoles(arr) {
if (Array.isArray(arr)) return arr;
}
function _iterableToArrayLimit(arr, i) {
if (
!(
Symbol.iterator in Object(arr) ||
Object.prototype.toString.call(arr) === '[object Arguments]'
)
) {
return;
}
const _arr = [];
let _n = true;
let _d = false;
let _e;
try {
for (
var _i = arr[Symbol.iterator](), _s;
!(_n = (_s = _i.next()).done);
_n = true
) {
_arr.push(_s.value);
if (i && _arr.length === i) break;
}
} catch (err) {
_d = true;
_e = err;
} finally {
try {
if (!_n && _i.return != null) _i.return();
} finally {
// eslint-disable-next-line
if (_d) throw _e;
}
}
return _arr;
}
function _nonIterableRest() {
throw new TypeError('Invalid attempt to destructure non-iterable instance');
}
const addProperty = function addProperty(obj, key, value) {
const retObj = obj;
if (retObj[key]) {
retObj[key] = _objectSpread2({}, retObj[key], {}, value);
} else {
retObj[key] = value;
}
return retObj;
};
const camelize = function camelize(str) {
return str.replace(/-([a-z])/g, function (g) {
return g[1].toUpperCase();
});
};
const capitalize = function capitalize(str) {
return str.charAt(0).toUpperCase() + str.slice(1);
};
const sanitize = function sanitize(name) {
return name
.replace(/\*/g, 'all-children')
.replace(/#/g, '$')
.replace(/\s\s+/g, ' ')
.replace(/(\d)\\\/(\d)/g, '$1~$2') // Added for escaped slashes like ".w-1/2"
.replace(/(\d)\\\.(\d)/g, '$1|$2') // Added for escaped dots like ".mb-0\.5"
.replace(/[^a-zA-Z0-9$|~]/g, '_')
.replace(/^_+/g, '')
.replace(/_+$/g, '')
.replace('|', '.') // Replace placeholder
.replace('~', '/'); // Replace placeholder
};
const fontface = function fontface(rule, result) {
let name = '';
let obj = {};
const fontObj = {};
rule.declarations.forEach(function (declaration) {
const cssProperty = camelize(declaration.property);
fontObj[cssProperty] = declaration.value;
name = capitalize(camelize(fontObj.fontFamily).replace(/"/g, ''));
obj = {
'@font-face': fontObj,
};
});
let dupeFlag = false;
Object.keys(result).forEach(function (key) {
if (key.split('_')[0] === name) {
if (JSON.stringify(result[key]) === JSON.stringify(obj)) {
dupeFlag = true;
}
}
});
if (!dupeFlag) {
const numVar = Object.entries(result).filter(function (resObj) {
return resObj[0].split('_')[0] === name;
}).length;
if (numVar > 0) {
name = ''.concat(name, '_').concat(numVar + 1);
}
name = sanitize(name);
return [name, obj];
}
return false;
};
const keyframes = function keyframes(rule) {
const keyFrameObj = {};
rule.keyframes.forEach(function (keyframe) {
keyframe.declarations.forEach(function (decl) {
keyFrameObj[keyframe.values[0]] = _objectSpread2(
{},
keyFrameObj[keyframe.values[0]],
_defineProperty({}, decl.property, decl.value)
);
});
});
let name = camelize('keyframes-'.concat(rule.name));
const obj = {};
obj['@keyframes '.concat(rule.name)] = keyFrameObj;
name = sanitize(name);
return [name, obj];
};
const standard = function standard(rule, result) {
const obj = {};
let retObj = {};
rule.declarations.forEach(function (declaration) {
const cssProperty = camelize(declaration.property);
obj[cssProperty] = declaration.value;
});
rule.selectors.forEach(function (selector) {
let name; // Check if selector contains a pseudo selector
const pseudoSelectorIndex = selector.indexOf(':');
if (pseudoSelectorIndex !== -1) {
// Find end of pseudo selector
let endPseudoSelectorIndex = selector.indexOf(' ', pseudoSelectorIndex);
if (endPseudoSelectorIndex === -1)
endPseudoSelectorIndex = selector.length; // Split selector
const primarySelector = selector.slice(0, pseudoSelectorIndex);
const pseudoSelector = selector.slice(
pseudoSelectorIndex,
endPseudoSelectorIndex
);
const secondarySelector = selector.slice(
endPseudoSelectorIndex,
selector.length
);
const pseudoObj = {};
pseudoObj['&'.concat(pseudoSelector).concat(secondarySelector)] = obj;
name = sanitize(primarySelector.trim());
retObj = addProperty(result, name, pseudoObj);
} else {
name = sanitize(selector.trim());
retObj = addProperty(result, name, obj);
}
});
return retObj;
};
const convertRules = function convertRules(rules) {
const res =
arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
let result = res;
rules.forEach(function (rule) {
if (rule.type === 'media') {
// Convert @media rules
const name = '@media '.concat(rule.media);
result[name] = result[name] || {};
const media = result[name];
convertRules(rule.rules, media);
} else if (rule.type === 'font-face') {
// Convert @font-face rules
const fontProp = fontface(rule, result);
if (fontProp) result = addProperty(result, fontProp[0], fontProp[1]);
} else if (rule.type === 'keyframes') {
// Convert @keyframes rules
const keyProp = keyframes(rule);
result = addProperty(result, keyProp[0], keyProp[1]);
} else if (rule.type === 'rule') {
// Convert standard CSS rules
const standardProp = standard(rule, result);
Object.entries(standardProp).forEach(function (_ref) {
const _ref2 = _slicedToArray(_ref, 2);
const key = _ref2[0];
const value = _ref2[1];
result = addProperty(result, key, value);
});
}
});
return result;
};
const convertToJS = function convertToJS(input) {
// Parse CSS string into rules array
try {
const parsedCss = css.parse(input);
const rules = parsedCss.stylesheet.rules;
return convertRules(rules);
} catch (err) {
throw new Error('Invalid CSS input: '.concat(err));
}
};
const reverseMediaQueries = function reverseMediaQueries(inputData) {
const exportObject = {};
const moveMediaInsideClass = function moveMediaInsideClass(object) {
const media =
arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false;
Object.entries(object).forEach(function (_ref) {
const _ref2 = _slicedToArray(_ref, 2);
const key = _ref2[0];
const value = _ref2[1];
if (key.includes('@media')) {
moveMediaInsideClass(object[key], key);
} else if (media) {
const tempObj = {};
tempObj[media] = value;
if (exportObject[key]) {
exportObject[key] = _objectSpread2(
{},
exportObject[key],
{},
tempObj
);
} else {
exportObject[key] = tempObj;
}
} else if (exportObject[key]) {
exportObject[key] = _objectSpread2({}, exportObject[key], {}, value);
} else {
exportObject[key] = value;
}
});
};
moveMediaInsideClass(inputData);
return exportObject;
};
const convertStringToJson = function convertStringToJson(input, mediaReverse) {
let contents = convertToJS(input);
if (mediaReverse) {
contents = reverseMediaQueries(contents);
}
return {
contents,
};
};
const convert = function convert(input) {
const config =
arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
const outputType = config.outputType;
const _outputPath = config.outputPath;
let mediaReverse = config.mediaReverse;
let convertedCss;
if (outputType === 'splitFile' || outputType === 'shakeFile') {
mediaReverse = true;
} // If input is a String of CSS
convertedCss = convertStringToJson(input, mediaReverse);
if (!outputType) {
if (Array.isArray(convertedCss)) {
return convertedCss.map(function (obj) {
return obj.contents;
});
} else {
return convertedCss.contents;
}
} else {
const writeRecur = function writeRecur(input) {
if (Array.isArray(input)) {
input.forEach(function (obj) {
writeRecur(obj);
});
}
};
writeRecur(convertedCss);
}
};
export { convert };