UNPKG

18.9 kBJavaScriptView Raw
1// Generated by CoffeeScript 2.5.1
2// Imports
3var CSON, extractOptsAndCallback, fsUtil, pathUtil, requireFresh;
4
5fsUtil = require('safefs');
6
7pathUtil = require('path');
8
9extractOptsAndCallback = require('extract-opts');
10
11requireFresh = require('requirefresh');
12
13// Public: The exported CSON singleton
14CSON = class CSON {
15 // ====================================
16 // Helpers
17
18 // Internal: Ensure Error Type
19 ensureErrorType(err) {
20 if (err instanceof Error) {
21 return err;
22 } else {
23 return this.ensureErrorType(err);
24 }
25 }
26
27 // Internal: Complete with callback if it exists
28 complete(result, next) {
29 // Complete
30 if (next) {
31 if (result instanceof Error) {
32 next(result);
33 } else {
34 next(null, result);
35 }
36 return this;
37 } else {
38 return result;
39 }
40 }
41
42 // Internal: Fills in any missing options for use in our methods
43
44 // opts - {Object} The options to prepare
45
46 // Returns the same opts {Object} that we received
47 getOptions(opts = {}) {
48 if (opts.format == null) {
49 opts.format = null;
50 }
51 if (opts.filename == null) {
52 opts.filename = null;
53 }
54 if (opts.filename) {
55 opts.filename = pathUtil.resolve(opts.filename);
56 if (opts.format == null) {
57 opts.format = this.getFormat(opts.filename);
58 }
59 }
60 if (opts.filename === null) {
61 delete opts.filename;
62 }
63 if (opts.json == null) {
64 opts.json = true;
65 }
66 if (opts.cson == null) {
67 opts.cson = true;
68 }
69 if (opts.javascript == null) {
70 opts.javascript = false;
71 }
72 if (opts.coffeescript == null) {
73 opts.coffeescript = false;
74 }
75 return opts;
76 }
77
78 // Internal: Gets the format for a file name or path
79
80 // file - {String} to get the format for
81
82 // Returns the determined format as a {String} ("json", "cson", "coffeescript", or "javascript", or null)
83 getFormat(file) {
84 switch (pathUtil.extname(file)) {
85 case '.json':
86 return 'json';
87 case '.cson':
88 return 'cson';
89 case '.coffee':
90 return 'coffeescript';
91 case '.js':
92 return 'javascript';
93 default:
94 return null;
95 }
96 }
97
98 // Internal: Helper for {::createString}, {::parseString}, {::parseFile}, {::requireFile}
99 action(args) {
100 var action, data, next, opts, prefix, ref, result, suffix;
101 // Prepare
102 ({action, prefix, suffix, data, opts, next} = args);
103 if (suffix == null) {
104 suffix = '';
105 }
106 [opts, next] = extractOptsAndCallback(opts, next);
107 // Prepare options
108 switch (action) {
109 case 'requireFile':
110 case 'parseFile':
111 if (opts.filename == null) {
112 opts.filename = data;
113 }
114 }
115 // Add defaults
116 opts = this.getOptions(opts);
117 // Default: CSON
118 if ((ref = opts.format) === null || ref === 'cson') {
119 if (opts.cson === true) {
120 result = this[prefix + 'CSON' + suffix](data, opts);
121 } else {
122 result = new Error(`CSON.${action}: Desired format is CSON however CSON is disabled by an option`);
123 }
124 // JSON
125 } else if (opts.format === 'json') {
126 if (opts.json === true) {
127 result = this[prefix + 'JSON' + suffix](data, opts);
128 } else {
129 result = new Error(`CSON.${action}: Desired format is JSON however JSON is disabled by an option`);
130 }
131 // JavaScript
132 } else if (opts.format === 'javascript') {
133 if (opts.javascript === true) {
134 result = this[prefix + 'JS' + suffix](data, opts);
135 } else {
136 result = new Error(`CSON.${action}: Desired format is JavaScript however JavaScript is disabled by an option`);
137 }
138 // CoffeeScript
139 } else if (opts.format === 'coffeescript') {
140 if (opts.coffeescript === true) {
141 result = this[prefix + 'CS' + suffix](data, opts);
142 } else {
143 result = new Error(`CSON.${action}: Desired format is CoffeeScript however CoffeeScript is disabled by an option`);
144 }
145 } else {
146 result = new Error(`CSON.${action}: Desired format is not supported`);
147 }
148 // Complete
149 return this.complete(result, next);
150 }
151
152 // ====================================
153 // Bundles
154
155 // Public: {Delegates to: .createString}
156 stringify(data, replacer, indent) {
157 var opts;
158 opts = {};
159 opts.replacer = replacer;
160 opts.indent = indent;
161 return this.createCSONString(data, opts);
162 }
163
164 // Public: {Delegates to: .parseCSONString}
165 parse(data, opts, next) {
166 return this.parseCSONString(data, opts, next);
167 }
168
169 // Public: {Delegates to: .parseCSONFile}
170 load(data, opts, next) {
171 return this.parseCSONFile(data, opts, next);
172 }
173
174 // Public: Converts an {Object} into a {String} of the desired format
175
176 // If the format option is not specified, we default to CSON
177
178 // data - {Object} The data to convert
179 // opts - {Object} The options (options may also be forwarded onto the parser library)
180 // :format - {String} The format to use: "cson" (default), "json", "coffeescript", or "javascript"
181 // :cson - {Boolean} Whether or not the CSON format should be allowed (defaults to `true`)
182 // :json - {Boolean} Whether or not the JSON format should be allowed (defaults to `true`)
183
184 // Returns {String} or {Error}
185 createString(data, opts, next) {
186 return this.action({
187 action: 'createString',
188 prefix: 'create',
189 suffix: 'String',
190 data,
191 opts,
192 next
193 });
194 }
195
196 // Public: Converts a {String} of the desired format into an {Object}
197
198 // If the format option is not specified, we default to CSON
199
200 // data - {String} The string to parse
201 // opts - {Object} The options (options may also be forwarded onto the parser library)
202 // :format - {String} The format to use: "cson" (default), "json", "coffeescript", or "javascript"
203 // :cson - {Boolean} Whether or not the CSON format should be allowed (defaults to `true`)
204 // :json - {Boolean} Whether or not the JSON format should be allowed (defaults to `true`)
205 // :coffeescript - {Boolean} Whether or not the CoffeeScript format should be allowed (defaults to `false`)
206 // :json - {Boolean} Whether or not the CoffeeScript format should be allowed (defaults to `json`)
207
208 // Returns {Object} or {Error}
209 parseString(data, opts, next) {
210 return this.action({
211 action: 'parseString',
212 prefix: 'parse',
213 suffix: 'String',
214 data,
215 opts,
216 next
217 });
218 }
219
220 // Public: Parses a file path of the desired format into an {Object}
221
222 // If the format option is not specified, we use the filename to detect what it should be, otherwise we default to CSON
223
224 // data - {String} The file path to parse
225 // opts - {Object} The options (options may also be forwarded onto the parser library)
226 // :format - {String} The format to use: "cson" (default), "json", "coffeescript", or "javascript"
227 // :cson - {Boolean} Whether or not the CSON format should be allowed (defaults to `true`)
228 // :json - {Boolean} Whether or not the JSON format should be allowed (defaults to `true`)
229 // :coffeescript - {Boolean} Whether or not the CoffeeScript format should be allowed (defaults to `false`)
230 // :json - {Boolean} Whether or not the CoffeeScript format should be allowed (defaults to `json`)
231
232 // Returns {Object} or {Error}
233 parseFile(data, opts, next) {
234 return this.action({
235 action: 'parseFile',
236 prefix: 'parse',
237 suffix: 'File',
238 data,
239 opts,
240 next
241 });
242 }
243
244 // Public: Requires or parses a file path of the desired format into an {Object}
245
246 // If the format option is not specified, we use the filename to detect what it should be, otherwise we default to CSON
247
248 // data - {String} The file path to require or parse
249 // opts - {Object} The options (options may also be forwarded onto the parser library)
250 // :format - {String} The format to use: "cson" (default), "json", "coffeescript", or "javascript"
251 // :cson - {Boolean} Whether or not the CSON format should be allowed (defaults to `true`)
252 // :json - {Boolean} Whether or not the JSON format should be allowed (defaults to `true`)
253 // :coffeescript - {Boolean} Whether or not the CoffeeScript format should be allowed (defaults to `false`)
254 // :json - {Boolean} Whether or not the CoffeeScript format should be allowed (defaults to `json`)
255
256 // Returns {Object} or {Error}
257 requireFile(data, opts, next) {
258 return this.action({
259 action: 'requireFile',
260 prefix: 'require',
261 suffix: 'File',
262 data,
263 opts,
264 next
265 });
266 }
267
268 // ====================================
269 // Creating Strings from Objects
270
271 // Public: Converts an {Object} into a JSON {String}
272
273 // data - {Object} The data to convert
274 // opts - {Object} The options (options may also be forwarded onto the parser library)
275 // :replacer - {Boolean} The replacer option for `JSON.stringify` (defaults to `null`)
276 // :indent - {Boolean} The indent option for `JSON.stringify` (defaults to two spaces ` `)
277
278 // Returns {String} or {Error}
279 createJSONString(data, opts, next) {
280 var err, result;
281 // Prepare
282 [opts, next] = extractOptsAndCallback(opts, next);
283 opts = this.getOptions(opts);
284 if (opts.replacer == null) {
285 opts.replacer = null;
286 }
287 if (opts.indent == null) {
288 opts.indent = ' ';
289 }
290 try {
291 // Stringify
292 result = JSON.stringify(data, opts.replacer, opts.indent);
293 } catch (error) {
294 err = error;
295 result = this.ensureErrorType(err);
296 }
297 // Complete
298 return this.complete(result, next);
299 }
300
301 // Public: Converts an {Object} into a CSON {String}
302
303 // data - {Object} The data to convert
304 // opts - {Object} The options (options may also be forwarded onto the parser library)
305 // :replacer - {Boolean} The replacer option for `require('cson-parser').stringify` (defaults to `null`)
306 // :indent - {Boolean} The indent option for `require('cson-parser').stringify` (defaults to a single tab `'\t'`)
307
308 // Returns {String} or {Error}
309 createCSONString(data, opts, next) {
310 var err, result;
311 // Prepare
312 [opts, next] = extractOptsAndCallback(opts, next);
313 opts = this.getOptions(opts);
314 if (opts.replacer == null) {
315 opts.replacer = null;
316 }
317 if (opts.indent == null) {
318 opts.indent = '\t';
319 }
320 try {
321 // Stringify
322 result = require('cson-parser').stringify(data, opts.replacer, opts.indent);
323 } catch (error) {
324 err = error;
325 result = this.ensureErrorType(err);
326 }
327 // Complete
328 return this.complete(result, next);
329 }
330
331 // Private: Not yet supported
332 createCSString(data, opts, next) {
333 var result;
334 // Prepare
335 [opts, next] = extractOptsAndCallback(opts, next);
336 // Stringify
337 result = new Error('CSON.createCS: Creating CoffeeScript code is not yet supported');
338 // Complete
339 return this.complete(result, next);
340 }
341
342 /*
343 Potentially we could use something like the following from CSON v1
344 However the JSON.stringify gets rid of functions...
345 which is the entire point of the coffeescript mode over the CSON mode...
346 So until we figure out how to toString() an object and keep the functions intact,
347 unsafe stringifying to CSON or CS or JS won't happen.
348
349 Perhaps https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/toSource
350 will be of use one day
351
352 src = "var result = #{JSON.stringify obj}"
353 result = require('js2coffee').build(src, opts).code
354 result = result.replace(/^\s*result\s*\=\s/, '')
355 if /^\s/.test(result) is false
356 result = result.trim()
357 if typeof obj is 'object'
358 unless Array.isArray(obj)
359 result = '{'+result+'}' unless result is '{}'
360 return result
361 */
362 // Private: Not yet supported
363 createJSString(data, opts, next) {
364 var result;
365 // Prepare
366 [opts, next] = extractOptsAndCallback(opts, next);
367 // Stringify
368 result = new Error('CSON.createJS: Creating JavaScript code is not yet supported');
369 // Complete
370 return this.complete(result, next);
371 }
372
373 // ====================================
374 // Parsing Strings to Objects
375
376 // Public: Parses a JSON {String} into an {Object}
377
378 // data - The JSON {String} to parse
379 // opts - {Object} The options, unused
380
381 // Returns {Object} or {Error}
382 parseJSONString(data, opts, next) {
383 var err, result;
384 // Prepare
385 [opts, next] = extractOptsAndCallback(opts, next);
386 try {
387 // Parse
388 result = JSON.parse(data);
389 } catch (error) {
390 err = error;
391 result = this.ensureErrorType(err);
392 }
393 // Complete
394 return this.complete(result, next);
395 }
396
397 // Public: Parses a CSON {String} into an {Object}
398
399 // data - The CSON {String} to parse
400 // opts - {Object} The options, unused
401
402 // Returns {Object} or {Error}
403 parseCSONString(data, opts, next) {
404 var err, result;
405 // Prepare
406 [opts, next] = extractOptsAndCallback(opts, next);
407 try {
408 // Parse
409 result = require('cson-parser').parse(data);
410 } catch (error) {
411 err = error;
412 result = this.ensureErrorType(err);
413 }
414 // Complete
415 return this.complete(result, next);
416 }
417
418 // Public: Parses a JavaScript {String} into an {Object}
419
420 // data - The JavaScript {String} to parse
421 // opts - {Object} The options (also passed to require('vm').runInNewContex)
422 // :context - {Object} The context option that is used in `require('vm').runInNewContext`, defaults to an empty object `{}`
423
424 // Returns {Object} or {Error}
425 parseJSString(data, opts, next) {
426 var err, result;
427 // Prepare
428 [opts, next] = extractOptsAndCallback(opts, next);
429 opts = this.getOptions(opts);
430 if (opts.context == null) {
431 opts.context = {};
432 }
433 try {
434 // Parse
435 result = require('vm').runInNewContext(data, opts.context, opts);
436 } catch (error) {
437 err = error;
438 result = this.ensureErrorType(err);
439 }
440 // Complete
441 return this.complete(result, next);
442 }
443
444 // Public: Parses a CoffeeScript {String} into an {Object}
445
446 // data - The CoffeeScript {String} to parse
447 // opts - {Object} The options, forwarded onto `require('coffeescript').eval`
448
449 // Returns {Object} or {Error}
450 parseCSString(data, opts, next) {
451 var err, result;
452 // Prepare
453 [opts, next] = extractOptsAndCallback(opts, next);
454 opts = this.getOptions(opts);
455 try {
456 // Parse
457 result = require('coffeescript').eval(data, opts);
458 } catch (error) {
459 err = error;
460 result = this.ensureErrorType(err);
461 }
462 // Complete
463 return this.complete(result, next);
464 }
465
466 // ====================================
467 // Parsing Files to Objects
468
469 // Public: Parses a JSON file into an {Object}
470
471 // data - {String} The file path to parse
472 // opts - {Object} The options, forwarded onto {::parseJSONString}
473
474 // Returns {Object} or {Error}
475 parseJSONFile(file, opts, next) {
476 var result;
477 // Prepare
478 [opts, next] = extractOptsAndCallback(opts, next);
479 // Parse
480 result = fsUtil.readFileSync(file);
481 if (result instanceof Error) {
482 result = result;
483 } else {
484 result = this.parseJSONString(result.toString(), opts);
485 }
486 // Complete
487 return this.complete(result, next);
488 }
489
490 // Public: Parses a CSON file into an {Object}
491
492 // data - {String} The file path to parse
493 // opts - {Object} The options, forwarded onto {::parseCSONString}
494
495 // Returns {Object} or {Error}
496 parseCSONFile(file, opts, next) {
497 var result;
498 // Prepare
499 [opts, next] = extractOptsAndCallback(opts, next);
500 // Parse
501 result = fsUtil.readFileSync(file);
502 if (result instanceof Error) {
503 result = result;
504 } else {
505 result = this.parseCSONString(result.toString(), opts);
506 }
507 // Complete
508 return this.complete(result, next);
509 }
510
511 // Public: Parses a JAvaScript file into an {Object}
512
513 // data - {String} The file path to parse
514 // opts - {Object} The options, forwarded onto {::parseJSString}
515
516 // Returns {Object} or {Error}
517 parseJSFile(file, opts, next) {
518 var result;
519 // Prepare
520 [opts, next] = extractOptsAndCallback(opts, next);
521 // Parse
522 result = fsUtil.readFileSync(file);
523 if (result instanceof Error) {
524 result = result;
525 } else {
526 result = this.parseJSString(result.toString(), opts);
527 }
528 // Complete
529 return this.complete(result, next);
530 }
531
532 // Public: Parses a CoffeeScript file into an {Object}
533
534 // data - {String} The file path to parse
535 // opts - {Object} The options, forwarded onto {::parseCSString}
536
537 // Returns {Object} or {Error}
538 parseCSFile(file, opts, next) {
539 var result;
540 // Prepare
541 [opts, next] = extractOptsAndCallback(opts, next);
542 // Parse
543 result = fsUtil.readFileSync(file);
544 if (result instanceof Error) {
545 result = result;
546 } else {
547 result = this.parseCSString(result.toString(), opts);
548 }
549 // Complete
550 return this.complete(result, next);
551 }
552
553 // ====================================
554 // Requiring Files to Objects
555
556 // Public: {Delegates to: .parseJSONFile}
557 requireJSONFile(file, opts, next) {
558 var result;
559 // Prepare
560 [opts, next] = extractOptsAndCallback(opts, next);
561 // Require
562 result = this.parseJSONFile(file, opts);
563 // Complete
564 return this.complete(result, next);
565 }
566
567 // Public: {Delegates to: .parseCSONFile}
568 requireCSONFile(file, opts, next) {
569 var result;
570 // Prepare
571 [opts, next] = extractOptsAndCallback(opts, next);
572 // Require
573 result = this.parseCSONFile(file, opts);
574 // Complete
575 return this.complete(result, next);
576 }
577
578 // Public: Requires a JavaScript file and returns the result {Object}
579
580 // data - {String} The file path to require
581 // opts - {Object} The options, unused
582
583 // Returns {Object} or {Error}
584 requireJSFile(file, opts, next) {
585 var err, result;
586 // Prepare
587 [opts, next] = extractOptsAndCallback(opts, next);
588 try {
589 // Require
590 result = requireFresh(file);
591 } catch (error) {
592 err = error;
593 result = this.ensureErrorType(err);
594 }
595 // Complete
596 return this.complete(result, next);
597 }
598
599 // Public: Requires a CoffeeScript file and returns the result {Object}
600
601 // data - {String} The file path to require
602 // opts - {Object} The options, unused
603
604 // Returns {Object} or {Error}
605 requireCSFile(file, opts, next) {
606 var err, result;
607 // Prepare
608 [opts, next] = extractOptsAndCallback(opts, next);
609 // Require
610 require('coffeescript/register');
611 try {
612 result = requireFresh(file);
613 } catch (error) {
614 err = error;
615 result = this.ensureErrorType(err);
616 }
617 // Complete
618 return this.complete(result, next);
619 }
620
621};
622
623// Export
624module.exports = new CSON();