Software zum Installieren eines Smart-Mirror Frameworks , zum Nutzen von hochschulrelevanten Informationen, auf einem Raspberry-Pi.
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.

object-parser.js 7.3KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357
  1. 'use strict';
  2. const camelCase = require('./camel-case');
  3. const getTemplate = require('./get-template');
  4. const Literal = require('./literal');
  5. const ObjectLiteral = require('./object');
  6. const postcss = require('postcss');
  7. const unCamelCase = require('./un-camel-case');
  8. function forEach(arr, callback) {
  9. arr && arr.forEach(callback);
  10. }
  11. const replaceProp = (fn) => (value) =>
  12. value.replace(/(\(\s*)(.*?)(\s*:)/g, (s, prefix, prop, suffix) => prefix + fn(prop) + suffix);
  13. const camelCaseProp = replaceProp(camelCase);
  14. const unCamelCaseProp = replaceProp(unCamelCase);
  15. function defineRaws(node, prop, prefix, suffix, props) {
  16. if (!props) {
  17. props = {};
  18. }
  19. const descriptor = {
  20. enumerable: true,
  21. get: () => node[prop],
  22. set: (value) => {
  23. node[prop] = value;
  24. },
  25. };
  26. if (!props.raw) {
  27. props.raw = descriptor;
  28. } else if (props.raw === 'camel') {
  29. props.raw = {
  30. enumerable: true,
  31. get: () => camelCase(node[prop]),
  32. set: (value) => {
  33. node[prop] = unCamelCase(value);
  34. },
  35. };
  36. }
  37. props.value = descriptor;
  38. node.raws[prop] = Object.defineProperties(
  39. {
  40. prefix,
  41. suffix,
  42. },
  43. props,
  44. );
  45. }
  46. class objectParser {
  47. constructor(input) {
  48. this.input = input;
  49. }
  50. parse(node) {
  51. const root = postcss.root({
  52. source: {
  53. input: this.input,
  54. start: node.loc.start,
  55. },
  56. });
  57. root.raws.node = node;
  58. const obj = new ObjectLiteral({
  59. raws: {
  60. node,
  61. },
  62. });
  63. root.push(obj);
  64. this.process(node, obj);
  65. this.sort(root);
  66. this.raws(root);
  67. const startNode = root.first.raws.node;
  68. const endNode = root.last.raws.node;
  69. const start = {
  70. line: startNode.loc.start.line,
  71. };
  72. let before = root.source.input.css.slice(
  73. startNode.start - startNode.loc.start.column,
  74. startNode.start,
  75. );
  76. if (/^\s+$/.test(before)) {
  77. start.column = 1;
  78. } else {
  79. before = '';
  80. start.column = startNode.loc.start.column;
  81. }
  82. root.first.raws.before = before;
  83. root.source.input.css = before + root.source.input.css.slice(startNode.start, endNode.end);
  84. root.source.start = start;
  85. this.root = root;
  86. }
  87. process(node, parent) {
  88. ['leadingComments', 'innerComments', 'trailingComments'].forEach((prop) => {
  89. forEach(node[prop], (child) => {
  90. this.source(child, this.comment(child, parent));
  91. });
  92. });
  93. const child = (this[node.type] || this.literal).apply(this, [node, parent]);
  94. this.source(node, child);
  95. return child;
  96. }
  97. source(node, parent) {
  98. parent.source = {
  99. input: this.input,
  100. start: node.loc.start,
  101. end: node.loc.end,
  102. };
  103. return parent;
  104. }
  105. raws(parent, node) {
  106. const source = this.input.css;
  107. parent.nodes.forEach((child, i) => {
  108. if (i) {
  109. child.raws.before = source
  110. .slice(parent.nodes[i - 1].raws.node.end, child.raws.node.start)
  111. .replace(/^\s*,+/, '');
  112. } else if (node) {
  113. child.raws.before = source.slice(node.start, child.raws.node.start).replace(/^\s*{+/, '');
  114. }
  115. });
  116. if (node) {
  117. let semicolon;
  118. let after;
  119. if (parent.nodes.length) {
  120. after = source.slice(parent.last.raws.node.end, node.end).replace(/^\s*,+/, () => {
  121. semicolon = true;
  122. return '';
  123. });
  124. } else {
  125. after = source.slice(node.start, node.end).replace(/^\s*{/, '');
  126. }
  127. parent.raws.after = after.replace(/}+\s*$/, '');
  128. parent.raws.semicolon = semicolon || false;
  129. }
  130. }
  131. sort(node) {
  132. node.nodes = node.nodes.sort((a, b) => a.raws.node.start - b.raws.node.start);
  133. }
  134. getNodeValue(node, wrappedValue) {
  135. const source = this.input.css;
  136. let rawValue;
  137. let cookedValue;
  138. switch (node.type) {
  139. case 'Identifier': {
  140. const isCssFloat = node.name === 'cssFloat';
  141. return {
  142. prefix: '',
  143. suffix: '',
  144. raw: isCssFloat && node.name,
  145. value: isCssFloat ? 'float' : node.name,
  146. };
  147. }
  148. case 'StringLiteral': {
  149. rawValue = node.extra.raw.slice(1, -1);
  150. cookedValue = node.value;
  151. break;
  152. }
  153. case 'TemplateLiteral': {
  154. rawValue = getTemplate(node, source);
  155. break;
  156. }
  157. default: {
  158. rawValue = source.slice(node.start, node.end);
  159. break;
  160. }
  161. }
  162. const valueWrap = wrappedValue.split(rawValue);
  163. return {
  164. prefix: valueWrap[0],
  165. suffix: valueWrap[1],
  166. value: cookedValue || rawValue,
  167. };
  168. }
  169. ObjectExpression(node, parent) {
  170. forEach(node.properties, (child) => {
  171. this.process(child, parent);
  172. });
  173. this.sort(parent);
  174. this.raws(parent, node);
  175. return parent;
  176. }
  177. ObjectProperty(node, parent) {
  178. const source = this.input.css;
  179. let between = source.indexOf(':', node.key.end);
  180. const rawKey = source.slice(node.start, between).trimRight();
  181. const rawValue = source.slice(between + 1, node.end).trimLeft();
  182. between = source.slice(node.start + rawKey.length, node.end - rawValue.length);
  183. const key = this.getNodeValue(node.key, rawKey);
  184. if (node.value.type === 'ObjectExpression') {
  185. let rule;
  186. if (/^@(\S+)(\s*)(.*)$/.test(key.value)) {
  187. const name = RegExp.$1;
  188. const afterName = RegExp.$2;
  189. const params = RegExp.$3;
  190. const atRule = postcss.atRule({
  191. name: unCamelCase(name),
  192. raws: {
  193. afterName,
  194. },
  195. nodes: [],
  196. });
  197. defineRaws(atRule, 'name', key.prefix + '@', params ? '' : key.suffix, {
  198. raw: 'camel',
  199. });
  200. if (params) {
  201. atRule.params = unCamelCaseProp(params);
  202. defineRaws(atRule, 'params', '', key.suffix, {
  203. raw: {
  204. enumerable: true,
  205. get: () => camelCaseProp(atRule.params),
  206. set: (value) => {
  207. atRule.params = unCamelCaseProp(value);
  208. },
  209. },
  210. });
  211. }
  212. rule = atRule;
  213. } else {
  214. // rule = this.rule(key, keyWrap, node.value, parent);
  215. rule = postcss.rule({
  216. selector: key.value,
  217. });
  218. defineRaws(rule, 'selector', key.prefix, key.suffix);
  219. }
  220. raw(rule);
  221. this.ObjectExpression(node.value, rule);
  222. return rule;
  223. }
  224. const value = this.getNodeValue(node.value, rawValue);
  225. if (key.value[0] === '@') {
  226. const atRule = postcss.atRule({
  227. name: unCamelCase(key.value),
  228. params: value.value,
  229. });
  230. defineRaws(atRule, 'name', key.prefix, key.suffix, {
  231. raw: 'camel',
  232. });
  233. defineRaws(atRule, 'params', value.prefix, value.suffix);
  234. raw(atRule);
  235. return atRule;
  236. } else {
  237. let decl;
  238. if (key.raw) {
  239. decl = postcss.decl({
  240. prop: key.value,
  241. value: value.value,
  242. raws: {
  243. prop: key,
  244. },
  245. });
  246. } else {
  247. decl = postcss.decl({
  248. prop: unCamelCase(key.value),
  249. value: value.value,
  250. });
  251. defineRaws(decl, 'prop', key.prefix, key.suffix, {
  252. raw: 'camel',
  253. });
  254. }
  255. defineRaws(decl, 'value', value.prefix, value.suffix);
  256. raw(decl);
  257. return decl;
  258. }
  259. function raw(postcssNode) {
  260. postcssNode.raws.between = between;
  261. postcssNode.raws.node = node;
  262. parent.push(postcssNode);
  263. }
  264. }
  265. literal(node, parent) {
  266. const literal = new Literal({
  267. text: this.input.css.slice(node.start, node.end),
  268. raws: {
  269. node,
  270. },
  271. });
  272. parent.push(literal);
  273. return literal;
  274. }
  275. comment(node, parent) {
  276. if (
  277. !parent.nodes ||
  278. (node.start < parent.raws.node.start && parent.type !== 'root' && parent.parent)
  279. ) {
  280. return this.comment(node, parent.parent);
  281. }
  282. const text = node.value.match(/^(\s*)((?:\S[\s\S]*?)?)(\s*)$/);
  283. const comment = postcss.comment({
  284. text: text[2],
  285. raws: {
  286. node,
  287. left: text[1],
  288. right: text[3],
  289. inline: node.type === 'CommentLine',
  290. },
  291. });
  292. parent.push(comment);
  293. return comment;
  294. }
  295. }
  296. module.exports = objectParser;