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.

index.js 10KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456
  1. 'use strict'
  2. var bail = require('bail')
  3. var buffer = require('is-buffer')
  4. var extend = require('extend')
  5. var plain = require('is-plain-obj')
  6. var trough = require('trough')
  7. var vfile = require('vfile')
  8. // Expose a frozen processor.
  9. module.exports = unified().freeze()
  10. var slice = [].slice
  11. var own = {}.hasOwnProperty
  12. // Process pipeline.
  13. var pipeline = trough()
  14. .use(pipelineParse)
  15. .use(pipelineRun)
  16. .use(pipelineStringify)
  17. function pipelineParse(p, ctx) {
  18. ctx.tree = p.parse(ctx.file)
  19. }
  20. function pipelineRun(p, ctx, next) {
  21. p.run(ctx.tree, ctx.file, done)
  22. function done(error, tree, file) {
  23. if (error) {
  24. next(error)
  25. } else {
  26. ctx.tree = tree
  27. ctx.file = file
  28. next()
  29. }
  30. }
  31. }
  32. function pipelineStringify(p, ctx) {
  33. var result = p.stringify(ctx.tree, ctx.file)
  34. if (result === undefined || result === null) {
  35. // Empty.
  36. } else if (typeof result === 'string' || buffer(result)) {
  37. ctx.file.contents = result
  38. } else {
  39. ctx.file.result = result
  40. }
  41. }
  42. // Function to create the first processor.
  43. function unified() {
  44. var attachers = []
  45. var transformers = trough()
  46. var namespace = {}
  47. var freezeIndex = -1
  48. var frozen
  49. // Data management.
  50. processor.data = data
  51. // Lock.
  52. processor.freeze = freeze
  53. // Plugins.
  54. processor.attachers = attachers
  55. processor.use = use
  56. // API.
  57. processor.parse = parse
  58. processor.stringify = stringify
  59. processor.run = run
  60. processor.runSync = runSync
  61. processor.process = process
  62. processor.processSync = processSync
  63. // Expose.
  64. return processor
  65. // Create a new processor based on the processor in the current scope.
  66. function processor() {
  67. var destination = unified()
  68. var index = -1
  69. while (++index < attachers.length) {
  70. destination.use.apply(null, attachers[index])
  71. }
  72. destination.data(extend(true, {}, namespace))
  73. return destination
  74. }
  75. // Freeze: used to signal a processor that has finished configuration.
  76. //
  77. // For example, take unified itself: it’s frozen.
  78. // Plugins should not be added to it.
  79. // Rather, it should be extended, by invoking it, before modifying it.
  80. //
  81. // In essence, always invoke this when exporting a processor.
  82. function freeze() {
  83. var values
  84. var transformer
  85. if (frozen) {
  86. return processor
  87. }
  88. while (++freezeIndex < attachers.length) {
  89. values = attachers[freezeIndex]
  90. if (values[1] === false) {
  91. continue
  92. }
  93. if (values[1] === true) {
  94. values[1] = undefined
  95. }
  96. transformer = values[0].apply(processor, values.slice(1))
  97. if (typeof transformer === 'function') {
  98. transformers.use(transformer)
  99. }
  100. }
  101. frozen = true
  102. freezeIndex = Infinity
  103. return processor
  104. }
  105. // Data management.
  106. // Getter / setter for processor-specific informtion.
  107. function data(key, value) {
  108. if (typeof key === 'string') {
  109. // Set `key`.
  110. if (arguments.length === 2) {
  111. assertUnfrozen('data', frozen)
  112. namespace[key] = value
  113. return processor
  114. }
  115. // Get `key`.
  116. return (own.call(namespace, key) && namespace[key]) || null
  117. }
  118. // Set space.
  119. if (key) {
  120. assertUnfrozen('data', frozen)
  121. namespace = key
  122. return processor
  123. }
  124. // Get space.
  125. return namespace
  126. }
  127. // Plugin management.
  128. //
  129. // Pass it:
  130. // * an attacher and options,
  131. // * a preset,
  132. // * a list of presets, attachers, and arguments (list of attachers and
  133. // options).
  134. function use(value) {
  135. var settings
  136. assertUnfrozen('use', frozen)
  137. if (value === null || value === undefined) {
  138. // Empty.
  139. } else if (typeof value === 'function') {
  140. addPlugin.apply(null, arguments)
  141. } else if (typeof value === 'object') {
  142. if ('length' in value) {
  143. addList(value)
  144. } else {
  145. addPreset(value)
  146. }
  147. } else {
  148. throw new Error('Expected usable value, not `' + value + '`')
  149. }
  150. if (settings) {
  151. namespace.settings = extend(namespace.settings || {}, settings)
  152. }
  153. return processor
  154. function addPreset(result) {
  155. addList(result.plugins)
  156. if (result.settings) {
  157. settings = extend(settings || {}, result.settings)
  158. }
  159. }
  160. function add(value) {
  161. if (typeof value === 'function') {
  162. addPlugin(value)
  163. } else if (typeof value === 'object') {
  164. if ('length' in value) {
  165. addPlugin.apply(null, value)
  166. } else {
  167. addPreset(value)
  168. }
  169. } else {
  170. throw new Error('Expected usable value, not `' + value + '`')
  171. }
  172. }
  173. function addList(plugins) {
  174. var index = -1
  175. if (plugins === null || plugins === undefined) {
  176. // Empty.
  177. } else if (typeof plugins === 'object' && 'length' in plugins) {
  178. while (++index < plugins.length) {
  179. add(plugins[index])
  180. }
  181. } else {
  182. throw new Error('Expected a list of plugins, not `' + plugins + '`')
  183. }
  184. }
  185. function addPlugin(plugin, value) {
  186. var entry = find(plugin)
  187. if (entry) {
  188. if (plain(entry[1]) && plain(value)) {
  189. value = extend(true, entry[1], value)
  190. }
  191. entry[1] = value
  192. } else {
  193. attachers.push(slice.call(arguments))
  194. }
  195. }
  196. }
  197. function find(plugin) {
  198. var index = -1
  199. while (++index < attachers.length) {
  200. if (attachers[index][0] === plugin) {
  201. return attachers[index]
  202. }
  203. }
  204. }
  205. // Parse a file (in string or vfile representation) into a unist node using
  206. // the `Parser` on the processor.
  207. function parse(doc) {
  208. var file = vfile(doc)
  209. var Parser
  210. freeze()
  211. Parser = processor.Parser
  212. assertParser('parse', Parser)
  213. if (newable(Parser, 'parse')) {
  214. return new Parser(String(file), file).parse()
  215. }
  216. return Parser(String(file), file) // eslint-disable-line new-cap
  217. }
  218. // Run transforms on a unist node representation of a file (in string or
  219. // vfile representation), async.
  220. function run(node, file, cb) {
  221. assertNode(node)
  222. freeze()
  223. if (!cb && typeof file === 'function') {
  224. cb = file
  225. file = null
  226. }
  227. if (!cb) {
  228. return new Promise(executor)
  229. }
  230. executor(null, cb)
  231. function executor(resolve, reject) {
  232. transformers.run(node, vfile(file), done)
  233. function done(error, tree, file) {
  234. tree = tree || node
  235. if (error) {
  236. reject(error)
  237. } else if (resolve) {
  238. resolve(tree)
  239. } else {
  240. cb(null, tree, file)
  241. }
  242. }
  243. }
  244. }
  245. // Run transforms on a unist node representation of a file (in string or
  246. // vfile representation), sync.
  247. function runSync(node, file) {
  248. var result
  249. var complete
  250. run(node, file, done)
  251. assertDone('runSync', 'run', complete)
  252. return result
  253. function done(error, tree) {
  254. complete = true
  255. result = tree
  256. bail(error)
  257. }
  258. }
  259. // Stringify a unist node representation of a file (in string or vfile
  260. // representation) into a string using the `Compiler` on the processor.
  261. function stringify(node, doc) {
  262. var file = vfile(doc)
  263. var Compiler
  264. freeze()
  265. Compiler = processor.Compiler
  266. assertCompiler('stringify', Compiler)
  267. assertNode(node)
  268. if (newable(Compiler, 'compile')) {
  269. return new Compiler(node, file).compile()
  270. }
  271. return Compiler(node, file) // eslint-disable-line new-cap
  272. }
  273. // Parse a file (in string or vfile representation) into a unist node using
  274. // the `Parser` on the processor, then run transforms on that node, and
  275. // compile the resulting node using the `Compiler` on the processor, and
  276. // store that result on the vfile.
  277. function process(doc, cb) {
  278. freeze()
  279. assertParser('process', processor.Parser)
  280. assertCompiler('process', processor.Compiler)
  281. if (!cb) {
  282. return new Promise(executor)
  283. }
  284. executor(null, cb)
  285. function executor(resolve, reject) {
  286. var file = vfile(doc)
  287. pipeline.run(processor, {file: file}, done)
  288. function done(error) {
  289. if (error) {
  290. reject(error)
  291. } else if (resolve) {
  292. resolve(file)
  293. } else {
  294. cb(null, file)
  295. }
  296. }
  297. }
  298. }
  299. // Process the given document (in string or vfile representation), sync.
  300. function processSync(doc) {
  301. var file
  302. var complete
  303. freeze()
  304. assertParser('processSync', processor.Parser)
  305. assertCompiler('processSync', processor.Compiler)
  306. file = vfile(doc)
  307. process(file, done)
  308. assertDone('processSync', 'process', complete)
  309. return file
  310. function done(error) {
  311. complete = true
  312. bail(error)
  313. }
  314. }
  315. }
  316. // Check if `value` is a constructor.
  317. function newable(value, name) {
  318. return (
  319. typeof value === 'function' &&
  320. value.prototype &&
  321. // A function with keys in its prototype is probably a constructor.
  322. // Classes’ prototype methods are not enumerable, so we check if some value
  323. // exists in the prototype.
  324. (keys(value.prototype) || name in value.prototype)
  325. )
  326. }
  327. // Check if `value` is an object with keys.
  328. function keys(value) {
  329. var key
  330. for (key in value) {
  331. return true
  332. }
  333. return false
  334. }
  335. // Assert a parser is available.
  336. function assertParser(name, Parser) {
  337. if (typeof Parser !== 'function') {
  338. throw new Error('Cannot `' + name + '` without `Parser`')
  339. }
  340. }
  341. // Assert a compiler is available.
  342. function assertCompiler(name, Compiler) {
  343. if (typeof Compiler !== 'function') {
  344. throw new Error('Cannot `' + name + '` without `Compiler`')
  345. }
  346. }
  347. // Assert the processor is not frozen.
  348. function assertUnfrozen(name, frozen) {
  349. if (frozen) {
  350. throw new Error(
  351. 'Cannot invoke `' +
  352. name +
  353. '` on a frozen processor.\nCreate a new processor first, by invoking it: use `processor()` instead of `processor`.'
  354. )
  355. }
  356. }
  357. // Assert `node` is a unist node.
  358. function assertNode(node) {
  359. if (!node || typeof node.type !== 'string') {
  360. throw new Error('Expected node, got `' + node + '`')
  361. }
  362. }
  363. // Assert that `complete` is `true`.
  364. function assertDone(name, asyncName, complete) {
  365. if (!complete) {
  366. throw new Error(
  367. '`' + name + '` finished async. Use `' + asyncName + '` instead'
  368. )
  369. }
  370. }