|
1 | 1 | var utils = require('./utils'),
|
2 | 2 | dirId = 1,
|
3 | 3 |
|
4 |
| - // Regexes! |
5 |
| - // regex to split multiple directive expressions |
6 |
| - // split by commas, but ignore commas within quotes, parens and escapes. |
7 |
| - SPLIT_RE = /(?:['"](?:\\.|[^'"])*['"]|\((?:\\.|[^\)])*\)|\\.|[^,])+/g, |
8 | 4 | // match up to the first single pipe, ignore those within quotes.
|
9 | 5 | KEY_RE = /^(?:['"](?:\\.|[^'"])*['"]|\\.|[^\|]|\|\|)+/,
|
10 | 6 | ARG_RE = /^([\w-$ ]+):(.+)$/,
|
@@ -140,59 +136,185 @@ DirProto.unbind = function () {
|
140 | 136 | * split a unquoted-comma separated expression into
|
141 | 137 | * multiple clauses
|
142 | 138 | */
|
143 |
| -Directive.split = function (exp) { |
144 |
| - return exp.indexOf(',') > -1 |
145 |
| - ? exp.match(SPLIT_RE) || [''] |
146 |
| - : [exp] |
147 |
| -} |
| 139 | +Directive.parse = function (str) { |
148 | 140 |
|
149 |
| -/** |
150 |
| - * parse a key, extract argument |
151 |
| - */ |
152 |
| -Directive.parseArg = function (rawKey) { |
153 |
| - var key = rawKey, |
154 |
| - arg = null |
155 |
| - if (rawKey.indexOf(':') > -1) { |
156 |
| - var argMatch = rawKey.match(ARG_RE) |
157 |
| - key = argMatch |
158 |
| - ? argMatch[2].trim() |
159 |
| - : key |
160 |
| - arg = argMatch |
161 |
| - ? argMatch[1].trim() |
162 |
| - : arg |
| 141 | + var inSingle = false, |
| 142 | + inDouble = false, |
| 143 | + curly = 0, |
| 144 | + square = 0, |
| 145 | + paren = 0, |
| 146 | + begin = 0, |
| 147 | + argIndex = 0, |
| 148 | + dirs = [], |
| 149 | + dir = {}, |
| 150 | + lastFilterIndex = 0 |
| 151 | + |
| 152 | + for (var c, i = 0, l = str.length; i < l; i++) { |
| 153 | + c = str.charAt(i) |
| 154 | + if (inSingle) { |
| 155 | + // check single quote |
| 156 | + if (c === "'") inSingle = !inSingle |
| 157 | + } else if (inDouble) { |
| 158 | + // check double quote |
| 159 | + if (c === '"') inDouble = !inDouble |
| 160 | + } else if (c === ',' && !paren && !curly && !square) { |
| 161 | + // reached the end of a directive |
| 162 | + pushDir() |
| 163 | + // reset & skip the comma |
| 164 | + dir = {} |
| 165 | + begin = argIndex = lastFilterIndex = i + 1 |
| 166 | + } else if (c === ':' && !dir.key && !dir.arg) { |
| 167 | + // argument |
| 168 | + argIndex = i + 1 |
| 169 | + dir.arg = str.slice(begin, i).trim() |
| 170 | + } else if (c === '|' && str.charAt(i + 1) !== '|') { |
| 171 | + if (!dir.key) { |
| 172 | + // first filter, end of key |
| 173 | + lastFilterIndex = i |
| 174 | + dir.key = str.slice(argIndex, i).trim() |
| 175 | + } else { |
| 176 | + // already has filter |
| 177 | + pushFilter() |
| 178 | + } |
| 179 | + } else if (c === '"') { |
| 180 | + inDouble = true |
| 181 | + } else if (c === "'") { |
| 182 | + inSingle = true |
| 183 | + } else if (c === '(') { |
| 184 | + paren++ |
| 185 | + } else if (c === ')') { |
| 186 | + paren-- |
| 187 | + } else if (c === '[') { |
| 188 | + square++ |
| 189 | + } else if (c === ']') { |
| 190 | + square-- |
| 191 | + } else if (c === '{') { |
| 192 | + curly++ |
| 193 | + } else if (c === '}') { |
| 194 | + curly-- |
| 195 | + } |
163 | 196 | }
|
164 |
| - return { |
165 |
| - key: key, |
166 |
| - arg: arg |
| 197 | + if (begin !== i) { |
| 198 | + pushDir() |
167 | 199 | }
|
168 |
| -} |
169 | 200 |
|
170 |
| -/** |
171 |
| - * parse a the filters |
172 |
| - */ |
173 |
| -Directive.parseFilters = function (exp) { |
174 |
| - if (exp.indexOf('|') < 0) { |
175 |
| - return |
176 |
| - } |
177 |
| - var filters = exp.match(FILTERS_RE), |
178 |
| - res, i, l, tokens |
179 |
| - if (filters) { |
180 |
| - res = [] |
181 |
| - for (i = 0, l = filters.length; i < l; i++) { |
182 |
| - tokens = filters[i].slice(1).match(FILTER_TOKEN_RE) |
183 |
| - if (tokens) { |
184 |
| - res.push({ |
185 |
| - name: tokens[0], |
186 |
| - args: tokens.length > 1 |
187 |
| - ? tokens.slice(1) |
188 |
| - : null |
189 |
| - }) |
190 |
| - } |
| 201 | + function pushDir () { |
| 202 | + dir.expression = str.slice(begin, i).trim() |
| 203 | + if (!dir.key) { |
| 204 | + dir.key = str.slice(argIndex, i).trim() |
| 205 | + } else if (lastFilterIndex !== begin) { |
| 206 | + pushFilter() |
191 | 207 | }
|
| 208 | + dirs.push(dir) |
| 209 | + } |
| 210 | + |
| 211 | + function pushFilter () { |
| 212 | + (dir.filters = dir.filters || []) |
| 213 | + .push(str.slice(lastFilterIndex + 1, i).trim()) |
| 214 | + lastFilterIndex = i + 1 |
192 | 215 | }
|
193 |
| - return res |
| 216 | + |
| 217 | + return dirs |
194 | 218 | }
|
195 | 219 |
|
| 220 | +// function split (str) { |
| 221 | +// var inSingle = false, |
| 222 | +// inDouble = false, |
| 223 | +// curly = 0, |
| 224 | +// square = 0, |
| 225 | +// paren = 0, |
| 226 | +// begin = 0, |
| 227 | +// end = 0, |
| 228 | +// res = [] |
| 229 | +// for (var c, i = 0, l = str.length; i < l; i++) { |
| 230 | +// c = str.charAt(i) |
| 231 | +// if (inSingle) { |
| 232 | +// if (c === "'") { |
| 233 | +// inSingle = !inSingle |
| 234 | +// } |
| 235 | +// end++ |
| 236 | +// } else if (inDouble) { |
| 237 | +// if (c === '"') { |
| 238 | +// inDouble = !inDouble |
| 239 | +// } |
| 240 | +// end++ |
| 241 | +// } else if (c === ',' && !paren && !curly && !square) { |
| 242 | +// res.push(str.slice(begin, end)) |
| 243 | +// begin = end = i + 1 |
| 244 | +// } else { |
| 245 | +// if (c === '"') { |
| 246 | +// inDouble = true |
| 247 | +// } else if (c === "'") { |
| 248 | +// inSingle = true |
| 249 | +// } else if (c === '(') { |
| 250 | +// paren++ |
| 251 | +// } else if (c === ')') { |
| 252 | +// paren-- |
| 253 | +// } else if (c === '[') { |
| 254 | +// square++ |
| 255 | +// } else if (c === ']') { |
| 256 | +// square-- |
| 257 | +// } else if (c === '{') { |
| 258 | +// curly++ |
| 259 | +// } else if (c === '}') { |
| 260 | +// curly-- |
| 261 | +// } |
| 262 | +// end++ |
| 263 | +// } |
| 264 | +// } |
| 265 | +// if (begin !== end) { |
| 266 | +// res.push(str.slice(begin, end)) |
| 267 | +// } |
| 268 | +// return res |
| 269 | +// } |
| 270 | + |
| 271 | +// /** |
| 272 | +// * parse a key, extract argument |
| 273 | +// */ |
| 274 | +// Directive.parseArg = function (rawKey) { |
| 275 | +// var key = rawKey, |
| 276 | +// arg = null |
| 277 | +// if (rawKey.indexOf(':') > -1) { |
| 278 | +// var argMatch = rawKey.match(ARG_RE) |
| 279 | +// key = argMatch |
| 280 | +// ? argMatch[2].trim() |
| 281 | +// : key |
| 282 | +// arg = argMatch |
| 283 | +// ? argMatch[1].trim() |
| 284 | +// : arg |
| 285 | +// } |
| 286 | +// return { |
| 287 | +// key: key, |
| 288 | +// arg: arg |
| 289 | +// } |
| 290 | +// } |
| 291 | + |
| 292 | +// /** |
| 293 | +// * parse a the filters |
| 294 | +// */ |
| 295 | +// Directive.parseFilters = function (exp) { |
| 296 | +// if (exp.indexOf('|') < 0) { |
| 297 | +// return |
| 298 | +// } |
| 299 | +// var filters = exp.match(FILTERS_RE), |
| 300 | +// res, i, l, tokens |
| 301 | +// if (filters) { |
| 302 | +// res = [] |
| 303 | +// for (i = 0, l = filters.length; i < l; i++) { |
| 304 | +// tokens = filters[i].slice(1).match(FILTER_TOKEN_RE) |
| 305 | +// if (tokens) { |
| 306 | +// res.push({ |
| 307 | +// name: tokens[0], |
| 308 | +// args: tokens.length > 1 |
| 309 | +// ? tokens.slice(1) |
| 310 | +// : null |
| 311 | +// }) |
| 312 | +// } |
| 313 | +// } |
| 314 | +// } |
| 315 | +// return res |
| 316 | +// } |
| 317 | + |
196 | 318 | /**
|
197 | 319 | * Inline computed filters so they become part
|
198 | 320 | * of the expression
|
|
0 commit comments