1 | // Generated by CoffeeScript 2.5.1
|
2 | // Imports
|
3 | var CSON, extractOptsAndCallback, fsUtil, pathUtil, requireFresh;
|
4 |
|
5 | fsUtil = require('safefs');
|
6 |
|
7 | pathUtil = require('path');
|
8 |
|
9 | extractOptsAndCallback = require('extract-opts');
|
10 |
|
11 | requireFresh = require('requirefresh');
|
12 |
|
13 | // Public: The exported CSON singleton
|
14 | CSON = 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
|
624 | module.exports = new CSON();
|