]> Dogcows Code - chaz/p5-CGI-Ex/blob - lib/CGI/Ex/yaml_load.js
CGI::Ex 2.07
[chaz/p5-CGI-Ex] / lib / CGI / Ex / yaml_load.js
1 /**----------------------------------------------------------------***
2 * Copyright 2007 - Paul Seamons *
3 * Distributed under the Perl Artistic License without warranty *
4 * Based upon YAML.pm v0.35 from Perl *
5 ***----------------------------------------------------------------**/
6
7 // $Revision: 1.18 $
8
9 // allow for missing methods in ie 5.0
10
11 if (! Array.prototype.unshift)
12 Array.prototype.unshift = function (add) {
13 for (var i=this.length; i > 0; i--) this[i] = this[i - 1];
14 this[0] = add;
15 };
16
17 if (!Array.prototype.shift)
18 Array.prototype.shift = function () {
19 var ret = this[0];
20 for (var i=0; i<this.length-1; i++) this[i] = this[i + 1];
21 this.length -= 1;
22 return ret;
23 };
24
25 if (!Array.prototype.push)
26 Array.prototype.push = function (add) {
27 this[this.length] = add;
28 };
29
30 // and now - the rest of the library
31
32 function YAML () {
33 this.parse = yaml_parse;
34 this.error = yaml_error;
35 this.warn = yaml_warn;
36 this.parse_throwaway = yaml_parse_throwaway;
37 this.parse_node = yaml_parse_node;
38 this.parse_next_line = yaml_parse_next_line;
39 this.parse_qualifiers = yaml_parse_qualifiers;
40 this.parse_explicit = yaml_parse_explicit;
41 this.parse_implicit = yaml_parse_implicit;
42 this.parse_map = yaml_parse_map;
43 this.parse_seq = yaml_parse_seq;
44 this.parse_inline = yaml_parse_inline;
45 }
46
47 function yaml_error (err) {
48 err += '\nDocument: '+this.document+'\n';
49 err += '\nLine: ' +this.line +'\n';
50 if (! document.hide_yaml_errors) alert(err);
51 document.yaml_error_occured = 1;
52 return;
53 }
54
55 function yaml_warn (err) {
56 if (! document.hide_yaml_errors) alert(err);
57 return;
58 }
59
60 function yaml_parse (text) {
61 document.yaml_error_occured = undefined;
62
63 // translate line endings down to \012
64 text = text.replace(new RegExp('\015\012','g'), '\012');
65 text = text.replace(new RegExp('\015','g'), '\012');
66 if (text.match('[\\x00-\\x08\\x0B-\\x0D\\x0E-\\x1F]'))
67 return this.error("Bad characters found");
68 if (text.length && ! text.match('\012$'))
69 text += '\012';
70
71 this.line = 1;
72 this.lines = text.split("\012");
73 this.document = 0;
74 this.documents = new Array();
75
76 this.parse_throwaway();
77 if (! this.eoy && ! this.lines[0].match('^---(\\s|$)')) {
78 this.lines.unshift('--- #YAML:1.0');
79 this.line --;
80 }
81
82 // loop looking for data structures
83 while (! this.eoy) {
84 this.anchors = new Array();
85 this.offset = new Array();
86 this.options = new Array();
87 this.document ++;
88 this.done = 0;
89 this.level = 0;
90 this.offset[0] = -1;
91 this.preface = '';
92 this.content = '';
93 this.indent = -1;
94
95 var m = this.lines[0].match('---\\s*(.*)$')
96 if (! m) return this.error("Missing YAML separator\n("+this.lines[0]+")");
97 var words = m[1].split("\\s+");
98 while (words.length && (m = words[0].match('^#(\\w+):(\\S.*)$'))) {
99 words.shift();
100 if (this.options[m[1]]) {
101 yaml.warn("Parse warn - multiple options " + m[1]);
102 continue;
103 }
104 this.options[m[1]] = m[2];
105 }
106
107 if (this.options['YAML'] && this.options['YAML'] != '1.0')
108 return this.error('Bad YAML version number - must be 1.0');
109 if (this.options['TAB'] && ! this.options['TAB'].match('^(NONE|\\d+)(:HARD)?$'))
110 return this.error('Unrecognized TAB policy');
111
112 this.documents.push(this.parse_node());
113 }
114
115 return this.documents;
116 }
117
118 function yaml_parse_throwaway () {
119 while (this.lines.length && this.lines[0].match('^\\s*(#|$)')) {
120 this.lines.shift();
121 this.line ++;
122 }
123 this.eoy = this.done = ! this.lines.length;
124 }
125
126 function yaml_parse_node (no_next) {
127 if (! no_next) this.parse_next_line(2); // COLLECTION
128
129 var preface = this.preface;
130 this.preface = '';
131 var node = '';
132 var type = '';
133 var indicator = '';
134 var escape = '';
135 var chomp = '';
136
137 var info = this.parse_qualifiers(preface);
138 var anchor = info[0];
139 var alias = info[1];
140 var explicit = info[2];
141 var implicit = info[3];
142 var yclass = info[4];
143 preface = info[5];
144
145
146 if (alias) {
147 if (! this.anchors[alias]) return this.error("Parse error - missing alias: "+alias);
148 return this.anchors[alias];
149 }
150
151 // see if this is a literal or an unfold block
152 this.inline = '';
153 if (preface.length) {
154 m = preface.match('^([>\\|])([+\\-]?)\\d*\\s*');
155 if (m) {
156 indicator = m[1];
157 chomp = m[2];
158 preface = preface.substring(0,m[0].length);
159 } else {
160 this.inline = preface;
161 preface = '';
162 }
163 }
164
165
166 if (this.inline.length) {
167 node = this.parse_inline(1, implicit, explicit, yclass);
168 if (this.inline.length) return this.error("Parse error - must be single line ("+this.inline+')');
169 } else {
170 this.level ++;
171 // block items
172 if (indicator) {
173 node = '';
174 while (! this.done && this.indent == this.offset[this.level]) {
175 node += this.content + '\n';
176 this.parse_next_line(1); // LEAF
177 }
178 if (indicator == '>') {
179 node = node.replace(new RegExp('[ \\t]*\n[ \\t]*(\\S)','gm'), ' $1');
180 }
181 if (! chomp || chomp == '-') node = node.replace(new RegExp('\n$',''),'');
182 if (implicit) node = this.parse_implicit(node);
183
184 } else {
185 if (! this.offset[this.level]) this.offset[this.level] = 0;
186 if (this.indent == this.offset[this.level]) {
187 if (this.content.match('^-( |$)')) {
188 node = this.parse_seq(anchor);
189 } else if (this.content.match('(^\\?|:( |$))')) {
190 node = this.parse_map(anchor);
191 } else if (preface.match('^\\s*$')) {
192 node = ''; //this.parse_implicit('');
193 } else {
194 return this.error('Parse error - bad node +('+this.content+')('+preface+')');
195 }
196 } else {
197 node = '';
198 }
199 }
200 this.level --
201 }
202 this.offset = this.offset.splice(0, this.level + 1);
203
204 if (explicit) {
205 if (yclass) return this.error("Parse error - classes not supported");
206 else node = this.parse_explicit(node, explicit);
207 }
208 if (anchor) this.anchors[anchor] = node;
209
210 return node;
211 }
212
213 function yaml_parse_next_line (type) {
214 var m;
215 var level = this.level;
216 var offset = this.offset[level];
217
218 if (offset == undefined) return this.error("Parse error - Bad level " + level);
219
220 // done with the current line - get the next
221 // remove following commented lines
222 this.lines.shift();
223 this.line ++;
224 this.eoy = this.done = ! this.lines.length;
225 if (this.eoy) return;
226 this.parse_throwaway();
227 if (this.eoy) return;
228
229 // Determine the offset for a new leaf node
230 if (this.preface && (m = this.preface.match('[>\\|][+\\-]?(\\d*)\\s*$'))) {
231 if (m[1].length && m[1] == '0') return this.error("Parse error zero indent");
232 type = 1;
233 if (m[1].length) {
234 this.offset[level + 1] = offset + m[1];
235 } else if ((m = this.lines[0].match('^( *)\\S')) && m[1].length > offset) {
236 this.offset[level + 1] = m[1].length;
237 } else {
238 this.offset[level + 1] = offset + 1;
239 }
240 level ++;
241 offset = this.offset[level];
242 }
243
244 // COLLECTION
245 if (type == 2 && this.preface.match('^\\s*(!\\S*|&\\S+)*\\s*$')) {
246 m = this.lines[0].match('^( *)\\S');
247 if (! m) return this.error("Missing leading space on line "+this.lines[0]);
248 this.offset[level + 1] = (m[1].length > offset) ? m[1].length : offset + 1;
249 offset = this.offset[++ level];
250
251 // LEAF
252 } else if (type == 1) {
253 // skip blank lines and comment lines
254 while (this.lines.length && this.lines[0].match('^\\s*(#|$)')) {
255 m = this.lines[0].match('^( *)');
256 if (! m) return this.error("Missing leading space on comment " + this.lines[0]);
257 if (m[1].length > offset) break;
258 this.lines.shift();
259 this.line ++;
260 }
261 this.eoy = this.done = ! this.lines.length;
262 } else {
263 this.parse_throwaway();
264 }
265
266 if (this.eoy) return;
267 if (this.lines[0].match('^---(\\s|$)')) {
268 this.done = 1;
269 return;
270 }
271
272 if (type == 1 && (m = this.lines[0].match('^ {'+offset+'}(.*)$'))) {
273 this.indent = offset;
274 this.content = m[1];
275 } else if (this.lines[0].match('^\\s*$')) {
276 this.indent = offset;
277 this.content = '';
278 } else {
279 m = this.lines[0].match('^( *)(\\S.*)$');
280 // # yaml.warn(" indent(${\length($1)}) offsets(@{$o->{offset}}) \n");
281 var len = (m) ? m[1].length : 0;
282 while (this.offset[level] > len) level --;
283 if (this.offset[level] != len)
284 return this.error("Parse error inconsitent indentation:\n"
285 + '(this.lines[0]: '+this.lines[0]+', len: '+len+', level: '+level+', this.offset[level]: '+this.offset[level]+')\n');
286
287 this.indent = len;
288 this.content = m ? m[2] : '';
289 }
290
291 if (this.indent - offset > 1)
292 return this.error("Parse error - indentation");
293
294 return;
295 }
296
297 function yaml_parse_qualifiers (preface) {
298 var info = new Array();
299 // 0 = anchor
300 // 1 = alias
301 // 2 = explicit
302 // 3 = implicit
303 // 4 = class - not used for now
304 // 5 = preface
305
306 var m;
307 while (preface.match('^[&\\*!]')) {
308 // explicit, implicit
309 if (m = preface.match('^\!(\\S*)\\s*')) {
310 preface = preface.substring(m[0].length);
311 if (m[1].length) info[2] = m[1];
312 else info[3] = 1;
313 // anchor, alias
314 } else if (m = preface.match('^([&\\*])([^ ,:]+)\\s*')) {
315 preface = preface.substring(m[0].length);
316 if (! m[2].match('^\\w+$')) return this.error("Bad name "+m[2]);
317 if (info[0] || info[1]) return this.error("Already found anchor or alias "+m[2]);
318 if (m[1] == '&') info[0] = m[2];
319 if (m[1] == '*') info[1] = m[2];
320 }
321 }
322
323 info[5] = preface;
324 return info;
325 }
326
327 function yaml_parse_explicit (node, explicit) {
328 var m;
329 if (m = explicit.match('^(int|float|bool|date|time|datetime|binary)$')) {
330 // return this.error("No handler yet for explict " + m[1]);
331 // just won't check types for now
332 return node;
333 } else if (m = explicit.match('^perl/(glob|regexp|code|ref):(\\w(\\w|::)*)?$')) {
334 return this.error("No handler yet for perltype " + m[1]);
335 } else if (m = explicit.match('^perl/(\\@|\\$)?([a-zA-Z](\\w|::)+)$')) {
336 return this.error("No handler yet for perl object " + m[1]);
337 } else if (! (m = explicit.match('/'))) {
338 return this.error("Load error - no conversion "+explicit);
339 } else {
340 return this.error("No YAML::Node handler made yet "+explicit);
341 }
342 }
343
344 function yaml_parse_implicit (value) {
345 value.replace(new RegExp('\\s*$',''),'');
346 if (value == '') return '';
347 if (value.match('^-?\\d+$')) return 0 + value;
348 if (value.match('^[+-]?(\\d*)(\\.\\d*|)?([Ee][+-]?\\d+)?$')) return 1 * value;
349 if (value.match('^\\d{4}\-\\d{2}\-\\d{2}(T\\d{2}:\\d{2}:\\d{2}(\\.\\d*[1-9])?(Z|[-+]\\d{2}(:\\d{2})?))?$')
350 || value.match('^\\w')) return "" + value;
351 if (value == '~') return undefined;
352 if (value == '+') return 1;
353 if (value == '-') return 0;
354 return this.error("Parse Error bad implicit value ("+value+")");
355 }
356
357 function yaml_parse_map (anchor) {
358 var m;
359 var node = new Array ();
360 if (anchor) this.anchors[anchor] = node;
361
362 while (! this.done && this.indent == this.offset[this.level]) {
363 var key;
364 if (this.content.match('^\\?\\s*')) {
365 this.preface = this.content;
366 key = '' + this.parse_node();
367 } else if (m = this.content.match('^=\\s*')) {
368 this.content = this.content.substring(m[0].length);
369 key = "\x07YAML\x07VALUE\x07";
370 } else if (m = this.content.match('^//\\s*')) {
371 this.content = this.content.substring(m[0].length);
372 key = "\x07YAML\x07COMMENT\x07";
373 } else {
374
375 this.inline = this.content;
376 key = this.parse_inline();
377 this.content = this.inline;
378 this.inline = '';
379 }
380
381 if (! (m = this.content.match('^:\\s*'))) return this.error("Parse error - bad map element "+this.content);
382 this.content = this.content.substring(m[0].length);
383
384 this.preface = this.content;
385
386 var value = this.parse_node();
387
388 if (node[key]) this.warn('Warn - duplicate key '+key);
389 else node[key] = value;
390
391 }
392
393 return node;
394 }
395
396 function yaml_parse_seq (anchor) {
397 var m;
398 var node = new Array ();
399 if (anchor) this.anchors[anchor] = node;
400 while (! this.done && this.indent == this.offset[this.level]) {
401 var m;
402 if ((m = this.content.match('^- (.*)$')) || (m = this.content.match('^-()$'))) {
403 this.preface = m[1];
404 } else return this.error("Parse error - bad seq element "+this.content);
405
406 if (m = this.preface.match('^(\\s*)(\\w.*:( |$).*)$')) {
407 this.indent = this.offset[this.level] + 2 + m[1].length;
408 this.content = m[2];
409 this.offset[++ this.level] = this.indent;
410 this.preface = '';
411 node.push(this.parse_map(''));
412 this.level --;
413 this.offset[this.offset.length - 1] = this.level;
414 } else {
415 node.push(this.parse_node());
416 }
417 }
418
419 return node;
420 }
421
422 function yaml_parse_inline (top, top_implicit, top_explicit, top_class) {
423 this.inline = this.inline.replace('^\\s+','').replace(new RegExp('\\s+$',''),'');
424
425 var info = this.parse_qualifiers(this.inline);
426 var anchor = info[0];
427 var alias = info[1];
428 var explicit = info[2];
429 var implicit = info[3];
430 var yclass = info[4];
431 this.inline = info[5];
432 var node;
433 var m;
434
435 // copy the reference
436 if (alias) {
437 if (! this.anchors[alias]) return this.error("Parse error - missing alias: "+alias);
438 node = this.anchors[alias];
439
440 // new key based array
441 } else if (m = this.inline.match('^\\{\\s*')) {
442 this.inline = this.inline.substring(m[0].length);
443 node = new Array ();
444 while (! (m = this.inline.match('^\\}'))) {
445 var key = this.parse_inline();
446 if (! (m = this.inline.match('^:\\s+'))) return this.error("Parse error - bad map element "+this.inline);
447 this.inline = this.inline.substring(m[0].length);
448 var value = this.parse_inline();
449 if (node[key]) this.warn("Warn - duplicate key found: "+key);
450 else node[key] = value;
451 if (this.inline.match('^\\}')) break;
452 if (! (m = this.inline.match('^,\\s*'))) return this.error("Parse error - missing map comma "+this.inline);
453 this.inline = this.inline.substring(m[0].length);
454 }
455 this.inline = this.inline.substring(m[0].length);
456
457 // new array
458 } else if (m = this.inline.match('^\\[\\s*')) {
459 this.inline = this.inline.substring(m[0].length);
460 node = new Array ();
461 while (! (m = this.inline.match('^\\]'))) {
462 node.push(this.parse_inline());
463 if (m = this.inline.match('^\\]')) break;
464 if (! (m = this.inline.match('^,\\s*'))) return this.error("Parse error - missing seq comma "+this.inline);
465 this.inline = this.inline.substring(m[0].length);
466 }
467 this.inline = this.inline.substring(m[0].length);
468
469 // double quoted
470 } else if (this.inline.match('^"')) {
471 if (m = this.inline.match('^"((?:"|[^"])*)"\\s*(.*)$')) {
472 this.inline = m[2];
473 m[1] = m[1].replace(new RegExp('\\\\"','g'),'"');
474 node = m[1];
475 } else {
476 return this.error("Bad double quote "+this.inline);
477 }
478 node = unescape(node); // built in
479 if (implicit || top_implicit) node = this.parse_implicit(node);
480
481 // single quoted
482 } else if (this.inline.match("^'")) {
483 if (m = this.inline.match("^'((?:''|[^'])*)'\\s*(.*)$")) {
484 this.inline = m[2];
485 m[1] = m[1].replace(new RegExp("''",'g'),"'");
486 node = m[1];
487 } else {
488 return this.error("Bad single quote "+this.inline);
489 }
490 node = unescape(node); // built in
491 if (implicit || top_implicit) node = this.parse_implicit(node);
492
493 // simple
494 } else {
495 if (top) {
496 node = this.inline;
497 this.inline = '';
498 } else {
499 if (m = this.inline.match('^([^!@#%^&*,\\[\\]{}\\:]*)')) {
500 this.inline = this.inline.substring(m[1].length);
501 node = m[1];
502 } else {
503 return this.error ("Bad simple match "+this.inline);
504 }
505 if (! explicit && ! top_explicit) node = this.parse_implicit(node);
506 }
507 }
508 if (explicit || top_explicit) {
509 if (! explicit) explicit = top_explicit;
510 if (yclass) return this.error("Parse error - classes not supported");
511 else node = this.parse_explicit(node, explicit);
512 }
513
514 if (anchor) this.anchors[anchor] = node;
515
516 return node;
517 }
518
519 document.yaml_load = function (text, anchors) {
520 var yaml = new YAML();
521 return yaml.parse(text, anchors);
522 }
523
524 document.js_dump = function (obj, name) {
525 var t = '';
526 if (! name) {
527 name = '[obj]';
528 t = 'Dump:\n'
529 }
530 if (typeof(obj) == 'function') return name+'=[FUNCTION]\n'
531 if (typeof(obj) != 'object') return name+'='+obj+'\n';
532 var hold = new Array();
533 for (var i in obj) hold[hold.length] = i;
534 hold = hold.sort();
535 for (var i = 0; i < hold.length; i++) {
536 var n = hold[i];
537 t += document.js_dump(obj[n], name +'.'+n);
538 }
539 return t;
540 }
541
542 // the end
This page took 0.069556 seconds and 4 git commands to generate.