1 |
|
2 |
|
3 |
|
4 |
|
5 |
|
6 |
|
7 |
|
8 |
|
9 |
|
10 |
|
11 |
|
12 |
|
13 |
|
14 |
|
15 |
|
16 |
|
17 |
|
18 |
|
19 |
|
20 |
|
21 |
|
22 |
|
23 |
|
24 |
|
25 |
|
26 |
|
27 | (function () {
|
28 | 'use strict';
|
29 |
|
30 | var Syntax, common;
|
31 |
|
32 | common = require('./common');
|
33 | Syntax = common.Syntax;
|
34 |
|
35 | function isDirective(stmt) {
|
36 | var expr;
|
37 | if (stmt.type === Syntax.ExpressionStatement) {
|
38 | expr = stmt.expression;
|
39 | if (expr.type === Syntax.Literal && typeof expr.value === 'string') {
|
40 | return true;
|
41 | }
|
42 | }
|
43 | return false;
|
44 | }
|
45 |
|
46 | function escapeAllowedCharacter(ch, next) {
|
47 | var code = ch.charCodeAt(0), hex = code.toString(16), result = '\\';
|
48 |
|
49 | switch (ch) {
|
50 | case '\b':
|
51 | result += 'b';
|
52 | break;
|
53 | case '\f':
|
54 | result += 'f';
|
55 | break;
|
56 | case '\t':
|
57 | result += 't';
|
58 | break;
|
59 | default:
|
60 | if (code > 0xff) {
|
61 | result += 'u' + '0000'.slice(hex.length) + hex;
|
62 | } else if (ch === '\u0000' && '0123456789'.indexOf(next) < 0) {
|
63 | result += '0';
|
64 | } else if (ch === '\v') {
|
65 | result += 'v';
|
66 | } else {
|
67 | result += 'x' + '00'.slice(hex.length) + hex;
|
68 | }
|
69 | break;
|
70 | }
|
71 |
|
72 | return result;
|
73 | }
|
74 |
|
75 | function escapeDisallowedCharacter(ch) {
|
76 | var result = '\\';
|
77 | switch (ch) {
|
78 | case '\\':
|
79 | result += '\\';
|
80 | break;
|
81 | case '\n':
|
82 | result += 'n';
|
83 | break;
|
84 | case '\r':
|
85 | result += 'r';
|
86 | break;
|
87 | case '\u2028':
|
88 | result += 'u2028';
|
89 | break;
|
90 | case '\u2029':
|
91 | result += 'u2029';
|
92 | break;
|
93 | default:
|
94 | throw new Error('Incorrectly classified character');
|
95 | }
|
96 |
|
97 | return result;
|
98 | }
|
99 |
|
100 | function escapeString(str) {
|
101 | var result = '', i, len, ch;
|
102 |
|
103 | if (typeof str[0] === 'undefined') {
|
104 | str = common.stringToArray(str);
|
105 | }
|
106 |
|
107 | for (i = 0, len = str.length; i < len; i += 1) {
|
108 | ch = str[i];
|
109 | if (ch === '\'') {
|
110 | result += '\\\'';
|
111 | } else if ('\\\n\r\u2028\u2029'.indexOf(ch) >= 0) {
|
112 | result += escapeDisallowedCharacter(ch);
|
113 | continue;
|
114 | } else if (!(ch >= ' ' && ch <= '~')) {
|
115 | result += escapeAllowedCharacter(ch, str[i + 1]);
|
116 | continue;
|
117 | }
|
118 | result += ch;
|
119 | }
|
120 |
|
121 | return result;
|
122 | }
|
123 |
|
124 | function annotateDirective(tree, options) {
|
125 | var result;
|
126 |
|
127 | if (options == null) {
|
128 | options = { destructive: false };
|
129 | }
|
130 |
|
131 | result = (options.destructive) ? tree : common.deepCopy(tree);
|
132 |
|
133 | common.traverse(result, {
|
134 | enter: function enter(node, parent) {
|
135 | var stmt, i, iz;
|
136 |
|
137 | if (!(node.type === Syntax.Program ||
|
138 | (node.type === Syntax.BlockStatement && (parent.type === Syntax.FunctionExpression || parent.type === Syntax.FunctionDeclaration)))) {
|
139 | return;
|
140 | }
|
141 |
|
142 | for (i = 0, iz = node.body.length; i < iz; ++i) {
|
143 | stmt = node.body[i];
|
144 | if (isDirective(stmt)) {
|
145 | stmt.type = Syntax.DirectiveStatement;
|
146 | if (stmt.expression.raw) {
|
147 | stmt.directive = stmt.expression.raw.substring(1, stmt.expression.raw.length - 1);
|
148 | stmt.value = stmt.expression.value;
|
149 | stmt.raw = stmt.expression.raw;
|
150 | } else {
|
151 | stmt.directive = escapeString(stmt.expression.value);
|
152 | stmt.value = stmt.expression.value;
|
153 | stmt.raw = '\'' + stmt.directive + '\'';
|
154 | }
|
155 | delete stmt.expression;
|
156 | } else {
|
157 | return;
|
158 | }
|
159 | }
|
160 | }
|
161 | });
|
162 |
|
163 | return result;
|
164 | }
|
165 |
|
166 | annotateDirective.passName = 'annotate-directive';
|
167 | module.exports = annotateDirective;
|
168 | }());
|
169 |
|