|
18 | 18 | import { nameCompare } from './util';
|
19 | 19 | import { stringLength } from '@firebase/util';
|
20 | 20 |
|
| 21 | +/** Maximum key depth. */ |
| 22 | +const MAX_PATH_DEPTH = 32; |
| 23 | + |
| 24 | +/** Maximum number of (UTF8) bytes in a Firebase path. */ |
| 25 | +const MAX_PATH_LENGTH_BYTES = 768; |
| 26 | + |
21 | 27 | /**
|
22 | 28 | * An immutable object representing a parsed path. It's immutable so that you
|
23 | 29 | * can pass them around to other functions without worrying about them changing
|
@@ -252,84 +258,78 @@ export function pathContains(path: Path, other: Path): boolean {
|
252 | 258 | * The definition of a path always begins with '/'.
|
253 | 259 | */
|
254 | 260 | export class ValidationPath {
|
255 |
| - private parts_: string[]; |
| 261 | + parts_: string[]; |
256 | 262 | /** Initialize to number of '/' chars needed in path. */
|
257 |
| - private byteLength_: number; |
| 263 | + byteLength_: number; |
258 | 264 |
|
259 | 265 | /**
|
260 | 266 | * @param path Initial Path.
|
261 | 267 | * @param errorPrefix_ Prefix for any error messages.
|
262 | 268 | */
|
263 |
| - constructor(path: Path, private errorPrefix_: string) { |
| 269 | + constructor(path: Path, public errorPrefix_: string) { |
264 | 270 | this.parts_ = pathSlice(path, 0);
|
265 | 271 | /** Initialize to number of '/' chars needed in path. */
|
266 | 272 | this.byteLength_ = Math.max(1, this.parts_.length);
|
267 | 273 |
|
268 | 274 | for (let i = 0; i < this.parts_.length; i++) {
|
269 | 275 | this.byteLength_ += stringLength(this.parts_[i]);
|
270 | 276 | }
|
271 |
| - this.checkValid_(); |
| 277 | + validationPathCheckValid(this); |
272 | 278 | }
|
| 279 | +} |
273 | 280 |
|
274 |
| - /** @const {number} Maximum key depth. */ |
275 |
| - static get MAX_PATH_DEPTH() { |
276 |
| - return 32; |
| 281 | +export function validationPathPush( |
| 282 | + validationPath: ValidationPath, |
| 283 | + child: string |
| 284 | +): void { |
| 285 | + // Count the needed '/' |
| 286 | + if (validationPath.parts_.length > 0) { |
| 287 | + validationPath.byteLength_ += 1; |
277 | 288 | }
|
| 289 | + validationPath.parts_.push(child); |
| 290 | + validationPath.byteLength_ += stringLength(child); |
| 291 | + validationPathCheckValid(validationPath); |
| 292 | +} |
278 | 293 |
|
279 |
| - /** @const {number} Maximum number of (UTF8) bytes in a Firebase path. */ |
280 |
| - static get MAX_PATH_LENGTH_BYTES() { |
281 |
| - return 768; |
282 |
| - } |
283 |
| - |
284 |
| - /** @param child */ |
285 |
| - push(child: string) { |
286 |
| - // Count the needed '/' |
287 |
| - if (this.parts_.length > 0) { |
288 |
| - this.byteLength_ += 1; |
289 |
| - } |
290 |
| - this.parts_.push(child); |
291 |
| - this.byteLength_ += stringLength(child); |
292 |
| - this.checkValid_(); |
| 294 | +export function validationPathPop(validationPath: ValidationPath): void { |
| 295 | + const last = validationPath.parts_.pop(); |
| 296 | + validationPath.byteLength_ -= stringLength(last); |
| 297 | + // Un-count the previous '/' |
| 298 | + if (validationPath.parts_.length > 0) { |
| 299 | + validationPath.byteLength_ -= 1; |
293 | 300 | }
|
| 301 | +} |
294 | 302 |
|
295 |
| - pop() { |
296 |
| - const last = this.parts_.pop(); |
297 |
| - this.byteLength_ -= stringLength(last); |
298 |
| - // Un-count the previous '/' |
299 |
| - if (this.parts_.length > 0) { |
300 |
| - this.byteLength_ -= 1; |
301 |
| - } |
| 303 | +function validationPathCheckValid(validationPath: ValidationPath): void { |
| 304 | + if (validationPath.byteLength_ > MAX_PATH_LENGTH_BYTES) { |
| 305 | + throw new Error( |
| 306 | + validationPath.errorPrefix_ + |
| 307 | + 'has a key path longer than ' + |
| 308 | + MAX_PATH_LENGTH_BYTES + |
| 309 | + ' bytes (' + |
| 310 | + validationPath.byteLength_ + |
| 311 | + ').' |
| 312 | + ); |
302 | 313 | }
|
303 |
| - |
304 |
| - private checkValid_() { |
305 |
| - if (this.byteLength_ > ValidationPath.MAX_PATH_LENGTH_BYTES) { |
306 |
| - throw new Error( |
307 |
| - this.errorPrefix_ + |
308 |
| - 'has a key path longer than ' + |
309 |
| - ValidationPath.MAX_PATH_LENGTH_BYTES + |
310 |
| - ' bytes (' + |
311 |
| - this.byteLength_ + |
312 |
| - ').' |
313 |
| - ); |
314 |
| - } |
315 |
| - if (this.parts_.length > ValidationPath.MAX_PATH_DEPTH) { |
316 |
| - throw new Error( |
317 |
| - this.errorPrefix_ + |
318 |
| - 'path specified exceeds the maximum depth that can be written (' + |
319 |
| - ValidationPath.MAX_PATH_DEPTH + |
320 |
| - ') or object contains a cycle ' + |
321 |
| - this.toErrorString() |
322 |
| - ); |
323 |
| - } |
| 314 | + if (validationPath.parts_.length > MAX_PATH_DEPTH) { |
| 315 | + throw new Error( |
| 316 | + validationPath.errorPrefix_ + |
| 317 | + 'path specified exceeds the maximum depth that can be written (' + |
| 318 | + MAX_PATH_DEPTH + |
| 319 | + ') or object contains a cycle ' + |
| 320 | + validationPathToErrorString(validationPath) |
| 321 | + ); |
324 | 322 | }
|
| 323 | +} |
325 | 324 |
|
326 |
| - /** |
327 |
| - * String for use in error messages - uses '.' notation for path. |
328 |
| - */ |
329 |
| - toErrorString(): string { |
330 |
| - if (this.parts_.length === 0) { |
331 |
| - return ''; |
332 |
| - } |
333 |
| - return "in property '" + this.parts_.join('.') + "'"; |
| 325 | +/** |
| 326 | + * String for use in error messages - uses '.' notation for path. |
| 327 | + */ |
| 328 | +export function validationPathToErrorString( |
| 329 | + validationPath: ValidationPath |
| 330 | +): string { |
| 331 | + if (validationPath.parts_.length === 0) { |
| 332 | + return ''; |
334 | 333 | }
|
| 334 | + return "in property '" + validationPath.parts_.join('.') + "'"; |
335 | 335 | }
|
0 commit comments