js-beautify 0.1.7
Sign up to get free protection for your applications and to get access to all the features.
- data/.document +5 -0
- data/.gitmodules +4 -0
- data/Gemfile +13 -0
- data/Gemfile.lock +27 -0
- data/LICENSE.txt +20 -0
- data/README.rdoc +13 -0
- data/Rakefile +29 -0
- data/VERSION +1 -0
- data/bin/js-beautify +5 -0
- data/init.sh +3 -0
- data/js-beautify-copy/.gitmodules +3 -0
- data/js-beautify-copy/Makefile +71 -0
- data/js-beautify-copy/README.md +39 -0
- data/js-beautify-copy/attic/beautify-cl/beautify-cl.js +142 -0
- data/js-beautify-copy/attic/bin/beautify_js +80 -0
- data/js-beautify-copy/attic/opera-userscript/beautifier.js +1087 -0
- data/js-beautify-copy/attic/opera-userscript/make_opera_userscript.sh +42 -0
- data/js-beautify-copy/attic/qtscript/jsbeautify.cpp +121 -0
- data/js-beautify-copy/attic/qtscript/jsbeautify.pro +5 -0
- data/js-beautify-copy/attic/qtscript/jsbeautify.qrc +6 -0
- data/js-beautify-copy/attic/qtscript/readme.txt +28 -0
- data/js-beautify-copy/attic/readme.txt +2 -0
- data/js-beautify-copy/attic/unmaintained/bbedit/jsBeautify_BBED.scpt +522 -0
- data/js-beautify-copy/attic/unmaintained/c-sharp/JSBeautify.cs +801 -0
- data/js-beautify-copy/attic/v8/README.txt +40 -0
- data/js-beautify-copy/attic/v8/beautify.h +2390 -0
- data/js-beautify-copy/attic/v8/jsbeautify.cpp +215 -0
- data/js-beautify-copy/beautify-css.js +198 -0
- data/js-beautify-copy/beautify-html.js +514 -0
- data/js-beautify-copy/beautify.js +1293 -0
- data/js-beautify-copy/favicon.png +0 -0
- data/js-beautify-copy/index.html +401 -0
- data/js-beautify-copy/jquery/jquery.cookie.js +96 -0
- data/js-beautify-copy/jquery/jquery.js +167 -0
- data/js-beautify-copy/license.txt +24 -0
- data/js-beautify-copy/php/jsbeautifier.php +1599 -0
- data/js-beautify-copy/php/test.php +476 -0
- data/js-beautify-copy/python/MANIFEST.in +2 -0
- data/js-beautify-copy/python/js-beautify +7 -0
- data/js-beautify-copy/python/js-beautify-profile +16 -0
- data/js-beautify-copy/python/js-beautify-test +10 -0
- data/js-beautify-copy/python/jsbeautifier/__init__.py +1166 -0
- data/js-beautify-copy/python/jsbeautifier/tests/__init__.py +1 -0
- data/js-beautify-copy/python/jsbeautifier/tests/testindentation.py +43 -0
- data/js-beautify-copy/python/jsbeautifier/tests/testjsbeautifier.py +464 -0
- data/js-beautify-copy/python/jsbeautifier/unpackers/README.specs.mkd +25 -0
- data/js-beautify-copy/python/jsbeautifier/unpackers/__init__.py +67 -0
- data/js-beautify-copy/python/jsbeautifier/unpackers/evalbased.py +39 -0
- data/js-beautify-copy/python/jsbeautifier/unpackers/javascriptobfuscator.py +58 -0
- data/js-beautify-copy/python/jsbeautifier/unpackers/myobfuscate.py +86 -0
- data/js-beautify-copy/python/jsbeautifier/unpackers/packer.py +104 -0
- data/js-beautify-copy/python/jsbeautifier/unpackers/tests/__init__.py +2 -0
- data/js-beautify-copy/python/jsbeautifier/unpackers/tests/test-myobfuscate-input.js +1 -0
- data/js-beautify-copy/python/jsbeautifier/unpackers/tests/test-myobfuscate-output.js +65 -0
- data/js-beautify-copy/python/jsbeautifier/unpackers/tests/test-packer-62-input.js +1 -0
- data/js-beautify-copy/python/jsbeautifier/unpackers/tests/test-packer-non62-input.js +1 -0
- data/js-beautify-copy/python/jsbeautifier/unpackers/tests/testjavascriptobfuscator.py +46 -0
- data/js-beautify-copy/python/jsbeautifier/unpackers/tests/testmyobfuscate.py +40 -0
- data/js-beautify-copy/python/jsbeautifier/unpackers/tests/testpacker.py +34 -0
- data/js-beautify-copy/python/jsbeautifier/unpackers/tests/testurlencode.py +36 -0
- data/js-beautify-copy/python/jsbeautifier/unpackers/urlencode.py +34 -0
- data/js-beautify-copy/python/setup.py +17 -0
- data/js-beautify-copy/tests/beautify-tests.js +489 -0
- data/js-beautify-copy/tests/run-tests +17 -0
- data/js-beautify-copy/tests/sanitytest.js +128 -0
- data/js-beautify-copy/unpackers/javascriptobfuscator_unpacker.js +103 -0
- data/js-beautify-copy/unpackers/myobfuscate_unpacker.js +81 -0
- data/js-beautify-copy/unpackers/p_a_c_k_e_r_unpacker.js +61 -0
- data/js-beautify-copy/unpackers/urlencode_unpacker.js +51 -0
- data/lib/js-beautify.rb +0 -0
- data/test/helper.rb +18 -0
- data/test/test_js-beautify.rb +7 -0
- data/update.sh +23 -0
- metadata +173 -0
@@ -0,0 +1,215 @@
|
|
1
|
+
/*
|
2
|
+
Copyright (c) 2010 Ariya Hidayat <ariya.hidayat@gmail.com>
|
3
|
+
Copyright (c) 2009 Einar Lielmanis
|
4
|
+
Copyright (c) 2010 Nicolas Ferrero <ferrero.nicolas@gmail.com>
|
5
|
+
|
6
|
+
Permission is hereby granted, free of charge, to any person
|
7
|
+
obtaining a copy of this software and associated documentation
|
8
|
+
files (the "Software"), to deal in the Software without
|
9
|
+
restriction, including without limitation the rights to use,
|
10
|
+
copy, modify, merge, publish, distribute, sublicense, and/or sell
|
11
|
+
copies of the Software, and to permit persons to whom the
|
12
|
+
Software is furnished to do so, subject to the following
|
13
|
+
conditions:
|
14
|
+
|
15
|
+
The above copyright notice and this permission notice shall be
|
16
|
+
included in all copies or substantial portions of the Software.
|
17
|
+
|
18
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
19
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
|
20
|
+
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
21
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
22
|
+
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
23
|
+
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
24
|
+
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
25
|
+
OTHER DEALINGS IN THE SOFTWARE.
|
26
|
+
*/
|
27
|
+
|
28
|
+
#include <v8.h>
|
29
|
+
#include <string.h>
|
30
|
+
#include <stdlib.h>
|
31
|
+
#include "beautify.h"
|
32
|
+
|
33
|
+
#define BUF_SIZE 1024
|
34
|
+
|
35
|
+
using namespace v8;
|
36
|
+
|
37
|
+
Handle<String> readFile(const char* name)
|
38
|
+
{
|
39
|
+
FILE *file = stdin;
|
40
|
+
int len = 0;
|
41
|
+
char *buf;
|
42
|
+
Handle<String> result;
|
43
|
+
|
44
|
+
if (name)
|
45
|
+
{
|
46
|
+
file = fopen(name, "rb");
|
47
|
+
|
48
|
+
if (file == NULL)
|
49
|
+
{
|
50
|
+
return Handle<String>();
|
51
|
+
}
|
52
|
+
|
53
|
+
fseek(file, 0, SEEK_END);
|
54
|
+
len = ftell(file);
|
55
|
+
rewind(file);
|
56
|
+
buf = new char[len + 1];
|
57
|
+
buf[len] = '\0';
|
58
|
+
fread(buf, 1, len, file);
|
59
|
+
fclose(file);
|
60
|
+
result = String::New(buf);
|
61
|
+
delete[] buf;
|
62
|
+
}
|
63
|
+
else
|
64
|
+
{
|
65
|
+
char c;
|
66
|
+
buf = (char*)malloc(BUF_SIZE + 1);
|
67
|
+
int buf_size = BUF_SIZE + 1;
|
68
|
+
|
69
|
+
while ((c = getchar()) != EOF)
|
70
|
+
{
|
71
|
+
buf[len++] = c;
|
72
|
+
|
73
|
+
if (len == buf_size)
|
74
|
+
{
|
75
|
+
buf_size <<= 1;
|
76
|
+
buf = (char*)realloc(buf, buf_size);
|
77
|
+
}
|
78
|
+
}
|
79
|
+
|
80
|
+
buf[len] = '\0';
|
81
|
+
result = String::New(buf);
|
82
|
+
free(buf);
|
83
|
+
}
|
84
|
+
|
85
|
+
return result;
|
86
|
+
}
|
87
|
+
|
88
|
+
void writeFile(Handle<Value> result, const char* name)
|
89
|
+
{
|
90
|
+
if (result.IsEmpty() || result->IsUndefined())
|
91
|
+
{
|
92
|
+
return;
|
93
|
+
}
|
94
|
+
|
95
|
+
FILE* file = stdout;
|
96
|
+
|
97
|
+
if (name)
|
98
|
+
{
|
99
|
+
file = fopen(name, "wt");
|
100
|
+
|
101
|
+
if (file == NULL)
|
102
|
+
{
|
103
|
+
return;
|
104
|
+
}
|
105
|
+
}
|
106
|
+
|
107
|
+
String::Utf8Value str(result);
|
108
|
+
fprintf(file, "%s\n", *str);
|
109
|
+
|
110
|
+
if (name)
|
111
|
+
{
|
112
|
+
fclose(file);
|
113
|
+
}
|
114
|
+
}
|
115
|
+
|
116
|
+
static void usage(char* progname)
|
117
|
+
{
|
118
|
+
printf("Usage: %s [options] source-file\n", progname);
|
119
|
+
printf("[options]\n");
|
120
|
+
printf(" --overwrite : Overwrite source-file (use with care!)\n");
|
121
|
+
printf(" --indent-size or -s: Indentation size. (default 4)\n");
|
122
|
+
printf(" --indent-char or -c: Character to indent with. (default space)\n");
|
123
|
+
printf(" --disable-preserve-newlines or -d: Do not preserve existing line breaks.\n");
|
124
|
+
printf(" --indent-level or -l: Initial indentation level, you probably won't need this ever. (default 0)\n");
|
125
|
+
printf(" --space-after-anon-function or -f: Space is added between \"function ()\", otherwise the common \"function()\" output is used.\n");
|
126
|
+
printf(" --braces-on-own-line or -b: ANSI / Allman brace style, each opening/closing brace gets its own line.\n");
|
127
|
+
printf(" --keep-array-indentation or -k: Keep array indentation.\n");
|
128
|
+
printf(" --help or -h: Prints this help statement.\n");
|
129
|
+
}
|
130
|
+
|
131
|
+
int main(int argc, char* argv[])
|
132
|
+
{
|
133
|
+
Handle<String> source;
|
134
|
+
HandleScope handle_scope;
|
135
|
+
Handle<ObjectTemplate> global = ObjectTemplate::New();
|
136
|
+
Handle<ObjectTemplate> options = ObjectTemplate::New();
|
137
|
+
bool overwrite = false;
|
138
|
+
const char* output = 0;
|
139
|
+
|
140
|
+
for (int argpos = 1; argpos < argc; ++argpos)
|
141
|
+
{
|
142
|
+
if (argv[argpos][0] != '-')
|
143
|
+
{
|
144
|
+
source = readFile(argv[argpos]);
|
145
|
+
output = argv[argpos];
|
146
|
+
}
|
147
|
+
else if (strcmp(argv[argpos], "--stdin") == 0)
|
148
|
+
{
|
149
|
+
source = readFile(0);
|
150
|
+
}
|
151
|
+
else if (strcmp(argv[argpos], "--overwrite") == 0)
|
152
|
+
{
|
153
|
+
overwrite = true;
|
154
|
+
}
|
155
|
+
else if (strcmp(argv[argpos], "--indent-size") == 0 ||
|
156
|
+
strcmp(argv[argpos], "-s") == 0)
|
157
|
+
{
|
158
|
+
options->Set("indent_size", String::New(argv[argpos+1]));
|
159
|
+
}
|
160
|
+
else if (strcmp(argv[argpos], "--indent-char") == 0 ||
|
161
|
+
strcmp(argv[argpos], "-c") == 0)
|
162
|
+
{
|
163
|
+
options->Set("indent_char", String::New(argv[argpos+1]));
|
164
|
+
}
|
165
|
+
else if (strcmp(argv[argpos], "--disable-preserve-newlines") == 0 ||
|
166
|
+
strcmp(argv[argpos], "-d") == 0)
|
167
|
+
{
|
168
|
+
options->Set("preserve_newlines", Boolean::New(false));
|
169
|
+
}
|
170
|
+
else if (strcmp(argv[argpos], "--indent-level") == 0 ||
|
171
|
+
strcmp(argv[argpos], "-l") == 0)
|
172
|
+
{
|
173
|
+
options->Set("indent_level", String::New(argv[argpos+1]));
|
174
|
+
}
|
175
|
+
else if (strcmp(argv[argpos], "--space-after-anon-function") == 0 ||
|
176
|
+
strcmp(argv[argpos], "-f") == 0)
|
177
|
+
{
|
178
|
+
options->Set("space_after_anon_function", Boolean::New(true));
|
179
|
+
}
|
180
|
+
else if (strcmp(argv[argpos], "--braces-on-own-line") == 0 ||
|
181
|
+
strcmp(argv[argpos], "-b") == 0)
|
182
|
+
{
|
183
|
+
options->Set("braces_on_own_line", Boolean::New(true));
|
184
|
+
}
|
185
|
+
else if (strcmp(argv[argpos], "--keep-array-indentation") == 0 ||
|
186
|
+
strcmp(argv[argpos], "-k") == 0)
|
187
|
+
{
|
188
|
+
options->Set("keep_array_indentation", Boolean::New(true));
|
189
|
+
}
|
190
|
+
else if (strcmp(argv[argpos], "--help") == 0 ||
|
191
|
+
strcmp(argv[argpos], "-h") == 0)
|
192
|
+
{
|
193
|
+
usage(argv[0]);
|
194
|
+
return -1;
|
195
|
+
}
|
196
|
+
}
|
197
|
+
|
198
|
+
if (source.IsEmpty())
|
199
|
+
{
|
200
|
+
usage(argv[0]);
|
201
|
+
return -1;
|
202
|
+
}
|
203
|
+
|
204
|
+
global->Set("source", source);
|
205
|
+
global->Set("options", options);
|
206
|
+
Handle<Context> context = Context::New(NULL, global);
|
207
|
+
Context::Scope context_scope(context);
|
208
|
+
Handle<Script> beautifyScript = Script::Compile(String::New(beautify_code));
|
209
|
+
beautifyScript->Run();
|
210
|
+
Handle<Script> runnerScript = Script::Compile(String::New("js_beautify(source, options);"));
|
211
|
+
Handle<Value> result = runnerScript->Run();
|
212
|
+
writeFile(result, overwrite ? output : 0);
|
213
|
+
return 0;
|
214
|
+
}
|
215
|
+
|
@@ -0,0 +1,198 @@
|
|
1
|
+
/*
|
2
|
+
|
3
|
+
CSS Beautifier
|
4
|
+
---------------
|
5
|
+
|
6
|
+
Written by Harutyun Amirjanyan, (amirjanyan@gmail.com)
|
7
|
+
|
8
|
+
Based on code initially developed by: Einar Lielmanis, <elfz@laacz.lv>
|
9
|
+
http://jsbeautifier.org/
|
10
|
+
|
11
|
+
|
12
|
+
You are free to use this in any way you want, in case you find this useful or working for you.
|
13
|
+
|
14
|
+
Usage:
|
15
|
+
css_beautify(source_text);
|
16
|
+
css_beautify(source_text, options);
|
17
|
+
|
18
|
+
The options are:
|
19
|
+
indent_size (default 4) — indentation size,
|
20
|
+
indent_char (default space) — character to indent with,
|
21
|
+
|
22
|
+
e.g
|
23
|
+
|
24
|
+
css_beautify(css_source_text, {
|
25
|
+
'indent_size': 1,
|
26
|
+
'indent_char': '\t'
|
27
|
+
});
|
28
|
+
*/
|
29
|
+
|
30
|
+
// http://www.w3.org/TR/CSS21/syndata.html#tokenization
|
31
|
+
// http://www.w3.org/TR/css3-syntax/
|
32
|
+
function css_beautify(source_text, options) {
|
33
|
+
options = options || {};
|
34
|
+
var indentSize = options.indent_size || 4;
|
35
|
+
var indentCharacter = options.indent_char || ' ';
|
36
|
+
|
37
|
+
// compatibility
|
38
|
+
if (typeof indentSize == "string")
|
39
|
+
indentSize = parseInt(indentSize);
|
40
|
+
|
41
|
+
|
42
|
+
// tokenizer
|
43
|
+
var whiteRe = /^\s+$/;
|
44
|
+
var wordRe = /[\w$\-_]/;
|
45
|
+
|
46
|
+
var pos = -1, ch;
|
47
|
+
function next() {
|
48
|
+
return ch = source_text.charAt(++pos)
|
49
|
+
}
|
50
|
+
function peek() {
|
51
|
+
return source_text.charAt(pos+1)
|
52
|
+
}
|
53
|
+
function eatString(comma) {
|
54
|
+
var start = pos;
|
55
|
+
while(next()){
|
56
|
+
if (ch=="\\"){
|
57
|
+
next();
|
58
|
+
next();
|
59
|
+
} else if (ch == comma) {
|
60
|
+
break;
|
61
|
+
} else if (ch == "\n") {
|
62
|
+
break;
|
63
|
+
}
|
64
|
+
}
|
65
|
+
return source_text.substring(start, pos + 1);
|
66
|
+
}
|
67
|
+
|
68
|
+
function eatWhitespace() {
|
69
|
+
var start = pos;
|
70
|
+
while (whiteRe.test(peek()))
|
71
|
+
pos++;
|
72
|
+
return pos != start;
|
73
|
+
}
|
74
|
+
|
75
|
+
function skipWhitespace() {
|
76
|
+
var start = pos;
|
77
|
+
do{
|
78
|
+
}while (whiteRe.test(next()))
|
79
|
+
return pos != start + 1;
|
80
|
+
}
|
81
|
+
|
82
|
+
function eatComment() {
|
83
|
+
var start = pos;
|
84
|
+
next();
|
85
|
+
while (next()) {
|
86
|
+
if (ch == "*" && peek() == "/") {
|
87
|
+
pos ++;
|
88
|
+
break;
|
89
|
+
}
|
90
|
+
}
|
91
|
+
|
92
|
+
return source_text.substring(start, pos + 1);
|
93
|
+
}
|
94
|
+
|
95
|
+
|
96
|
+
function lookBack(str, index) {
|
97
|
+
return output.slice(-str.length + (index||0), index).join("").toLowerCase() == str;
|
98
|
+
}
|
99
|
+
|
100
|
+
// printer
|
101
|
+
var indentString = source_text.match(/^[\r\n]*[\t ]*/)[0];
|
102
|
+
var singleIndent = Array(indentSize + 1).join(indentCharacter);
|
103
|
+
var indentLevel = 0;
|
104
|
+
function indent() {
|
105
|
+
indentLevel++;
|
106
|
+
indentString += singleIndent;
|
107
|
+
}
|
108
|
+
function outdent() {
|
109
|
+
indentLevel--;
|
110
|
+
indentString = indentString.slice(0, -indentSize);
|
111
|
+
}
|
112
|
+
|
113
|
+
print = {}
|
114
|
+
print["{"] = function(ch) {
|
115
|
+
print.singleSpace();
|
116
|
+
output.push(ch);
|
117
|
+
print.newLine();
|
118
|
+
}
|
119
|
+
print["}"] = function(ch) {
|
120
|
+
print.newLine();
|
121
|
+
output.push(ch);
|
122
|
+
print.newLine();
|
123
|
+
}
|
124
|
+
|
125
|
+
print.newLine = function(keepWhitespace) {
|
126
|
+
if (!keepWhitespace)
|
127
|
+
while (whiteRe.test(output[output.length - 1]))
|
128
|
+
output.pop();
|
129
|
+
|
130
|
+
if (output.length)
|
131
|
+
output.push('\n');
|
132
|
+
if (indentString)
|
133
|
+
output.push(indentString);
|
134
|
+
}
|
135
|
+
print.singleSpace = function() {
|
136
|
+
if (output.length && !whiteRe.test(output[output.length - 1]))
|
137
|
+
output.push(' ');
|
138
|
+
}
|
139
|
+
var output = [];
|
140
|
+
if (indentString)
|
141
|
+
output.push(indentString);
|
142
|
+
/*_____________________--------------------_____________________*/
|
143
|
+
|
144
|
+
while(true) {
|
145
|
+
var isAfterSpace = skipWhitespace();
|
146
|
+
|
147
|
+
if (!ch)
|
148
|
+
break;
|
149
|
+
|
150
|
+
if (ch == '{') {
|
151
|
+
indent();
|
152
|
+
print["{"](ch);
|
153
|
+
} else if (ch == '}') {
|
154
|
+
outdent();
|
155
|
+
print["}"](ch);
|
156
|
+
} else if (ch == '"' || ch == '\'') {
|
157
|
+
output.push(eatString(ch))
|
158
|
+
} else if (ch == ';') {
|
159
|
+
output.push(ch, '\n', indentString);
|
160
|
+
} else if (ch == '/' && peek() == '*') { // comment
|
161
|
+
print.newLine();
|
162
|
+
output.push(eatComment(), "\n", indentString);
|
163
|
+
} else if (ch == '(') { // may be a url
|
164
|
+
output.push(ch);
|
165
|
+
eatWhitespace();
|
166
|
+
if (lookBack("url", -1) && next()) {
|
167
|
+
if (ch != ')' && ch != '"' && ch != '\'')
|
168
|
+
output.push(eatString(')'));
|
169
|
+
else
|
170
|
+
pos--;
|
171
|
+
}
|
172
|
+
} else if (ch == ')') {
|
173
|
+
output.push(ch);
|
174
|
+
} else if (ch == ',') {
|
175
|
+
eatWhitespace();
|
176
|
+
output.push(ch);
|
177
|
+
print.singleSpace();
|
178
|
+
} else if (ch == ']') {
|
179
|
+
output.push(ch);
|
180
|
+
} else if (ch == '[' || ch == '=') { // no whitespace before or after
|
181
|
+
eatWhitespace();
|
182
|
+
output.push(ch);
|
183
|
+
} else {
|
184
|
+
if (isAfterSpace)
|
185
|
+
print.singleSpace();
|
186
|
+
|
187
|
+
output.push(ch);
|
188
|
+
}
|
189
|
+
}
|
190
|
+
|
191
|
+
|
192
|
+
var sweetCode = output.join('').replace(/[\n ]+$/, '');
|
193
|
+
return sweetCode;
|
194
|
+
}
|
195
|
+
|
196
|
+
|
197
|
+
if (typeof exports !== "undefined")
|
198
|
+
exports.css_beautify = css_beautify;
|
@@ -0,0 +1,514 @@
|
|
1
|
+
/*
|
2
|
+
|
3
|
+
Style HTML
|
4
|
+
---------------
|
5
|
+
|
6
|
+
Written by Nochum Sossonko, (nsossonko@hotmail.com)
|
7
|
+
|
8
|
+
Based on code initially developed by: Einar Lielmanis, <elfz@laacz.lv>
|
9
|
+
http://jsbeautifier.org/
|
10
|
+
|
11
|
+
|
12
|
+
You are free to use this in any way you want, in case you find this useful or working for you.
|
13
|
+
|
14
|
+
Usage:
|
15
|
+
style_html(html_source);
|
16
|
+
|
17
|
+
style_html(html_source, options);
|
18
|
+
|
19
|
+
The options are:
|
20
|
+
indent_size (default 4) — indentation size,
|
21
|
+
indent_char (default space) — character to indent with,
|
22
|
+
max_char (default 70) - maximum amount of characters per line,
|
23
|
+
brace_style (default "collapse") - "collapse" | "expand" | "end-expand"
|
24
|
+
put braces on the same line as control statements (default), or put braces on own line (Allman / ANSI style), or just put end braces on own line.
|
25
|
+
unformatted (default ['a']) - list of tags, that shouldn't be reformatted
|
26
|
+
indent_scripts (default normal) - "keep"|"separate"|"normal"
|
27
|
+
|
28
|
+
e.g.
|
29
|
+
|
30
|
+
style_html(html_source, {
|
31
|
+
'indent_size': 2,
|
32
|
+
'indent_char': ' ',
|
33
|
+
'max_char': 78,
|
34
|
+
'brace_style': 'expand',
|
35
|
+
'unformatted': ['a', 'sub', 'sup', 'b', 'i', 'u']
|
36
|
+
});
|
37
|
+
*/
|
38
|
+
|
39
|
+
function style_html(html_source, options) {
|
40
|
+
//Wrapper function to invoke all the necessary constructors and deal with the output.
|
41
|
+
|
42
|
+
var multi_parser,
|
43
|
+
indent_size,
|
44
|
+
indent_character,
|
45
|
+
max_char,
|
46
|
+
brace_style;
|
47
|
+
|
48
|
+
options = options || {};
|
49
|
+
indent_size = options.indent_size || 4;
|
50
|
+
indent_character = options.indent_char || ' ';
|
51
|
+
brace_style = options.brace_style || 'collapse';
|
52
|
+
max_char = options.max_char == 0 ? Infinity : options.max_char || 70;
|
53
|
+
unformatted = options.unformatted || ['a'];
|
54
|
+
|
55
|
+
function Parser() {
|
56
|
+
|
57
|
+
this.pos = 0; //Parser position
|
58
|
+
this.token = '';
|
59
|
+
this.current_mode = 'CONTENT'; //reflects the current Parser mode: TAG/CONTENT
|
60
|
+
this.tags = { //An object to hold tags, their position, and their parent-tags, initiated with default values
|
61
|
+
parent: 'parent1',
|
62
|
+
parentcount: 1,
|
63
|
+
parent1: ''
|
64
|
+
};
|
65
|
+
this.tag_type = '';
|
66
|
+
this.token_text = this.last_token = this.last_text = this.token_type = '';
|
67
|
+
|
68
|
+
this.Utils = { //Uilities made available to the various functions
|
69
|
+
whitespace: "\n\r\t ".split(''),
|
70
|
+
single_token: 'br,input,link,meta,!doctype,basefont,base,area,hr,wbr,param,img,isindex,?xml,embed'.split(','), //all the single tags for HTML
|
71
|
+
extra_liners: 'head,body,/html'.split(','), //for tags that need a line of whitespace before them
|
72
|
+
in_array: function (what, arr) {
|
73
|
+
for (var i=0; i<arr.length; i++) {
|
74
|
+
if (what === arr[i]) {
|
75
|
+
return true;
|
76
|
+
}
|
77
|
+
}
|
78
|
+
return false;
|
79
|
+
}
|
80
|
+
}
|
81
|
+
|
82
|
+
this.get_content = function () { //function to capture regular content between tags
|
83
|
+
|
84
|
+
var input_char = '';
|
85
|
+
var content = [];
|
86
|
+
var space = false; //if a space is needed
|
87
|
+
while (this.input.charAt(this.pos) !== '<') {
|
88
|
+
if (this.pos >= this.input.length) {
|
89
|
+
return content.length?content.join(''):['', 'TK_EOF'];
|
90
|
+
}
|
91
|
+
|
92
|
+
input_char = this.input.charAt(this.pos);
|
93
|
+
this.pos++;
|
94
|
+
this.line_char_count++;
|
95
|
+
|
96
|
+
if (this.Utils.in_array(input_char, this.Utils.whitespace)) {
|
97
|
+
if (content.length) {
|
98
|
+
space = true;
|
99
|
+
}
|
100
|
+
this.line_char_count--;
|
101
|
+
continue; //don't want to insert unnecessary space
|
102
|
+
}
|
103
|
+
else if (space) {
|
104
|
+
if (this.line_char_count >= this.max_char) { //insert a line when the max_char is reached
|
105
|
+
content.push('\n');
|
106
|
+
for (var i=0; i<this.indent_level; i++) {
|
107
|
+
content.push(this.indent_string);
|
108
|
+
}
|
109
|
+
this.line_char_count = 0;
|
110
|
+
}
|
111
|
+
else{
|
112
|
+
content.push(' ');
|
113
|
+
this.line_char_count++;
|
114
|
+
}
|
115
|
+
space = false;
|
116
|
+
}
|
117
|
+
content.push(input_char); //letter at-a-time (or string) inserted to an array
|
118
|
+
}
|
119
|
+
return content.length?content.join(''):'';
|
120
|
+
}
|
121
|
+
|
122
|
+
this.get_contents_to = function (name) { //get the full content of a script or style to pass to js_beautify
|
123
|
+
if (this.pos == this.input.length) {
|
124
|
+
return ['', 'TK_EOF'];
|
125
|
+
}
|
126
|
+
var input_char = '';
|
127
|
+
var content = '';
|
128
|
+
var reg_match = new RegExp('\<\/' + name + '\\s*\>', 'igm');
|
129
|
+
reg_match.lastIndex = this.pos;
|
130
|
+
var reg_array = reg_match.exec(this.input);
|
131
|
+
var end_script = reg_array?reg_array.index:this.input.length; //absolute end of script
|
132
|
+
if(this.pos < end_script) { //get everything in between the script tags
|
133
|
+
content = this.input.substring(this.pos, end_script);
|
134
|
+
this.pos = end_script;
|
135
|
+
}
|
136
|
+
return content;
|
137
|
+
}
|
138
|
+
|
139
|
+
this.record_tag = function (tag){ //function to record a tag and its parent in this.tags Object
|
140
|
+
if (this.tags[tag + 'count']) { //check for the existence of this tag type
|
141
|
+
this.tags[tag + 'count']++;
|
142
|
+
this.tags[tag + this.tags[tag + 'count']] = this.indent_level; //and record the present indent level
|
143
|
+
}
|
144
|
+
else { //otherwise initialize this tag type
|
145
|
+
this.tags[tag + 'count'] = 1;
|
146
|
+
this.tags[tag + this.tags[tag + 'count']] = this.indent_level; //and record the present indent level
|
147
|
+
}
|
148
|
+
this.tags[tag + this.tags[tag + 'count'] + 'parent'] = this.tags.parent; //set the parent (i.e. in the case of a div this.tags.div1parent)
|
149
|
+
this.tags.parent = tag + this.tags[tag + 'count']; //and make this the current parent (i.e. in the case of a div 'div1')
|
150
|
+
}
|
151
|
+
|
152
|
+
this.retrieve_tag = function (tag) { //function to retrieve the opening tag to the corresponding closer
|
153
|
+
if (this.tags[tag + 'count']) { //if the openener is not in the Object we ignore it
|
154
|
+
var temp_parent = this.tags.parent; //check to see if it's a closable tag.
|
155
|
+
while (temp_parent) { //till we reach '' (the initial value);
|
156
|
+
if (tag + this.tags[tag + 'count'] === temp_parent) { //if this is it use it
|
157
|
+
break;
|
158
|
+
}
|
159
|
+
temp_parent = this.tags[temp_parent + 'parent']; //otherwise keep on climbing up the DOM Tree
|
160
|
+
}
|
161
|
+
if (temp_parent) { //if we caught something
|
162
|
+
this.indent_level = this.tags[tag + this.tags[tag + 'count']]; //set the indent_level accordingly
|
163
|
+
this.tags.parent = this.tags[temp_parent + 'parent']; //and set the current parent
|
164
|
+
}
|
165
|
+
delete this.tags[tag + this.tags[tag + 'count'] + 'parent']; //delete the closed tags parent reference...
|
166
|
+
delete this.tags[tag + this.tags[tag + 'count']]; //...and the tag itself
|
167
|
+
if (this.tags[tag + 'count'] == 1) {
|
168
|
+
delete this.tags[tag + 'count'];
|
169
|
+
}
|
170
|
+
else {
|
171
|
+
this.tags[tag + 'count']--;
|
172
|
+
}
|
173
|
+
}
|
174
|
+
}
|
175
|
+
|
176
|
+
this.get_tag = function () { //function to get a full tag and parse its type
|
177
|
+
var input_char = '';
|
178
|
+
var content = [];
|
179
|
+
var space = false;
|
180
|
+
|
181
|
+
do {
|
182
|
+
if (this.pos >= this.input.length) {
|
183
|
+
return content.length?content.join(''):['', 'TK_EOF'];
|
184
|
+
}
|
185
|
+
|
186
|
+
input_char = this.input.charAt(this.pos);
|
187
|
+
this.pos++;
|
188
|
+
this.line_char_count++;
|
189
|
+
|
190
|
+
if (this.Utils.in_array(input_char, this.Utils.whitespace)) { //don't want to insert unnecessary space
|
191
|
+
space = true;
|
192
|
+
this.line_char_count--;
|
193
|
+
continue;
|
194
|
+
}
|
195
|
+
|
196
|
+
if (input_char === "'" || input_char === '"') {
|
197
|
+
if (!content[1] || content[1] !== '!') { //if we're in a comment strings don't get treated specially
|
198
|
+
input_char += this.get_unformatted(input_char);
|
199
|
+
space = true;
|
200
|
+
}
|
201
|
+
}
|
202
|
+
|
203
|
+
if (input_char === '=') { //no space before =
|
204
|
+
space = false;
|
205
|
+
}
|
206
|
+
|
207
|
+
if (content.length && content[content.length-1] !== '=' && input_char !== '>'
|
208
|
+
&& space) { //no space after = or before >
|
209
|
+
if (this.line_char_count >= this.max_char) {
|
210
|
+
this.print_newline(false, content);
|
211
|
+
this.line_char_count = 0;
|
212
|
+
}
|
213
|
+
else {
|
214
|
+
content.push(' ');
|
215
|
+
this.line_char_count++;
|
216
|
+
}
|
217
|
+
space = false;
|
218
|
+
}
|
219
|
+
content.push(input_char); //inserts character at-a-time (or string)
|
220
|
+
} while (input_char !== '>');
|
221
|
+
|
222
|
+
var tag_complete = content.join('');
|
223
|
+
var tag_index;
|
224
|
+
if (tag_complete.indexOf(' ') != -1) { //if there's whitespace, thats where the tag name ends
|
225
|
+
tag_index = tag_complete.indexOf(' ');
|
226
|
+
}
|
227
|
+
else { //otherwise go with the tag ending
|
228
|
+
tag_index = tag_complete.indexOf('>');
|
229
|
+
}
|
230
|
+
var tag_check = tag_complete.substring(1, tag_index).toLowerCase();
|
231
|
+
if (tag_complete.charAt(tag_complete.length-2) === '/' ||
|
232
|
+
this.Utils.in_array(tag_check, this.Utils.single_token)) { //if this tag name is a single tag type (either in the list or has a closing /)
|
233
|
+
this.tag_type = 'SINGLE';
|
234
|
+
}
|
235
|
+
else if (tag_check === 'script') { //for later script handling
|
236
|
+
this.record_tag(tag_check);
|
237
|
+
this.tag_type = 'SCRIPT';
|
238
|
+
}
|
239
|
+
else if (tag_check === 'style') { //for future style handling (for now it justs uses get_content)
|
240
|
+
this.record_tag(tag_check);
|
241
|
+
this.tag_type = 'STYLE';
|
242
|
+
}
|
243
|
+
else if (this.Utils.in_array(tag_check, unformatted)) { // do not reformat the "unformatted" tags
|
244
|
+
var comment = this.get_unformatted('</'+tag_check+'>', tag_complete); //...delegate to get_unformatted function
|
245
|
+
content.push(comment);
|
246
|
+
this.tag_type = 'SINGLE';
|
247
|
+
}
|
248
|
+
else if (tag_check.charAt(0) === '!') { //peek for <!-- comment
|
249
|
+
if (tag_check.indexOf('[if') != -1) { //peek for <!--[if conditional comment
|
250
|
+
if (tag_complete.indexOf('!IE') != -1) { //this type needs a closing --> so...
|
251
|
+
var comment = this.get_unformatted('-->', tag_complete); //...delegate to get_unformatted
|
252
|
+
content.push(comment);
|
253
|
+
}
|
254
|
+
this.tag_type = 'START';
|
255
|
+
}
|
256
|
+
else if (tag_check.indexOf('[endif') != -1) {//peek for <!--[endif end conditional comment
|
257
|
+
this.tag_type = 'END';
|
258
|
+
this.unindent();
|
259
|
+
}
|
260
|
+
else if (tag_check.indexOf('[cdata[') != -1) { //if it's a <[cdata[ comment...
|
261
|
+
var comment = this.get_unformatted(']]>', tag_complete); //...delegate to get_unformatted function
|
262
|
+
content.push(comment);
|
263
|
+
this.tag_type = 'SINGLE'; //<![CDATA[ comments are treated like single tags
|
264
|
+
}
|
265
|
+
else {
|
266
|
+
var comment = this.get_unformatted('-->', tag_complete);
|
267
|
+
content.push(comment);
|
268
|
+
this.tag_type = 'SINGLE';
|
269
|
+
}
|
270
|
+
}
|
271
|
+
else {
|
272
|
+
if (tag_check.charAt(0) === '/') { //this tag is a double tag so check for tag-ending
|
273
|
+
this.retrieve_tag(tag_check.substring(1)); //remove it and all ancestors
|
274
|
+
this.tag_type = 'END';
|
275
|
+
}
|
276
|
+
else { //otherwise it's a start-tag
|
277
|
+
this.record_tag(tag_check); //push it on the tag stack
|
278
|
+
this.tag_type = 'START';
|
279
|
+
}
|
280
|
+
if (this.Utils.in_array(tag_check, this.Utils.extra_liners)) { //check if this double needs an extra line
|
281
|
+
this.print_newline(true, this.output);
|
282
|
+
}
|
283
|
+
}
|
284
|
+
return content.join(''); //returns fully formatted tag
|
285
|
+
}
|
286
|
+
|
287
|
+
this.get_unformatted = function (delimiter, orig_tag) { //function to return unformatted content in its entirety
|
288
|
+
|
289
|
+
if (orig_tag && orig_tag.indexOf(delimiter) != -1) {
|
290
|
+
return '';
|
291
|
+
}
|
292
|
+
var input_char = '';
|
293
|
+
var content = '';
|
294
|
+
var space = true;
|
295
|
+
do {
|
296
|
+
|
297
|
+
if (this.pos >= this.input.length) {
|
298
|
+
return content;
|
299
|
+
}
|
300
|
+
|
301
|
+
input_char = this.input.charAt(this.pos);
|
302
|
+
this.pos++
|
303
|
+
|
304
|
+
if (this.Utils.in_array(input_char, this.Utils.whitespace)) {
|
305
|
+
if (!space) {
|
306
|
+
this.line_char_count--;
|
307
|
+
continue;
|
308
|
+
}
|
309
|
+
if (input_char === '\n' || input_char === '\r') {
|
310
|
+
content += '\n';
|
311
|
+
/* Don't change tab indention for unformatted blocks. If using code for html editing, this will greatly affect <pre> tags if they are specified in the 'unformatted array'
|
312
|
+
for (var i=0; i<this.indent_level; i++) {
|
313
|
+
content += this.indent_string;
|
314
|
+
}
|
315
|
+
space = false; //...and make sure other indentation is erased
|
316
|
+
*/
|
317
|
+
this.line_char_count = 0;
|
318
|
+
continue;
|
319
|
+
}
|
320
|
+
}
|
321
|
+
content += input_char;
|
322
|
+
this.line_char_count++;
|
323
|
+
space = true;
|
324
|
+
|
325
|
+
|
326
|
+
} while (content.indexOf(delimiter) == -1);
|
327
|
+
return content;
|
328
|
+
}
|
329
|
+
|
330
|
+
this.get_token = function () { //initial handler for token-retrieval
|
331
|
+
var token;
|
332
|
+
|
333
|
+
if (this.last_token === 'TK_TAG_SCRIPT' || this.last_token === 'TK_TAG_STYLE') { //check if we need to format javascript
|
334
|
+
var type = this.last_token.substr(7)
|
335
|
+
token = this.get_contents_to(type);
|
336
|
+
if (typeof token !== 'string') {
|
337
|
+
return token;
|
338
|
+
}
|
339
|
+
return [token, 'TK_' + type];
|
340
|
+
}
|
341
|
+
if (this.current_mode === 'CONTENT') {
|
342
|
+
token = this.get_content();
|
343
|
+
if (typeof token !== 'string') {
|
344
|
+
return token;
|
345
|
+
}
|
346
|
+
else {
|
347
|
+
return [token, 'TK_CONTENT'];
|
348
|
+
}
|
349
|
+
}
|
350
|
+
|
351
|
+
if (this.current_mode === 'TAG') {
|
352
|
+
token = this.get_tag();
|
353
|
+
if (typeof token !== 'string') {
|
354
|
+
return token;
|
355
|
+
}
|
356
|
+
else {
|
357
|
+
var tag_name_type = 'TK_TAG_' + this.tag_type;
|
358
|
+
return [token, tag_name_type];
|
359
|
+
}
|
360
|
+
}
|
361
|
+
}
|
362
|
+
|
363
|
+
this.get_full_indent = function (level) {
|
364
|
+
level = this.indent_level + level || 0;
|
365
|
+
if (level < 1)
|
366
|
+
return '';
|
367
|
+
|
368
|
+
return Array(level + 1).join(this.indent_string);
|
369
|
+
}
|
370
|
+
|
371
|
+
|
372
|
+
this.printer = function (js_source, indent_character, indent_size, max_char, brace_style) { //handles input/output and some other printing functions
|
373
|
+
|
374
|
+
this.input = js_source || ''; //gets the input for the Parser
|
375
|
+
this.output = [];
|
376
|
+
this.indent_character = indent_character;
|
377
|
+
this.indent_string = '';
|
378
|
+
this.indent_size = indent_size;
|
379
|
+
this.brace_style = brace_style;
|
380
|
+
this.indent_level = 0;
|
381
|
+
this.max_char = max_char;
|
382
|
+
this.line_char_count = 0; //count to see if max_char was exceeded
|
383
|
+
|
384
|
+
for (var i=0; i<this.indent_size; i++) {
|
385
|
+
this.indent_string += this.indent_character;
|
386
|
+
}
|
387
|
+
|
388
|
+
this.print_newline = function (ignore, arr) {
|
389
|
+
this.line_char_count = 0;
|
390
|
+
if (!arr || !arr.length) {
|
391
|
+
return;
|
392
|
+
}
|
393
|
+
if (!ignore) { //we might want the extra line
|
394
|
+
while (this.Utils.in_array(arr[arr.length-1], this.Utils.whitespace)) {
|
395
|
+
arr.pop();
|
396
|
+
}
|
397
|
+
}
|
398
|
+
arr.push('\n');
|
399
|
+
for (var i=0; i<this.indent_level; i++) {
|
400
|
+
arr.push(this.indent_string);
|
401
|
+
}
|
402
|
+
}
|
403
|
+
|
404
|
+
this.print_token = function (text) {
|
405
|
+
this.output.push(text);
|
406
|
+
}
|
407
|
+
|
408
|
+
this.indent = function () {
|
409
|
+
this.indent_level++;
|
410
|
+
}
|
411
|
+
|
412
|
+
this.unindent = function () {
|
413
|
+
if (this.indent_level > 0) {
|
414
|
+
this.indent_level--;
|
415
|
+
}
|
416
|
+
}
|
417
|
+
}
|
418
|
+
return this;
|
419
|
+
}
|
420
|
+
|
421
|
+
/*_____________________--------------------_____________________*/
|
422
|
+
|
423
|
+
multi_parser = new Parser(); //wrapping functions Parser
|
424
|
+
multi_parser.printer(html_source, indent_character, indent_size, max_char, brace_style); //initialize starting values
|
425
|
+
|
426
|
+
while (true) {
|
427
|
+
var t = multi_parser.get_token();
|
428
|
+
multi_parser.token_text = t[0];
|
429
|
+
multi_parser.token_type = t[1];
|
430
|
+
|
431
|
+
if (multi_parser.token_type === 'TK_EOF') {
|
432
|
+
break;
|
433
|
+
}
|
434
|
+
|
435
|
+
switch (multi_parser.token_type) {
|
436
|
+
case 'TK_TAG_START':
|
437
|
+
multi_parser.print_newline(false, multi_parser.output);
|
438
|
+
multi_parser.print_token(multi_parser.token_text);
|
439
|
+
multi_parser.indent();
|
440
|
+
multi_parser.current_mode = 'CONTENT';
|
441
|
+
break;
|
442
|
+
case 'TK_TAG_STYLE':
|
443
|
+
case 'TK_TAG_SCRIPT':
|
444
|
+
multi_parser.print_newline(false, multi_parser.output);
|
445
|
+
multi_parser.print_token(multi_parser.token_text);
|
446
|
+
multi_parser.current_mode = 'CONTENT';
|
447
|
+
break;
|
448
|
+
case 'TK_TAG_END':
|
449
|
+
//Print new line only if the tag has no content and has child
|
450
|
+
if (multi_parser.last_token === 'TK_CONTENT' && multi_parser.last_text === '') {
|
451
|
+
var tag_name = multi_parser.token_text.match(/\w+/)[0];
|
452
|
+
var tag_extracted_from_last_output = multi_parser.output[multi_parser.output.length -1].match(/<\s*(\w+)/);
|
453
|
+
if (tag_extracted_from_last_output === null || tag_extracted_from_last_output[1] !== tag_name)
|
454
|
+
multi_parser.print_newline(true, multi_parser.output);
|
455
|
+
}
|
456
|
+
multi_parser.print_token(multi_parser.token_text);
|
457
|
+
multi_parser.current_mode = 'CONTENT';
|
458
|
+
break;
|
459
|
+
case 'TK_TAG_SINGLE':
|
460
|
+
multi_parser.print_newline(false, multi_parser.output);
|
461
|
+
multi_parser.print_token(multi_parser.token_text);
|
462
|
+
multi_parser.current_mode = 'CONTENT';
|
463
|
+
break;
|
464
|
+
case 'TK_CONTENT':
|
465
|
+
if (multi_parser.token_text !== '') {
|
466
|
+
multi_parser.print_token(multi_parser.token_text);
|
467
|
+
}
|
468
|
+
multi_parser.current_mode = 'TAG';
|
469
|
+
break;
|
470
|
+
case 'TK_STYLE':
|
471
|
+
case 'TK_SCRIPT':
|
472
|
+
if (multi_parser.token_text !== '') {
|
473
|
+
multi_parser.output.push('\n');
|
474
|
+
var text = multi_parser.token_text;
|
475
|
+
if (multi_parser.token_type == 'TK_SCRIPT') {
|
476
|
+
var _beautifier = typeof js_beautify == 'function' && js_beautify;
|
477
|
+
} else if (multi_parser.token_type == 'TK_STYLE') {
|
478
|
+
var _beautifier = typeof css_beautify == 'function' && css_beautify;
|
479
|
+
}
|
480
|
+
|
481
|
+
if (options.indent_scripts == "keep") {
|
482
|
+
var script_indent_level = 0;
|
483
|
+
} else if (options.indent_scripts == "separate") {
|
484
|
+
var script_indent_level = -multi_parser.indent_level;
|
485
|
+
} else {
|
486
|
+
var script_indent_level = 1;
|
487
|
+
}
|
488
|
+
|
489
|
+
var indentation = multi_parser.get_full_indent(script_indent_level);
|
490
|
+
if (_beautifier) {
|
491
|
+
// call the Beautifier if avaliable
|
492
|
+
text = _beautifier(text.replace(/^\s*/, indentation), options);
|
493
|
+
} else {
|
494
|
+
// simply indent the string otherwise
|
495
|
+
var white = text.match(/^\s*/)[0];
|
496
|
+
var _level = white.match(/[^\n\r]*$/)[0].split(multi_parser.indent_string).length - 1;
|
497
|
+
var reindent = multi_parser.get_full_indent(script_indent_level -_level);
|
498
|
+
text = text.replace(/^\s*/, indentation)
|
499
|
+
.replace(/\r\n|\r|\n/g, '\n' + reindent)
|
500
|
+
.replace(/\s*$/, '');
|
501
|
+
}
|
502
|
+
if (text) {
|
503
|
+
multi_parser.print_token(text);
|
504
|
+
multi_parser.print_newline(true, multi_parser.output);
|
505
|
+
}
|
506
|
+
}
|
507
|
+
multi_parser.current_mode = 'TAG';
|
508
|
+
break;
|
509
|
+
}
|
510
|
+
multi_parser.last_token = multi_parser.token_type;
|
511
|
+
multi_parser.last_text = multi_parser.token_text;
|
512
|
+
}
|
513
|
+
return multi_parser.output.join('');
|
514
|
+
}
|