UNPKG

phpjs

Version:

php.js offers community built php functions in javascript

478 lines (406 loc) 16.1 kB
<!-- Generated by Rakefile:build --> <strong> <a href="http://brett-zamir.me" rel="nofollow">Brett Zamir</a> </strong> on 2010-04-11 23:30:40 <br /> When I said just now that my own patching does not validate, I didn't mean it is invalid code, but merely that it doesn't do checking of the validity of the diff supplied to it. <hr /> <strong> <a href="http://brett-zamir.me" rel="nofollow">Brett Zamir</a> </strong> on 2010-04-11 23:29:50 <br /> Hi, My own patching code does not validate. If you want some code that does, the following may work. It is based on code by Imgen Tata, though I have reformatted them to work as self-contained functions in the spirit of php.js (if combined, they could replace xdiff_string_patch): <pre><code>/* * Patches original text to generate new text * @author Imgen Tata (http://www.myipdf.com/) * @see http://en.wikipedia.org/wiki/Diff#Unified_format * @param {String} ori_text The original text * @param {String} unidiff_patch The patch in unidiff format. will be validated. * @returns {String} The generated new text * @see Unified diff format on http://en.wikipedia.org/wiki/Diff#Unified_format */ function string_unidiff_patch (ori_text, unidiff_patch) { var HEADER_PREFIX = '@@ ', HEADER_SUFFIX = ' @@', ORIGINAL_INDICATOR = '-', NEW_INDICATOR = '+', RANGE_SEPARATOR = ',', CONTEXT_INDICATOR = ' ', DELETION_INDICATOR = '-', ADDITION_INDICATOR = '+', ori_lines, patch_lines, patch_line, new_lines = [], NEW_LINE = '\n', line_index = 0, last_line_index = 0, ori_hunk_start = 0, ori_hunk_size = 0, new_hunk_start = 0, new_hunk_size = 0, context_size = 0, deletion_size = 0, addition_size = 0, i, j, one_or_more_whitespace = '\\s*', number_extractor = '(\\d+)', //Construct the range extractor regular expression string range_extractor_reg_exp_str = HEADER_PREFIX + one_or_more_whitespace + ORIGINAL_INDICATOR + one_or_more_whitespace + number_extractor + RANGE_SEPARATOR + one_or_more_whitespace + number_extractor + one_or_more_whitespace + '\\' + NEW_INDICATOR + number_extractor + RANGE_SEPARATOR + one_or_more_whitespace + number_extractor + one_or_more_whitespace + HEADER_SUFFIX, range_extractor = new RegExp(range_extractor_reg_exp_str), ranges, ori_len, first_char, /* *Trims string */ trim = function(text) { if (typeof text != 'string') { throw Error('String parameter required'); } return text.replace(/(^\s*)|(\s*$)/g, ''); }, /* *Verifies type of arguments */ verify_type = function(type) { var args = arguments, args_len = arguments.length, basic_types = ['number', 'boolean', 'string', 'function', 'object', 'undefined'], basic_type, i, j, type_of_type = typeof type; if (type_of_type != 'string' &amp;&amp; type_of_type != 'function') { throw new Error('Bad type parameter'); } if (args_len &lt; 2) { throw new Error('Too few arguments'); } if (type_of_type == 'string') { type = trim(type); if (type == '') { throw new Error('Bad type parameter'); } for (j = 0; j &lt; basic_types.length; j++) { basic_type = basic_types[j]; if (basic_type == type) { for (i = 1; i &lt; args_len; i++) { if (typeof args[i] != type) { throw new Error('Bad type'); } } return; } } throw new Error('Bad type parameter'); } //Not basic type. we need to use instanceof operator for (i = 1; i &lt; args_len; i++) { if (!(args[i] instanceof type)) { throw new Error('Bad type'); } } }, /* *Splits text into lines and return as a string array */ split_into_lines = function(text) { verify_type('string', text); if (text == '') { return []; } return text.split('\n'); }, patch_hunk_header_validator = function( context_size, ori_hunk_size, delection_size, new_hunk_size, addition_size) { if (ori_hunk_size != (context_size + deletion_size) || new_hunk_size != (context_size + addition_size) ) { throw 'invalid patch header'; } }; verify_type('string', ori_text); verify_type('string', unidiff_patch); ori_lines = split_into_lines(ori_text); ori_len = ori_lines.length; patch_lines = split_into_lines(unidiff_patch); for (i = 0; i &lt; patch_lines.length; i++) { patch_line = patch_lines[i]; if (patch_line === '') {//Skip empty line continue; } if (patch_line.indexOf(HEADER_PREFIX) != -1) {//A diff hunk header found //validate the previous patch header patch_hunk_header_validator(context_size, ori_hunk_size, deletion_size, new_hunk_size, addition_size); ranges = patch_line.match(range_extractor); if (ranges === null) { throw 'invalid patch header'; } ori_hunk_start = ranges[1]; ori_hunk_size = ranges[2]; new_hunk_start = ranges[3]; new_hunk_size = ranges[4]; last_line_index = line_index; line_index = Math.max( ori_hunk_start - 1, 0); if(ori_len &gt; 0){ //Validate line index if (last_line_index &gt; line_index || line_index &gt; ori_len) { throw 'invalid patch header'; } for (j = last_line_index; j &lt; line_index; j++) { new_lines.push(ori_lines[j]); } } //validate new hunk start index if (new_hunk_start &gt; 0 &amp;&amp; new_hunk_start != new_lines.length + 1) { throw 'invalid patch header'; } //Reset sizes context_size = 0; deletion_size = 0; addition_size = 0; continue; } first_char = patch_line.charAt(0); switch (first_char) { case CONTEXT_INDICATOR: new_lines.push(ori_lines[line_index]); line_index++; context_size++; break; case DELETION_INDICATOR: line_index++; deletion_size++; break; case ADDITION_INDICATOR: new_lines.push(patch_line.substr(1)); addition_size++; break; default: throw 'Unrecognized initial character in unidiff line'; } } //Validate the last patch header patch_hunk_header_validator(context_size, ori_hunk_size, deletion_size, new_hunk_size, addition_size); //Append the remaining lines while (line_index &lt; ori_len) { new_lines.push(ori_lines[line_index]); line_index++; } return new_lines.join(NEW_LINE); } /* * Reverse patches original text to generate new text * @author Imgen Tata (http://www.myipdf.com/) * @see http://en.wikipedia.org/wiki/Diff#Unified_format * @param {String} new_text The new text * @param {String} unidiff_patch The patch in unidiff format. Will be validated. * @returns {String} The generated original text * @see Unified diff format on http://en.wikipedia.org/wiki/Diff#Unified_format */ function string_unidiff_reverse_patch (new_text, unidiff_patch) { var HEADER_PREFIX = '@@ ', HEADER_SUFFIX = ' @@', ORIGINAL_INDICATOR = '-', NEW_INDICATOR = '+', RANGE_SEPARATOR = ',', CONTEXT_INDICATOR = ' ', DELETION_INDICATOR = '-', ADDITION_INDICATOR = '+', new_lines, NEW_LINE = '\n', patch_lines, patch_line, ori_lines = [], line_index = 0, last_line_index = 0, ori_hunk_start = 0, ori_hunk_size = 0, new_hunk_start = 0, new_hunk_size = 0, context_size = 0, deletion_size = 0, addition_size = 0, i, j, one_or_more_whitespace = '\\s*', number_extractor = '(\\d+)', //Construct the range extractor regular expression string range_extractor_reg_exp_str = HEADER_PREFIX + one_or_more_whitespace + ORIGINAL_INDICATOR + one_or_more_whitespace + number_extractor + RANGE_SEPARATOR + one_or_more_whitespace + number_extractor + one_or_more_whitespace + '\\' + NEW_INDICATOR + number_extractor + RANGE_SEPARATOR + one_or_more_whitespace + number_extractor + one_or_more_whitespace + HEADER_SUFFIX, range_extractor = new RegExp(range_extractor_reg_exp_str), ranges, new_len, first_char, /* *Trims string */ trim = function(text) { if (typeof text != 'string') { throw Error('String parameter required'); } return text.replace(/(^\s*)|(\s*$)/g, ''); }, /* *Verifies type of arguments */ verify_type = function(type) { var args = arguments, args_len = arguments.length, basic_types = ['number', 'boolean', 'string', 'function', 'object', 'undefined'], basic_type, i, j, type_of_type = typeof type; if (type_of_type != 'string' &amp;&amp; type_of_type != 'function') { throw new Error('Bad type parameter'); } if (args_len &lt; 2) { throw new Error('Too few arguments'); } if (type_of_type == 'string') { type = trim(type); if (type == '') { throw new Error('Bad type parameter'); } for (j = 0; j &lt; basic_types.length; j++) { basic_type = basic_types[j]; if (basic_type == type) { for (i = 1; i &lt; args_len; i++) { if (typeof args[i] != type) { throw new Error('Bad type'); } } return; } } throw new Error('Bad type parameter'); } //Not basic type. we need to use instanceof operator for (i = 1; i &lt; args_len; i++) { if (!(args[i] instanceof type)) { throw new Error('Bad type'); } } }, /* *Splits text into lines and return as a string array */ split_into_lines = function(text) { verify_type('string', text); if (text == '') { return []; } return text.split('\n'); }, patch_hunk_header_validator = function( context_size, ori_hunk_size, delection_size, new_hunk_size, addition_size) { if (ori_hunk_size != (context_size + deletion_size) || new_hunk_size != (context_size + addition_size) ) { throw 'invalid patch header'; } }; verify_type('string', new_text); verify_type('string', unidiff_patch); new_lines = split_into_lines(new_text); new_len = new_lines.length; patch_lines = split_into_lines(unidiff_patch); for (i = 0; i &lt; patch_lines.length; i++) { patch_line = patch_lines[i]; if (patch_line === '') {//Skip empty line continue; } if (patch_line.indexOf(HEADER_PREFIX) != -1) {//A diff hunk header found //validate the previous patch header patch_hunk_header_validator(context_size, ori_hunk_size, deletion_size, new_hunk_size, addition_size); ranges = patch_line.match(range_extractor); if (ranges === null) { throw 'invalid patch header'; } ori_hunk_start = ranges[1]; ori_hunk_size = ranges[2]; new_hunk_start = ranges[3]; new_hunk_size = ranges[4]; last_line_index = line_index; line_index = Math.max( new_hunk_start - 1, 0); if(new_len &gt; 0){ //Validate line index if (last_line_index &gt; line_index || line_index &gt; new_len) { throw 'invalid patch header'; } for (j = last_line_index; j &lt; line_index; j++) { ori_lines.push(new_lines[j]); } } //validate original hunk start index if (ori_hunk_start &gt; 0 &amp;&amp; ori_hunk_start != ori_lines.length + 1) { throw 'invalid patch header'; } //Reset sizes context_size = 0; deletion_size = 0; addition_size = 0; continue; } first_char = patch_line.charAt(0); switch (first_char) { case CONTEXT_INDICATOR: ori_lines.push(new_lines[line_index]); line_index++; context_size++; break; case DELETION_INDICATOR: //Put deleted line back ori_lines.push(patch_line.substr(1)); deletion_size++; break; case ADDITION_INDICATOR: line_index++; addition_size++; break; default: throw 'Unrecognized initial character in unidiff line'; } } //Validate the last patch header patch_hunk_header_validator(context_size, ori_hunk_size, deletion_size, new_hunk_size, addition_size); //Append the remaining lines while (line_index &lt; new_len) { ori_lines.push(new_lines[line_index]); line_index++; } return ori_lines.join(NEW_LINE); } </code></pre> <hr />