1"use strict"; 2(self["webpackChunkoptica_boavista"] = self["webpackChunkoptica_boavista"] || []).push([["polyfills"],{ 3 4/***/ 7435: 5/*!**************************!*\ 6 !*** ./src/polyfills.ts ***! 7 \**************************/ 8/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { 9 10__webpack_require__.r(__webpack_exports__); 11/* harmony import */ var _angular_localize_init__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! @angular/localize/init */ 6344); 12/* harmony import */ var zone_js__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! zone.js */ 4946); 13/* harmony import */ var zone_js__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(zone_js__WEBPACK_IMPORTED_MODULE_1__); 14/*************************************************************************************************** 15 * Load `$localize` onto the global scope - used if i18n tags appear in Angular templates. 16 */ 17 18/** 19 * This file includes polyfills needed by Angular and is loaded before the app. 20 * You can add your own extra polyfills to this file. 21 * 22 * This file is divided into 2 sections: 23 * 1. Browser polyfills. These are applied before loading ZoneJS and are sorted by browsers. 24 * 2. Application imports. Files imported after ZoneJS that should be loaded before your main 25 * file. 26 * 27 * The current setup is for so-called "evergreen" browsers; the last versions of browsers that 28 * automatically update themselves. This includes recent versions of Safari, Chrome (including 29 * Opera), Edge on the desktop, and iOS and Chrome on mobile. 30 * 31 * Learn more in https://angular.io/guide/browser-support 32 */ 33/*************************************************************************************************** 34 * BROWSER POLYFILLS 35 */ 36/** 37 * By default, zone.js will patch all possible macroTask and DomEvents 38 * user can disable parts of macroTask/DomEvents patch by setting following flags 39 * because those flags need to be set before `zone.js` being loaded, and webpack 40 * will put import in the top of bundle, so user need to create a separate file 41 * in this directory (for example: zone-flags.ts), and put the following flags 42 * into that file, and then add the following code before importing zone.js. 43 * import './zone-flags'; 44 * 45 * The flags allowed in zone-flags.ts are listed here. 46 * 47 * The following flags will work for all browsers. 48 * 49 * (window as any).__Zone_disable_requestAnimationFrame = true; // disable patch requestAnimationFrame 50 * (window as any).__Zone_disable_on_property = true; // disable patch onProperty such as onclick 51 * (window as any).__zone_symbol__UNPATCHED_EVENTS = ['scroll', 'mousemove']; // disable patch specified eventNames 52 * 53 * in IE/Edge developer tools, the addEventListener will also be wrapped by zone.js 54 * with the following flag, it will bypass `zone.js` patch for IE/Edge 55 * 56 * (window as any).__Zone_enable_cross_context_check = true; 57 * 58 */ 59/*************************************************************************************************** 60 * Zone JS is required by default for Angular itself. 61 */ 62 // Included with Angular CLI. 63/*************************************************************************************************** 64 * APPLICATION IMPORTS 65 */ 66 67 68/***/ }), 69 70/***/ 4946: 71/*!***********************************************!*\ 72 !*** ./node_modules/zone.js/fesm2015/zone.js ***! 73 \***********************************************/ 74/***/ (() => { 75 76 77/** 78 * @license Angular v14.2.0-next.0 79 * (c) 2010-2022 Google LLC. https://angular.io/ 80 * License: MIT 81 */ 82 83/** 84 * @license 85 * Copyright Google LLC All Rights Reserved. 86 * 87 * Use of this source code is governed by an MIT-style license that can be 88 * found in the LICENSE file at https://angular.io/license 89 */ 90 91(function (global) { 92 const performance = global['performance']; 93 94 function mark(name) { 95 performance && performance['mark'] && performance['mark'](name); 96 } 97 98 function performanceMeasure(name, label) { 99 performance && performance['measure'] && performance['measure'](name, label); 100 } 101 102 mark('Zone'); // Initialize before it's accessed below. 103 // __Zone_symbol_prefix global can be used to override the default zone 104 // symbol prefix with a custom one if needed. 105 106 const symbolPrefix = global['__Zone_symbol_prefix'] || '__zone_symbol__'; 107 108 function __symbol__(name) { 109 return symbolPrefix + name; 110 } 111 112 const checkDuplicate = global[__symbol__('forceDuplicateZoneCheck')] === true; 113 114 if (global['Zone']) { 115 // if global['Zone'] already exists (maybe zone.js was already loaded or 116 // some other lib also registered a global object named Zone), we may
vendor: 21,308 bytes, lines 116-742
116need 117 // to throw an error, but sometimes user may not want this error. 118 // For example, 119 // we have two web pages, page1 includes zone.js, page2 doesn't. 120 // and the 1st time user load page1 and page2, everything work fine, 121 // but when user load page2 again, error occurs because global['Zone'] already exists. 122 // so we add a flag to let user choose whether to throw this error or not. 123 // By default, if existing Zone is from zone.js, we will not throw the error. 124 if (checkDuplicate || typeof global['Zone'].__symbol__ !== 'function') { 125 throw new Error('Zone already loaded.'); 126 } else { 127 return global['Zone']; 128 } 129 } 130 131 class Zone { 132 constructor(parent, zoneSpec) { 133 this._parent = parent; 134 this._name = zoneSpec ? zoneSpec.name || 'unnamed' : '<root>'; 135 this._properties = zoneSpec && zoneSpec.properties || {}; 136 this._zoneDelegate = new _ZoneDelegate(this, this._parent && this._parent._zoneDelegate, zoneSpec); 137 } 138 139 static assertZonePatched() { 140 if (global['Promise'] !== patches['ZoneAwarePromise']) { 141 throw new Error('Zone.js has detected that ZoneAwarePromise `(window|global).Promise` ' + 'has been overwritten.\n' + 'Most likely cause is that a Promise polyfill has been loaded ' + 'after Zone.js (Polyfilling Promise api is not necessary when zone.js is loaded. ' + 'If you must load one, do so before loading zone.js.)'); 142 } 143 } 144 145 static get root() { 146 let zone = Zone.current; 147 148 while (zone.parent) { 149 zone = zone.parent; 150 } 151 152 return zone; 153 } 154 155 static get current() { 156 return _currentZoneFrame.zone; 157 } 158 159 static get currentTask() { 160 return _currentTask; 161 } // tslint:disable-next-line:require-internal-with-underscore 162 163 164 static __load_patch(name, fn, ignoreDuplicate = false) { 165 if (patches.hasOwnProperty(name)) { 166 // `checkDuplicate` option is defined from global variable 167 // so it works for all modules. 168 // `ignoreDuplicate` can work for the specified module 169 if (!ignoreDuplicate && checkDuplicate) { 170 throw Error('Already loaded patch: ' + name); 171 } 172 } else if (!global['__Zone_disable_' + name]) { 173 const perfName = 'Zone:' + name; 174 mark(perfName); 175 patches[name] = fn(global, Zone, _api); 176 performanceMeasure(perfName, perfName); 177 } 178 } 179 180 get parent() { 181 return this._parent; 182 } 183 184 get name() { 185 return this._name; 186 } 187 188 get(key) { 189 const zone = this.getZoneWith(key); 190 if (zone) return zone._properties[key]; 191 } 192 193 getZoneWith(key) { 194 let current = this; 195 196 while (current) { 197 if (current._properties.hasOwnProperty(key)) { 198 return current; 199 } 200 201 current = current._parent; 202 } 203 204 return null; 205 } 206 207 fork(zoneSpec) { 208 if (!zoneSpec) throw new Error('ZoneSpec required!'); 209 return this._zoneDelegate.fork(this, zoneSpec); 210 } 211 212 wrap(callback, source) { 213 if (typeof callback !== 'function') { 214 throw new Error('Expecting function got: ' + callback); 215 } 216 217 const _callback = this._zoneDelegate.intercept(this, callback, source); 218 219 const zone = this; 220 return function () { 221 return zone.runGuarded(_callback, this, arguments, source); 222 }; 223 } 224 225 run(callback, applyThis, applyArgs, source) { 226 _currentZoneFrame = { 227 parent: _currentZoneFrame, 228 zone: this 229 }; 230 231 try { 232 return this._zoneDelegate.invoke(this, callback, applyThis, applyArgs, source); 233 } finally { 234 _currentZoneFrame = _currentZoneFrame.parent; 235 } 236 } 237 238 runGuarded(callback, applyThis = null, applyArgs, source) { 239 _currentZoneFrame = { 240 parent: _currentZoneFrame, 241 zone: this 242 }; 243 244 try { 245 try { 246 return this._zoneDelegate.invoke(this, callback, applyThis, applyArgs, source); 247 } catch (error) { 248 if (this._zoneDelegate.handleError(this, error)) { 249 throw error; 250 } 251 } 252 } finally { 253 _currentZoneFrame = _currentZoneFrame.parent; 254 } 255 } 256 257 runTask(task, applyThis, applyArgs) { 258 if (task.zone != this) { 259 throw new Error('A task can only be run in the zone of creation! (Creation: ' + (task.zone || NO_ZONE).name + '; Execution: ' + this.name + ')'); 260 } // https://github.com/angular/zone.js/issues/778, sometimes eventTask 261 // will run in notScheduled(canceled) state, we should not try to 262 // run such kind of task but just return 263 264 265 if (task.state === notScheduled && (task.type === eventTask || task.type === macroTask)) { 266 return; 267 } 268 269 const reEntryGuard = task.state != running; 270 reEntryGuard && task._transitionTo(running, scheduled); 271 task.runCount++; 272 const previousTask = _currentTask; 273 _currentTask = task; 274 _currentZoneFrame = { 275 parent: _currentZoneFrame, 276 zone: this 277 }; 278 279 try { 280 if (task.type == macroTask && task.data && !task.data.isPeriodic) { 281 task.cancelFn = undefined; 282 } 283 284 try { 285 return this._zoneDelegate.invokeTask(this, task, applyThis, applyArgs); 286 } catch (error) { 287 if (this._zoneDelegate.handleError(this, error)) { 288 throw error; 289 } 290 } 291 } finally { 292 // if the task's state is notScheduled or unknown, then it has already been cancelled 293 // we should not reset the state to scheduled 294 if (task.state !== notScheduled && task.state !== unknown) { 295 if (task.type == eventTask || task.data && task.data.isPeriodic) { 296 reEntryGuard && task._transitionTo(scheduled, running); 297 } else { 298 task.runCount = 0; 299 300 this._updateTaskCount(task, -1); 301 302 reEntryGuard && task._transitionTo(notScheduled, running, notScheduled); 303 } 304 } 305 306 _currentZoneFrame = _currentZoneFrame.parent; 307 _currentTask = previousTask; 308 } 309 } 310 311 scheduleTask(task) { 312 if (task.zone && task.zone !== this) { 313 // check if the task was rescheduled, the newZone 314 // should not be the children of the original zone 315 let newZone = this; 316 317 while (newZone) { 318 if (newZone === task.zone) { 319 throw Error(`can not reschedule task to ${this.name} which is descendants of the original zone ${task.zone.name}`); 320 } 321 322 newZone = newZone.parent; 323 } 324 } 325 326 task._transitionTo(scheduling, notScheduled); 327 328 const zoneDelegates = []; 329 task._zoneDelegates = zoneDelegates; 330 task._zone = this; 331 332 try { 333 task = this._zoneDelegate.scheduleTask(this, task); 334 } catch (err) { 335 // should set task's state to unknown when scheduleTask throw error 336 // because the err may from reschedule, so the fromState maybe notScheduled 337 task._transitionTo(unknown, scheduling, notScheduled); // TODO: @JiaLiPassion, should we check the result from handleError? 338 339 340 this._zoneDelegate.handleError(this, err); 341 342 throw err; 343 } 344 345 if (task._zoneDelegates === zoneDelegates) { 346 // we have to check because internally the delegate can reschedule the task. 347 this._updateTaskCount(task, 1); 348 } 349 350 if (task.state == scheduling) { 351 task._transitionTo(scheduled, scheduling); 352 } 353 354 return task; 355 } 356 357 scheduleMicroTask(source, callback, data, customSchedule) { 358 return this.scheduleTask(new ZoneTask(microTask, source, callback, data, customSchedule, undefined)); 359 } 360 361 scheduleMacroTask(source, callback, data, customSchedule, customCancel) { 362 return this.scheduleTask(new ZoneTask(macroTask, source, callback, data, customSchedule, customCancel)); 363 } 364 365 scheduleEventTask(source, callback, data, customSchedule, customCancel) { 366 return this.scheduleTask(new ZoneTask(eventTask, source, callback, data, customSchedule, customCancel)); 367 } 368 369 cancelTask(task) { 370 if (task.zone != this) throw new Error('A task can only be cancelled in the zone of creation! (Creation: ' + (task.zone || NO_ZONE).name + '; Execution: ' + this.name + ')'); 371 372 task._transitionTo(canceling, scheduled, running); 373 374 try { 375 this._zoneDelegate.cancelTask(this, task); 376 } catch (err) { 377 // if error occurs when cancelTask, transit the state to unknown 378 task._transitionTo(unknown, canceling); 379 380 this._zoneDelegate.handleError(this, err); 381 382 throw err; 383 } 384 385 this._updateTaskCount(task, -1); 386 387 task._transitionTo(notScheduled, canceling); 388 389 task.runCount = 0; 390 return task; 391 } 392 393 _updateTaskCount(task, count) { 394 const zoneDelegates = task._zoneDelegates; 395 396 if (count == -1) { 397 task._zoneDelegates = null; 398 } 399 400 for (let i = 0; i < zoneDelegates.length; i++) { 401 zoneDelegates[i]._updateTaskCount(task.type, count); 402 } 403 } 404 405 } // tslint:disable-next-line:require-internal-with-underscore 406 407 408 Zone.__symbol__ = __symbol__; 409 const DELEGATE_ZS = { 410 name: '', 411 onHasTask: (delegate, _, target, hasTaskState) => delegate.hasTask(target, hasTaskState), 412 onScheduleTask: (delegate, _, target, task) => delegate.scheduleTask(target, task), 413 onInvokeTask: (delegate, _, target, task, applyThis, applyArgs) => delegate.invokeTask(target, task, applyThis, applyArgs), 414 onCancelTask: (delegate, _, target, task) => delegate.cancelTask(target, task) 415 }; 416 417 class _ZoneDelegate { 418 constructor(zone, parentDelegate, zoneSpec) { 419 this._taskCounts = { 420 'microTask': 0, 421 'macroTask': 0, 422 'eventTask': 0 423 }; 424 this.zone = zone; 425 this._parentDelegate = parentDelegate; 426 this._forkZS = zoneSpec && (zoneSpec && zoneSpec.onFork ? zoneSpec : parentDelegate._forkZS); 427 this._forkDlgt = zoneSpec && (zoneSpec.onFork ? parentDelegate : parentDelegate._forkDlgt); 428 this._forkCurrZone = zoneSpec && (zoneSpec.onFork ? this.zone : parentDelegate._forkCurrZone); 429 this._interceptZS = zoneSpec && (zoneSpec.onIntercept ? zoneSpec : parentDelegate._interceptZS); 430 this._interceptDlgt = zoneSpec && (zoneSpec.onIntercept ? parentDelegate : parentDelegate._interceptDlgt); 431 this._interceptCurrZone = zoneSpec && (zoneSpec.onIntercept ? this.zone : parentDelegate._interceptCurrZone); 432 this._invokeZS = zoneSpec && (zoneSpec.onInvoke ? zoneSpec : parentDelegate._invokeZS); 433 this._invokeDlgt = zoneSpec && (zoneSpec.onInvoke ? parentDelegate : parentDelegate._invokeDlgt); 434 this._invokeCurrZone = zoneSpec && (zoneSpec.onInvoke ? this.zone : parentDelegate._invokeCurrZone); 435 this._handleErrorZS = zoneSpec && (zoneSpec.onHandleError ? zoneSpec : parentDelegate._handleErrorZS); 436 this._handleErrorDlgt = zoneSpec && (zoneSpec.onHandleError ? parentDelegate : parentDelegate._handleErrorDlgt); 437 this._handleErrorCurrZone = zoneSpec && (zoneSpec.onHandleError ? this.zone : parentDelegate._handleErrorCurrZone); 438 this._scheduleTaskZS = zoneSpec && (zoneSpec.onScheduleTask ? zoneSpec : parentDelegate._scheduleTaskZS); 439 this._scheduleTaskDlgt = zoneSpec && (zoneSpec.onScheduleTask ? parentDelegate : parentDelegate._scheduleTaskDlgt); 440 this._scheduleTaskCurrZone = zoneSpec && (zoneSpec.onScheduleTask ? this.zone : parentDelegate._scheduleTaskCurrZone); 441 this._invokeTaskZS = zoneSpec && (zoneSpec.onInvokeTask ? zoneSpec : parentDelegate._invokeTaskZS); 442 this._invokeTaskDlgt = zoneSpec && (zoneSpec.onInvokeTask ? parentDelegate : parentDelegate._invokeTaskDlgt); 443 this._invokeTaskCurrZone = zoneSpec && (zoneSpec.onInvokeTask ? this.zone : parentDelegate._invokeTaskCurrZone); 444 this._cancelTaskZS = zoneSpec && (zoneSpec.onCancelTask ? zoneSpec : parentDelegate._cancelTaskZS); 445 this._cancelTaskDlgt = zoneSpec && (zoneSpec.onCancelTask ? parentDelegate : parentDelegate._cancelTaskDlgt); 446 this._cancelTaskCurrZone = zoneSpec && (zoneSpec.onCancelTask ? this.zone : parentDelegate._cancelTaskCurrZone); 447 this._hasTaskZS = null; 448 this._hasTaskDlgt = null; 449 this._hasTaskDlgtOwner = null; 450 this._hasTaskCurrZone = null; 451 const zoneSpecHasTask = zoneSpec && zoneSpec.onHasTask; 452 const parentHasTask = parentDelegate && parentDelegate._hasTaskZS; 453 454 if (zoneSpecHasTask || parentHasTask) { 455 // If we need to report hasTask, than this ZS needs to do ref counting on tasks. In such 456 // a case all task related interceptors must go through this ZD. We can't short circuit it. 457 this._hasTaskZS = zoneSpecHasTask ? zoneSpec : DELEGATE_ZS; 458 this._hasTaskDlgt = parentDelegate; 459 this._hasTaskDlgtOwner = this; 460 this._hasTaskCurrZone = zone; 461 462 if (!zoneSpec.onScheduleTask) { 463 this._scheduleTaskZS = DELEGATE_ZS; 464 this._scheduleTaskDlgt = parentDelegate; 465 this._scheduleTaskCurrZone = this.zone; 466 } 467 468 if (!zoneSpec.onInvokeTask) { 469 this._invokeTaskZS = DELEGATE_ZS; 470 this._invokeTaskDlgt = parentDelegate; 471 this._invokeTaskCurrZone = this.zone; 472 } 473 474 if (!zoneSpec.onCancelTask) { 475 this._cancelTaskZS = DELEGATE_ZS; 476 this._cancelTaskDlgt = parentDelegate; 477 this._cancelTaskCurrZone = this.zone; 478 } 479 } 480 } 481 482 fork(targetZone, zoneSpec) { 483 return this._forkZS ? this._forkZS.onFork(this._forkDlgt, this.zone, targetZone, zoneSpec) : new Zone(targetZone, zoneSpec); 484 } 485 486 intercept(targetZone, callback, source) { 487 return this._interceptZS ? this._interceptZS.onIntercept(this._interceptDlgt, this._interceptCurrZone, targetZone, callback, source) : callback; 488 } 489 490 invoke(targetZone, callback, applyThis, applyArgs, source) { 491 return this._invokeZS ? this._invokeZS.onInvoke(this._invokeDlgt, this._invokeCurrZone, targetZone, callback, applyThis, applyArgs, source) : callback.apply(applyThis, applyArgs); 492 } 493 494 handleError(targetZone, error) { 495 return this._handleErrorZS ? this._handleErrorZS.onHandleError(this._handleErrorDlgt, this._handleErrorCurrZone, targetZone, error) : true; 496 } 497 498 scheduleTask(targetZone, task) { 499 let returnTask = task; 500 501 if (this._scheduleTaskZS) { 502 if (this._hasTaskZS) { 503 returnTask._zoneDelegates.push(this._hasTaskDlgtOwner); 504 } // clang-format off 505 506 507 returnTask = this._scheduleTaskZS.onScheduleTask(this._scheduleTaskDlgt, this._scheduleTaskCurrZone, targetZone, task); // clang-format on 508 509 if (!returnTask) returnTask = task; 510 } else { 511 if (task.scheduleFn) { 512 task.scheduleFn(task); 513 } else if (task.type == microTask) { 514 scheduleMicroTask(task); 515 } else { 516 throw new Error('Task is missing scheduleFn.'); 517 } 518 } 519 520 return returnTask; 521 } 522 523 invokeTask(targetZone, task, applyThis, applyArgs) { 524 return this._invokeTaskZS ? this._invokeTaskZS.onInvokeTask(this._invokeTaskDlgt, this._invokeTaskCurrZone, targetZone, task, applyThis, applyArgs) : task.callback.apply(applyThis, applyArgs); 525 } 526 527 cancelTask(targetZone, task) { 528 let value; 529 530 if (this._cancelTaskZS) { 531 value = this._cancelTaskZS.onCancelTask(this._cancelTaskDlgt, this._cancelTaskCurrZone, targetZone, task); 532 } else { 533 if (!task.cancelFn) { 534 throw Error('Task is not cancelable'); 535 } 536 537 value = task.cancelFn(task); 538 } 539 540 return value; 541 } 542 543 hasTask(targetZone, isEmpty) { 544 // hasTask should not throw error so other ZoneDelegate 545 // can still trigger hasTask callback 546 try { 547 this._hasTaskZS && this._hasTaskZS.onHasTask(this._hasTaskDlgt, this._hasTaskCurrZone, targetZone, isEmpty); 548 } catch (err) { 549 this.handleError(targetZone, err); 550 } 551 } // tslint:disable-next-line:require-internal-with-underscore 552 553 554 _updateTaskCount(type, count) { 555 const counts = this._taskCounts; 556 const prev = counts[type]; 557 const next = counts[type] = prev + count; 558 559 if (next < 0) { 560 throw new Error('More tasks executed then were scheduled.'); 561 } 562 563 if (prev == 0 || next == 0) { 564 const isEmpty = { 565 microTask: counts['microTask'] > 0, 566 macroTask: counts['macroTask'] > 0, 567 eventTask: counts['eventTask'] > 0, 568 change: type 569 }; 570 this.hasTask(this.zone, isEmpty); 571 } 572 } 573 574 } 575 576 class ZoneTask { 577 constructor(type, source, callback, options, scheduleFn, cancelFn) { 578 // tslint:disable-next-line:require-internal-with-underscore 579 this._zone = null; 580 this.runCount = 0; // tslint:disable-next-line:require-internal-with-underscore 581 582 this._zoneDelegates = null; // tslint:disable-next-line:require-internal-with-underscore 583 584 this._state = 'notScheduled'; 585 this.type = type; 586 this.source = source; 587 this.data = options; 588 this.scheduleFn = scheduleFn; 589 this.cancelFn = cancelFn; 590 591 if (!callback) { 592 throw new Error('callback is not defined'); 593 } 594 595 this.callback = callback; 596 const self = this; // TODO: @JiaLiPassion options should have interface 597 598 if (type === eventTask && options && options.useG) { 599 this.invoke = ZoneTask.invokeTask; 600 } else { 601 this.invoke = function () { 602 return ZoneTask.invokeTask.call(global, self, this, arguments); 603 }; 604 } 605 } 606 607 static invokeTask(task, target, args) { 608 if (!task) { 609 task = this; 610 } 611 612 _numberOfNestedTaskFrames++; 613 614 try { 615 task.runCount++; 616 return task.zone.runTask(task, target, args); 617 } finally { 618 if (_numberOfNestedTaskFrames == 1) { 619 drainMicroTaskQueue(); 620 } 621 622 _numberOfNestedTaskFrames--; 623 } 624 } 625 626 get zone() { 627 return this._zone; 628 } 629 630 get state() { 631 return this._state; 632 } 633 634 cancelScheduleRequest() { 635 this._transitionTo(notScheduled, scheduling); 636 } // tslint:disable-next-line:require-internal-with-underscore 637 638 639 _transitionTo(toState, fromState1, fromState2) { 640 if (this._state === fromState1 || this._state === fromState2) { 641 this._state = toState; 642 643 if (toState == notScheduled) { 644 this._zoneDelegates = null; 645 } 646 } else { 647 throw new Error(`${this.type} '${this.source}': can not transition to '${toState}', expecting state '${fromState1}'${fromState2 ? ' or \'' + fromState2 + '\'' : ''}, was '${this._state}'.`); 648 } 649 } 650 651 toString() { 652 if (this.data && typeof this.data.handleId !== 'undefined') { 653 return this.data.handleId.toString(); 654 } else { 655 return Object.prototype.toString.call(this); 656 } 657 } // add toJSON method to prevent cyclic error when 658 // call JSON.stringify(zoneTask) 659 660 661 toJSON() { 662 return { 663 type: this.type, 664 state: this.state, 665 source: this.source, 666 zone: this.zone.name, 667 runCount: this.runCount 668 }; 669 } 670 671 } ////////////////////////////////////////////////////// 672 ////////////////////////////////////////////////////// 673 /// MICROTASK QUEUE 674 ////////////////////////////////////////////////////// 675 ////////////////////////////////////////////////////// 676 677 678 const symbolSetTimeout = __symbol__('setTimeout'); 679 680 const symbolPromise = __symbol__('Promise'); 681 682 const symbolThen = __symbol__('then'); 683 684 let _microTaskQueue = []; 685 let _isDrainingMicrotaskQueue = false; 686 let nativeMicroTaskQueuePromise; 687 688 function nativeScheduleMicroTask(func) { 689 if (!nativeMicroTaskQueuePromise) { 690 if (global[symbolPromise]) { 691 nativeMicroTaskQueuePromise = global[symbolPromise].resolve(0); 692 } 693 } 694 695 if (nativeMicroTaskQueuePromise) { 696 let nativeThen = nativeMicroTaskQueuePromise[symbolThen]; 697 698 if (!nativeThen) { 699 // native Promise is not patchable, we need to use `then` directly 700 // issue 1078 701 nativeThen = nativeMicroTaskQueuePromise['then']; 702 } 703 704 nativeThen.call(nativeMicroTaskQueuePromise, func); 705 } else { 706 global[symbolSetTimeout](func, 0); 707 } 708 } 709 710 function scheduleMicroTask(task) { 711 // if we are not running in any task, and there has not been anything scheduled 712 // we must bootstrap the initial task creation by manually scheduling the drain 713 if (_numberOfNestedTaskFrames === 0 && _microTaskQueue.length === 0) { 714 // We are not running in Task, so we need to kickstart the microtask queue. 715 nativeScheduleMicroTask(drainMicroTaskQueue); 716 } 717 718 task && _microTaskQueue.push(task); 719 } 720 721 function drainMicroTaskQueue() { 722 if (!_isDrainingMicrotaskQueue) { 723 _isDrainingMicrotaskQueue = true; 724 725 while (_microTaskQueue.length) { 726 const queue = _microTaskQueue; 727 _microTaskQueue = []; 728 729 for (let i = 0; i < queue.length; i++) { 730 const task = queue[i]; 731 732 try { 733 task.zone.runTask(task, null, null); 734 } catch (error) { 735 _api.onUnhandledError(error); 736 } 737 } 738 } 739 740 _api.microtaskDrainDone(); 741 742 _isDrainingMicrotaskQueue = false;
743 } 744 } ////////////////////////////////////////////////////// 745 ////////////////////////////////////////////////////// 746 /// BOOTSTRAP 747 ////////////////////////////////////////////////////// 748 ////////////////////////////////////////////////////// 749 750 751 const NO_ZONE = { 752 name: 'NO ZONE' 753 }; 754 const notScheduled = 'notScheduled', 755 scheduling = 'scheduling', 756 scheduled = 'scheduled', 757 running = 'running', 758 canceling = 'canceling', 759 unknown = 'unknown'; 760 const microTask = 'microTask', 761 macroTask = 'macroTask', 762 eventTask = 'eventTask'; 763 const patches = {}; 764 const _api = { 765 symbol: __symbol__, 766 currentZoneFrame: () => _currentZoneFrame, 767 onUnhandledError: noop, 768 microtaskDrainDone: noop, 769 scheduleMicroTask: scheduleMicroTask, 770 showUncaughtError: () => !Zone[__symbol__('ignoreConsoleErrorUncaughtError')], 771 patchEventTarget: () => [], 772 patchOnProperties: noop, 773 patchMethod: () => noop, 774 bindArguments: () => [], 775 patchThen: () => noop, 776 patchMacroTask: () => noop, 777 patchEventPrototype: () => noop, 778 isIEOrEdge: () => false, 779 getGlobalObjects: () => undefined, 780 ObjectDefineProperty: () => noop, 781 ObjectGetOwnPropertyDescriptor: () => undefined, 782 ObjectCreate: () => undefined, 783 ArraySlice: () => [], 784 patchClass: () => noop, 785 wrapWithCurrentZone: () => noop, 786 filterProperties: () => [], 787 attachOriginToPatched: () => noop, 788 _redefineProperty: () => noop, 789 patchCallbacks: () => noop, 790 nativeScheduleMicroTask: nativeScheduleMicroTask 791 }; 792 let _currentZoneFrame = { 793 parent: null, 794 zone: new Zone(null, null) 795 }; 796 let _currentTask = null; 797 let _numberOfNestedTaskFrames = 0; 798 799 function noop() {} 800 801 performanceMeasure('Zone', 'Zone'); 802 return global['Zone'] = Zone; 803})(typeof window !== 'undefined' && window || typeof self !== 'undefined' && self || global); 804/** 805 * @license 806 * Copyright Google LLC All Rights Reserved. 807 * 808 * Use of this source code is governed by an MIT-style license that can be 809 * found in the LICENSE file at https://angular.io/license 810 */ 811 812/** 813 * Suppress closure compiler errors about unknown 'Zone' variable 814 * @fileoverview 815 * @suppress {undefinedVars,globalThis,missingRequire} 816 */ 817/// <reference types="node"/> 818// issue #989, to reduce bundle size, use short name 819 820/** Object.getOwnPropertyDescriptor */ 821 822 823const ObjectGetOwnPropertyDescriptor = Object.getOwnPropertyDescriptor; 824/** Object.defineProperty */ 825 826const ObjectDefineProperty = Object.defineProperty; 827/** Object.getPrototypeOf */ 828 829const ObjectGetPrototypeOf = Object.getPrototypeOf; 830/** Object.create */ 831 832const ObjectCreate = Object.create; 833/** Array.prototype.slice */ 834 835const ArraySlice = Array.prototype.slice; 836/** addEventListener string const */ 837 838const ADD_EVENT_LISTENER_STR = 'addEventListener'; 839/** removeEventListener string const */ 840 841const REMOVE_EVENT_LISTENER_STR = 'removeEventListener'; 842/** zoneSymbol addEventListener */ 843 844const ZONE_SYMBOL_ADD_EVENT_LISTENER = Zone.__symbol__(ADD_EVENT_LISTENER_STR); 845/** zoneSymbol removeEventListener */ 846 847
848const ZONE_SYMBOL_REMOVE_EVENT_LISTENER = Zone.__symbol__(REMOVE_EVENT_LISTENER_STR); 849/** true string const */ 850 851 852const TRUE_STR = 'true'; 853/** false string const */ 854 855const FALSE_STR = 'false'; 856/** Zone symbol prefix string const. */ 857 858const ZONE_SYMBOL_PREFIX = Zone.__symbol__(''); 859 860function wrapWithCurrentZone(callback, source) { 861 return Zone.current.wrap(callback, source); 862} 863 864function scheduleMacroTaskWithCurrentZone(source, callback, data, customSchedule, customCancel) { 865 return Zone.current.scheduleMacroTask(source, callback, data, customSchedule, customCancel); 866} 867 868const zoneSymbol = Zone.__symbol__; 869const isWindowExists = typeof window !== 'undefined'; 870const internalWindow = isWindowExists ? window : undefined; 871 872const _global = isWindowExists && internalWindow || typeof self === 'object' && self || global; 873 874const REMOVE_ATTRIBUTE = 'removeAttribute'; 875 876function bindArguments(args, source) { 877 for (let i = args.length - 1; i >= 0; i--) { 878 if (typeof args[i] === 'function') { 879 args[i] = wrapWithCurrentZone(args[i], source + '_' + i); 880 } 881 } 882 883 return args; 884} 885 886function patchPrototype(prototype, fnNames) { 887 const source = prototype.constructor['name']; 888 889 for (let i = 0; i < fnNames.length; i++) { 890 const name = fnNames[i]; 891 const delegate = prototype[name]; 892 893 if (delegate) { 894 const prototypeDesc = ObjectGetOwnPropertyDescriptor(prototype, name); 895 896 if (!isPropertyWritable(prototypeDesc)) { 897 continue; 898 } 899 900 prototype[name] = (delegate => { 901 const patched = function () { 902 return delegate.apply(this, bindArguments(arguments, source + '.' + name)); 903 }; 904 905 attachOriginToPatched(patched, delegate); 906 return patched; 907 })(delegate); 908 } 909 } 910} 911 912function isPropertyWritable(propertyDesc) { 913 if (!propertyDesc) { 914 return true; 915 } 916 917 if (propertyDesc.writable === false) { 918 return false; 919 } 920 921 return !(typeof propertyDesc.get === 'function' && typeof propertyDesc.set === 'undefined'); 922} 923 924const isWebWorker = typeof WorkerGlobalScope !== 'undefined' && self instanceof WorkerGlobalScope; // Make sure to access `process` through `_global` so that WebPack does not accidentally browserify 925// this code. 926 927const isNode = !('nw' in _global) && typeof _global.process !== 'undefined' && {}.toString.call(_global.process) === '[object process]'; 928const isBrowser = !isNode && !isWebWorker && !!(isWindowExists && internalWindow['HTMLElement']); // we are in electron of nw, so we are both browser and nodejs 929// Make sure to access `process` through `_global` so that WebPack does not accidentally browserify 930// this code. 931 932const isMix = typeof _global.process !== 'undefined' && {}.toString.call(_global.process) === '[object process]' && !isWebWorker && !!(isWindowExists && internalWindow['HTMLElement']); 933const zoneSymbolEventNames$1 = {}; 934 935const wrapFn = function (event) { 936 // https://github.com/angular/zone.js/issues/911, in IE, sometimes 937 // event will be undefined, so we need to use window.event 938 event = event || _global.event; 939 940 if (!event) { 941 return; 942 } 943 944 let eventNameSymbol = zoneSymbolEventNames$1[event.type]; 945 946 if (!eventNameSymbol) { 947 eventNameSymbol = zoneSymbolEventNames$1[event.type] = zoneSymbol('ON_PROPERTY' + event.type); 948 } 949 950 const target = this || event.target || _global; 951 const listener = target[eventNameSymbol]; 952 let result; 953 954 if (isBrowser && target === internalWindow && event.type === 'error') { 955 // window.onerror have different signature 956 // https://developer.mozilla.org/en-US/docs/Web/API/GlobalEventHandlers/onerror#window.onerror 957 // and onerror callback will prevent default when callback return true 958 const errorEvent = event; 959 result = listener && listener.call(this, errorEvent.message, errorEvent.filename, errorEvent.lineno, errorEvent.colno, errorEvent.error); 960 961 if (result === true) { 962 event.preventDefault(); 963 } 964 } else { 965 result = listener && listener.apply(this, arguments); 966 967 if (result != undefined && !result) { 968 event.preventDefault(); 969 } 970 } 971 972 return result; 973}; 974 975function patchProperty(obj, prop, prototype) { 976 let desc = ObjectGetOwnPropertyDescriptor(obj, prop); 977 978 if (!desc && prototype) { 979 // when patch window object, use prototype to check prop exist or not
vendor: 55,207 bytes, lines 980-2716
980 const prototypeDesc = ObjectGetOwnPropertyDescriptor(prototype, prop); 981 982 if (prototypeDesc) { 983 desc = { 984 enumerable: true, 985 configurable: true 986 }; 987 } 988 } // if the descriptor not exists or is not configurable 989 // just return 990 991 992 if (!desc || !desc.configurable) { 993 return; 994 } 995 996 const onPropPatchedSymbol = zoneSymbol('on' + prop + 'patched'); 997 998 if (obj.hasOwnProperty(onPropPatchedSymbol) && obj[onPropPatchedSymbol]) { 999 return; 1000 } // A property descriptor cannot have getter/setter and be writable 1001 // deleting the writable and value properties avoids this error: 1002 // 1003 // TypeError: property descriptors must not specify a value or be writable when a 1004 // getter or setter has been specified 1005 1006 1007 delete desc.writable; 1008 delete desc.value; 1009 const originalDescGet = desc.get; 1010 const originalDescSet = desc.set; // slice(2) cuz 'onclick' -> 'click', etc 1011 1012 const eventName = prop.slice(2); 1013 let eventNameSymbol = zoneSymbolEventNames$1[eventName]; 1014 1015 if (!eventNameSymbol) { 1016 eventNameSymbol = zoneSymbolEventNames$1[eventName] = zoneSymbol('ON_PROPERTY' + eventName); 1017 } 1018 1019 desc.set = function (newValue) { 1020 // in some of windows's onproperty callback, this is undefined 1021 // so we need to check it 1022 let target = this; 1023 1024 if (!target && obj === _global) { 1025 target = _global; 1026 } 1027 1028 if (!target) { 1029 return; 1030 } 1031 1032 const previousValue = target[eventNameSymbol]; 1033 1034 if (typeof previousValue === 'function') { 1035 target.removeEventListener(eventName, wrapFn); 1036 } // issue #978, when onload handler was added before loading zone.js 1037 // we should remove it with originalDescSet 1038 1039 1040 originalDescSet && originalDescSet.call(target, null); 1041 target[eventNameSymbol] = newValue; 1042 1043 if (typeof newValue === 'function') { 1044 target.addEventListener(eventName, wrapFn, false); 1045 } 1046 }; // The getter would return undefined for unassigned properties but the default value of an 1047 // unassigned property is null 1048 1049 1050 desc.get = function () { 1051 // in some of windows's onproperty callback, this is undefined 1052 // so we need to check it 1053 let target = this; 1054 1055 if (!target && obj === _global) { 1056 target = _global; 1057 } 1058 1059 if (!target) { 1060 return null; 1061 } 1062 1063 const listener = target[eventNameSymbol]; 1064 1065 if (listener) { 1066 return listener; 1067 } else if (originalDescGet) { 1068 // result will be null when use inline event attribute, 1069 // such as <button onclick="func();">OK</button> 1070 // because the onclick function is internal raw uncompiled handler 1071 // the onclick will be evaluated when first time event was triggered or 1072 // the property is accessed, https://github.com/angular/zone.js/issues/525 1073 // so we should use original native get to retrieve the handler 1074 let value = originalDescGet.call(this); 1075 1076 if (value) { 1077 desc.set.call(this, value); 1078 1079 if (typeof target[REMOVE_ATTRIBUTE] === 'function') { 1080 target.removeAttribute(prop); 1081 } 1082 1083 return value; 1084 } 1085 } 1086 1087 return null; 1088 }; 1089 1090 ObjectDefineProperty(obj, prop, desc); 1091 obj[onPropPatchedSymbol] = true; 1092} 1093 1094function patchOnProperties(obj, properties, prototype) { 1095 if (properties) { 1096 for (let i = 0; i < properties.length; i++) { 1097 patchProperty(obj, 'on' + properties[i], prototype); 1098 } 1099 } else { 1100 const onProperties = []; 1101 1102 for (const prop in obj) { 1103 if (prop.slice(0, 2) == 'on') { 1104 onProperties.push(prop); 1105 } 1106 } 1107 1108 for (let j = 0; j < onProperties.length; j++) { 1109 patchProperty(obj, onProperties[j], prototype); 1110 } 1111 } 1112} 1113 1114const originalInstanceKey = zoneSymbol('originalInstance'); // wrap some native API on `window` 1115 1116function patchClass(className) { 1117 const OriginalClass = _global[className]; 1118 if (!OriginalClass) return; // keep original class in global 1119 1120 _global[zoneSymbol(className)] = OriginalClass; 1121 1122 _global[className] = function () { 1123 const a = bindArguments(arguments, className); 1124 1125 switch (a.length) { 1126 case 0: 1127 this[originalInstanceKey] = new OriginalClass(); 1128 break; 1129 1130 case 1: 1131 this[originalInstanceKey] = new OriginalClass(a[0]); 1132 break; 1133 1134 case 2: 1135 this[originalInstanceKey] = new OriginalClass(a[0], a[1]); 1136 break; 1137 1138 case 3: 1139 this[originalInstanceKey] = new OriginalClass(a[0], a[1], a[2]); 1140 break; 1141 1142 case 4: 1143 this[originalInstanceKey] = new OriginalClass(a[0], a[1], a[2], a[3]); 1144 break; 1145 1146 default: 1147 throw new Error('Arg list too long.'); 1148 } 1149 }; // attach original delegate to patched function 1150 1151 1152 attachOriginToPatched(_global[className], OriginalClass); 1153 const instance = new OriginalClass(function () {}); 1154 let prop; 1155 1156 for (prop in instance) { 1157 // https://bugs.webkit.org/show_bug.cgi?id=44721 1158 if (className === 'XMLHttpRequest' && prop === 'responseBlob') continue; 1159 1160 (function (prop) { 1161 if (typeof instance[prop] === 'function') { 1162 _global[className].prototype[prop] = function () { 1163 return this[originalInstanceKey][prop].apply(this[originalInstanceKey], arguments); 1164 }; 1165 } else { 1166 ObjectDefineProperty(_global[className].prototype, prop, { 1167 set: function (fn) { 1168 if (typeof fn === 'function') { 1169 this[originalInstanceKey][prop] = wrapWithCurrentZone(fn, className + '.' + prop); // keep callback in wrapped function so we can 1170 // use it in Function.prototype.toString to return 1171 // the native one. 1172 1173 attachOriginToPatched(this[originalInstanceKey][prop], fn); 1174 } else { 1175 this[originalInstanceKey][prop] = fn; 1176 } 1177 }, 1178 get: function () { 1179 return this[originalInstanceKey][prop]; 1180 } 1181 }); 1182 } 1183 })(prop); 1184 } 1185 1186 for (prop in OriginalClass) { 1187 if (prop !== 'prototype' && OriginalClass.hasOwnProperty(prop)) { 1188 _global[className][prop] = OriginalClass[prop]; 1189 } 1190 } 1191} 1192 1193function patchMethod(target, name, patchFn) { 1194 let proto = target; 1195 1196 while (proto && !proto.hasOwnProperty(name)) { 1197 proto = ObjectGetPrototypeOf(proto); 1198 } 1199 1200 if (!proto && target[name]) { 1201 // somehow we did not find it, but we can see it. This happens on IE for Window properties. 1202 proto = target; 1203 } 1204 1205 const delegateName = zoneSymbol(name); 1206 let delegate = null; 1207 1208 if (proto && (!(delegate = proto[delegateName]) || !proto.hasOwnProperty(delegateName))) { 1209 delegate = proto[delegateName] = proto[name]; // check whether proto[name] is writable 1210 // some property is readonly in safari, such as HtmlCanvasElement.prototype.toBlob 1211 1212 const desc = proto && ObjectGetOwnPropertyDescriptor(proto, name); 1213 1214 if (isPropertyWritable(desc)) { 1215 const patchDelegate = patchFn(delegate, delegateName, name); 1216 1217 proto[name] = function () { 1218 return patchDelegate(this, arguments); 1219 }; 1220 1221 attachOriginToPatched(proto[name], delegate); 1222 } 1223 } 1224 1225 return delegate; 1226} // TODO: @JiaLiPassion, support cancel task later if necessary 1227 1228 1229function patchMacroTask(obj, funcName, metaCreator) { 1230 let setNative = null; 1231 1232 function scheduleTask(task) { 1233 const data = task.data; 1234 1235 data.args[data.cbIdx] = function () { 1236 task.invoke.apply(this, arguments); 1237 }; 1238 1239 setNative.apply(data.target, data.args); 1240 return task; 1241 } 1242 1243 setNative = patchMethod(obj, funcName, delegate => function (self, args) { 1244 const meta = metaCreator(self, args); 1245 1246 if (meta.cbIdx >= 0 && typeof args[meta.cbIdx] === 'function') { 1247 return scheduleMacroTaskWithCurrentZone(meta.name, args[meta.cbIdx], meta, scheduleTask); 1248 } else { 1249 // cause an error by calling it directly. 1250 return delegate.apply(self, args); 1251 } 1252 }); 1253} 1254 1255function attachOriginToPatched(patched, original) { 1256 patched[zoneSymbol('OriginalDelegate')] = original; 1257} 1258 1259let isDetectedIEOrEdge = false; 1260let ieOrEdge = false; 1261 1262function isIE() { 1263 try { 1264 const ua = internalWindow.navigator.userAgent; 1265 1266 if (ua.indexOf('MSIE ') !== -1 || ua.indexOf('Trident/') !== -1) { 1267 return true; 1268 } 1269 } catch (error) {} 1270 1271 return false; 1272} 1273 1274function isIEOrEdge() { 1275 if (isDetectedIEOrEdge) { 1276 return ieOrEdge; 1277 } 1278 1279 isDetectedIEOrEdge = true; 1280 1281 try { 1282 const ua = internalWindow.navigator.userAgent; 1283 1284 if (ua.indexOf('MSIE ') !== -1 || ua.indexOf('Trident/') !== -1 || ua.indexOf('Edge/') !== -1) { 1285 ieOrEdge = true; 1286 } 1287 } catch (error) {} 1288 1289 return ieOrEdge; 1290} 1291/** 1292 * @license 1293 * Copyright Google LLC All Rights Reserved. 1294 * 1295 * Use of this source code is governed by an MIT-style license that can be 1296 * found in the LICENSE file at https://angular.io/license 1297 */ 1298 1299 1300Zone.__load_patch('ZoneAwarePromise', (global, Zone, api) => { 1301 const ObjectGetOwnPropertyDescriptor = Object.getOwnPropertyDescriptor; 1302 const ObjectDefineProperty = Object.defineProperty; 1303 1304 function readableObjectToString(obj) { 1305 if (obj && obj.toString === Object.prototype.toString) { 1306 const className = obj.constructor && obj.constructor.name; 1307 return (className ? className : '') + ': ' + JSON.stringify(obj); 1308 } 1309 1310 return obj ? obj.toString() : Object.prototype.toString.call(obj); 1311 } 1312 1313 const __symbol__ = api.symbol; 1314 const _uncaughtPromiseErrors = []; 1315 const isDisableWrappingUncaughtPromiseRejection = global[__symbol__('DISABLE_WRAPPING_UNCAUGHT_PROMISE_REJECTION')] === true; 1316 1317 const symbolPromise = __symbol__('Promise'); 1318 1319 const symbolThen = __symbol__('then'); 1320 1321 const creationTrace = '__creationTrace__'; 1322 1323 api.onUnhandledError = e => { 1324 if (api.showUncaughtError()) { 1325 const rejection = e && e.rejection; 1326 1327 if (rejection) { 1328 console.error('Unhandled Promise rejection:', rejection instanceof Error ? rejection.message : rejection, '; Zone:', e.zone.name, '; Task:', e.task && e.task.source, '; Value:', rejection, rejection instanceof Error ? rejection.stack : undefined); 1329 } else { 1330 console.error(e); 1331 } 1332 } 1333 }; 1334 1335 api.microtaskDrainDone = () => { 1336 while (_uncaughtPromiseErrors.length) { 1337 const uncaughtPromiseError = _uncaughtPromiseErrors.shift(); 1338 1339 try { 1340 uncaughtPromiseError.zone.runGuarded(() => { 1341 if (uncaughtPromiseError.throwOriginal) { 1342 throw uncaughtPromiseError.rejection; 1343 } 1344 1345 throw uncaughtPromiseError; 1346 }); 1347 } catch (error) { 1348 handleUnhandledRejection(error); 1349 } 1350 } 1351 }; 1352 1353 const UNHANDLED_PROMISE_REJECTION_HANDLER_SYMBOL = __symbol__('unhandledPromiseRejectionHandler'); 1354 1355 function handleUnhandledRejection(e) { 1356 api.onUnhandledError(e); 1357 1358 try { 1359 const handler = Zone[UNHANDLED_PROMISE_REJECTION_HANDLER_SYMBOL]; 1360 1361 if (typeof handler === 'function') { 1362 handler.call(this, e); 1363 } 1364 } catch (err) {} 1365 } 1366 1367 function isThenable(value) { 1368 return value && value.then; 1369 } 1370 1371 function forwardResolution(value) { 1372 return value; 1373 } 1374 1375 function forwardRejection(rejection) { 1376 return ZoneAwarePromise.reject(rejection); 1377 } 1378 1379 const symbolState = __symbol__('state'); 1380 1381 const symbolValue = __symbol__('value'); 1382 1383 const symbolFinally = __symbol__('finally'); 1384 1385 const symbolParentPromiseValue = __symbol__('parentPromiseValue'); 1386 1387 const symbolParentPromiseState = __symbol__('parentPromiseState'); 1388 1389 const source = 'Promise.then'; 1390 const UNRESOLVED = null; 1391 const RESOLVED = true; 1392 const REJECTED = false; 1393 const REJECTED_NO_CATCH = 0; 1394 1395 function makeResolver(promise, state) { 1396 return v => { 1397 try { 1398 resolvePromise(promise, state, v); 1399 } catch (err) { 1400 resolvePromise(promise, false, err); 1401 } // Do not return value or you will break the Promise spec. 1402 1403 }; 1404 } 1405 1406 const once = function () { 1407 let wasCalled = false; 1408 return function wrapper(wrappedFunction) { 1409 return function () { 1410 if (wasCalled) { 1411 return; 1412 } 1413 1414 wasCalled = true; 1415 wrappedFunction.apply(null, arguments); 1416 }; 1417 }; 1418 }; 1419 1420 const TYPE_ERROR = 'Promise resolved with itself'; 1421 1422 const CURRENT_TASK_TRACE_SYMBOL = __symbol__('currentTaskTrace'); // Promise Resolution 1423 1424 1425 function resolvePromise(promise, state, value) { 1426 const onceWrapper = once(); 1427 1428 if (promise === value) { 1429 throw new TypeError(TYPE_ERROR); 1430 } 1431 1432 if (promise[symbolState] === UNRESOLVED) { 1433 // should only get value.then once based on promise spec. 1434 let then = null; 1435 1436 try { 1437 if (typeof value === 'object' || typeof value === 'function') { 1438 then = value && value.then; 1439 } 1440 } catch (err) { 1441 onceWrapper(() => { 1442 resolvePromise(promise, false, err); 1443 })(); 1444 return promise; 1445 } // if (value instanceof ZoneAwarePromise) { 1446 1447 1448 if (state !== REJECTED && value instanceof ZoneAwarePromise && value.hasOwnProperty(symbolState) && value.hasOwnProperty(symbolValue) && value[symbolState] !== UNRESOLVED) { 1449 clearRejectedNoCatch(value); 1450 resolvePromise(promise, value[symbolState], value[symbolValue]); 1451 } else if (state !== REJECTED && typeof then === 'function') { 1452 try { 1453 then.call(value, onceWrapper(makeResolver(promise, state)), onceWrapper(makeResolver(promise, false))); 1454 } catch (err) { 1455 onceWrapper(() => { 1456 resolvePromise(promise, false, err); 1457 })(); 1458 } 1459 } else { 1460 promise[symbolState] = state; 1461 const queue = promise[symbolValue]; 1462 promise[symbolValue] = value; 1463 1464 if (promise[symbolFinally] === symbolFinally) { 1465 // the promise is generated by Promise.prototype.finally 1466 if (state === RESOLVED) { 1467 // the state is resolved, should ignore the value 1468 // and use parent promise value 1469 promise[symbolState] = promise[symbolParentPromiseState]; 1470 promise[symbolValue] = promise[symbolParentPromiseValue]; 1471 } 1472 } // record task information in value when error occurs, so we can 1473 // do some additional work such as render longStackTrace 1474 1475 1476 if (state === REJECTED && value instanceof Error) { 1477 // check if longStackTraceZone is here 1478 const trace = Zone.currentTask && Zone.currentTask.data && Zone.currentTask.data[creationTrace]; 1479 1480 if (trace) { 1481 // only keep the long stack trace into error when in longStackTraceZone 1482 ObjectDefineProperty(value, CURRENT_TASK_TRACE_SYMBOL, { 1483 configurable: true, 1484 enumerable: false, 1485 writable: true, 1486 value: trace 1487 }); 1488 } 1489 } 1490 1491 for (let i = 0; i < queue.length;) { 1492 scheduleResolveOrReject(promise, queue[i++], queue[i++], queue[i++], queue[i++]); 1493 } 1494 1495 if (queue.length == 0 && state == REJECTED) { 1496 promise[symbolState] = REJECTED_NO_CATCH; 1497 let uncaughtPromiseError = value; 1498 1499 try { 1500 // Here we throws a new Error to print more readable error log 1501 // and if the value is not an error, zone.js builds an `Error` 1502 // Object here to attach the stack information. 1503 throw new Error('Uncaught (in promise): ' + readableObjectToString(value) + (value && value.stack ? '\n' + value.stack : '')); 1504 } catch (err) { 1505 uncaughtPromiseError = err; 1506 } 1507 1508 if (isDisableWrappingUncaughtPromiseRejection) { 1509 // If disable wrapping uncaught promise reject 1510 // use the value instead of wrapping it. 1511 uncaughtPromiseError.throwOriginal = true; 1512 } 1513 1514 uncaughtPromiseError.rejection = value; 1515 uncaughtPromiseError.promise = promise; 1516 uncaughtPromiseError.zone = Zone.current; 1517 uncaughtPromiseError.task = Zone.currentTask; 1518 1519 _uncaughtPromiseErrors.push(uncaughtPromiseError); 1520 1521 api.scheduleMicroTask(); // to make sure that it is running 1522 } 1523 } 1524 } // Resolving an already resolved promise is a noop. 1525 1526 1527 return promise; 1528 } 1529 1530 const REJECTION_HANDLED_HANDLER = __symbol__('rejectionHandledHandler'); 1531 1532 function clearRejectedNoCatch(promise) { 1533 if (promise[symbolState] === REJECTED_NO_CATCH) { 1534 // if the promise is rejected no catch status 1535 // and queue.length > 0, means there is a error handler 1536 // here to handle the rejected promise, we should trigger 1537 // windows.rejectionhandled eventHandler or nodejs rejectionHandled 1538 // eventHandler 1539 try { 1540 const handler = Zone[REJECTION_HANDLED_HANDLER]; 1541 1542 if (handler && typeof handler === 'function') { 1543 handler.call(this, { 1544 rejection: promise[symbolValue], 1545 promise: promise 1546 }); 1547 } 1548 } catch (err) {} 1549 1550 promise[symbolState] = REJECTED; 1551 1552 for (let i = 0; i < _uncaughtPromiseErrors.length; i++) { 1553 if (promise === _uncaughtPromiseErrors[i].promise) { 1554 _uncaughtPromiseErrors.splice(i, 1); 1555 } 1556 } 1557 } 1558 } 1559 1560 function scheduleResolveOrReject(promise, zone, chainPromise, onFulfilled, onRejected) { 1561 clearRejectedNoCatch(promise); 1562 const promiseState = promise[symbolState]; 1563 const delegate = promiseState ? typeof onFulfilled === 'function' ? onFulfilled : forwardResolution : typeof onRejected === 'function' ? onRejected : forwardRejection; 1564 zone.scheduleMicroTask(source, () => { 1565 try { 1566 const parentPromiseValue = promise[symbolValue]; 1567 const isFinallyPromise = !!chainPromise && symbolFinally === chainPromise[symbolFinally]; 1568 1569 if (isFinallyPromise) { 1570 // if the promise is generated from finally call, keep parent promise's state and value 1571 chainPromise[symbolParentPromiseValue] = parentPromiseValue; 1572 chainPromise[symbolParentPromiseState] = promiseState; 1573 } // should not pass value to finally callback 1574 1575 1576 const value = zone.run(delegate, undefined, isFinallyPromise && delegate !== forwardRejection && delegate !== forwardResolution ? [] : [parentPromiseValue]); 1577 resolvePromise(chainPromise, true, value); 1578 } catch (error) { 1579 // if error occurs, should always return this error 1580 resolvePromise(chainPromise, false, error); 1581 } 1582 }, chainPromise); 1583 } 1584 1585 const ZONE_AWARE_PROMISE_TO_STRING = 'function ZoneAwarePromise() { [native code] }'; 1586 1587 const noop = function () {}; 1588 1589 const AggregateError = global.AggregateError; 1590 1591 class ZoneAwarePromise { 1592 static toString() { 1593 return ZONE_AWARE_PROMISE_TO_STRING; 1594 } 1595 1596 static resolve(value) { 1597 return resolvePromise(new this(null), RESOLVED, value); 1598 } 1599 1600 static reject(error) { 1601 return resolvePromise(new this(null), REJECTED, error); 1602 } 1603 1604 static any(values) { 1605 if (!values || typeof values[Symbol.iterator] !== 'function') { 1606 return Promise.reject(new AggregateError([], 'All promises were rejected')); 1607 } 1608 1609 const promises = []; 1610 let count = 0; 1611 1612 try { 1613 for (let v of values) { 1614 count++; 1615 promises.push(ZoneAwarePromise.resolve(v)); 1616 } 1617 } catch (err) { 1618 return Promise.reject(new AggregateError([], 'All promises were rejected')); 1619 } 1620 1621 if (count === 0) { 1622 return Promise.reject(new AggregateError([], 'All promises were rejected')); 1623 } 1624 1625 let finished = false; 1626 const errors = []; 1627 return new ZoneAwarePromise((resolve, reject) => { 1628 for (let i = 0; i < promises.length; i++) { 1629 promises[i].then(v => { 1630 if (finished) { 1631 return; 1632 } 1633 1634 finished = true; 1635 resolve(v); 1636 }, err => { 1637 errors.push(err); 1638 count--; 1639 1640 if (count === 0) { 1641 finished = true; 1642 reject(new AggregateError(errors, 'All promises were rejected')); 1643 } 1644 }); 1645 } 1646 }); 1647 } 1648 1649 static race(values) { 1650 let resolve; 1651 let reject; 1652 let promise = new this((res, rej) => { 1653 resolve = res; 1654 reject = rej; 1655 }); 1656 1657 function onResolve(value) { 1658 resolve(value); 1659 } 1660 1661 function onReject(error) { 1662 reject(error); 1663 } 1664 1665 for (let value of values) { 1666 if (!isThenable(value)) { 1667 value = this.resolve(value); 1668 } 1669 1670 value.then(onResolve, onReject); 1671 } 1672 1673 return promise; 1674 } 1675 1676 static all(values) { 1677 return ZoneAwarePromise.allWithCallback(values); 1678 } 1679 1680 static allSettled(values) { 1681 const P = this && this.prototype instanceof ZoneAwarePromise ? this : ZoneAwarePromise; 1682 return P.allWithCallback(values, { 1683 thenCallback: value => ({ 1684 status: 'fulfilled', 1685 value 1686 }), 1687 errorCallback: err => ({ 1688 status: 'rejected', 1689 reason: err 1690 }) 1691 }); 1692 } 1693 1694 static allWithCallback(values, callback) { 1695 let resolve; 1696 let reject; 1697 let promise = new this((res, rej) => { 1698 resolve = res; 1699 reject = rej; 1700 }); // Start at 2 to prevent prematurely resolving if .then is called immediately. 1701 1702 let unresolvedCount = 2; 1703 let valueIndex = 0; 1704 const resolvedValues = []; 1705 1706 for (let value of values) { 1707 if (!isThenable(value)) { 1708 value = this.resolve(value); 1709 } 1710 1711 const curValueIndex = valueIndex; 1712 1713 try { 1714 value.then(value => { 1715 resolvedValues[curValueIndex] = callback ? callback.thenCallback(value) : value; 1716 unresolvedCount--; 1717 1718 if (unresolvedCount === 0) { 1719 resolve(resolvedValues); 1720 } 1721 }, err => { 1722 if (!callback) { 1723 reject(err); 1724 } else { 1725 resolvedValues[curValueIndex] = callback.errorCallback(err); 1726 unresolvedCount--; 1727 1728 if (unresolvedCount === 0) { 1729 resolve(resolvedValues); 1730 } 1731 } 1732 }); 1733 } catch (thenErr) { 1734 reject(thenErr); 1735 } 1736 1737 unresolvedCount++; 1738 valueIndex++; 1739 } // Make the unresolvedCount zero-based again. 1740 1741 1742 unresolvedCount -= 2; 1743 1744 if (unresolvedCount === 0) { 1745 resolve(resolvedValues); 1746 } 1747 1748 return promise; 1749 } 1750 1751 constructor(executor) { 1752 const promise = this; 1753 1754 if (!(promise instanceof ZoneAwarePromise)) { 1755 throw new Error('Must be an instanceof Promise.'); 1756 } 1757 1758 promise[symbolState] = UNRESOLVED; 1759 promise[symbolValue] = []; // queue; 1760 1761 try { 1762 const onceWrapper = once(); 1763 executor && executor(onceWrapper(makeResolver(promise, RESOLVED)), onceWrapper(makeResolver(promise, REJECTED))); 1764 } catch (error) { 1765 resolvePromise(promise, false, error); 1766 } 1767 } 1768 1769 get [Symbol.toStringTag]() { 1770 return 'Promise'; 1771 } 1772 1773 get [Symbol.species]() { 1774 return ZoneAwarePromise; 1775 } 1776 1777 then(onFulfilled, onRejected) { 1778 var _a; // We must read `Symbol.species` safely because `this` may be anything. For instance, `this` 1779 // may be an object without a prototype (created through `Object.create(null)`); thus 1780 // `this.constructor` will be undefined. One of the use cases is SystemJS creating 1781 // prototype-less objects (modules) via `Object.create(null)`. The SystemJS creates an empty 1782 // object and copies promise properties into that object (within the `getOrCreateLoad` 1783 // function). The zone.js then checks if the resolved value has the `then` method and invokes 1784 // it with the `value` context. Otherwise, this will throw an error: `TypeError: Cannot read 1785 // properties of undefined (reading 'Symbol(Symbol.species)')`. 1786 1787 1788 let C = (_a = this.constructor) === null || _a === void 0 ? void 0 : _a[Symbol.species]; 1789 1790 if (!C || typeof C !== 'function') { 1791 C = this.constructor || ZoneAwarePromise; 1792 } 1793 1794 const chainPromise = new C(noop); 1795 const zone = Zone.current; 1796 1797 if (this[symbolState] == UNRESOLVED) { 1798 this[symbolValue].push(zone, chainPromise, onFulfilled, onRejected); 1799 } else { 1800 scheduleResolveOrReject(this, zone, chainPromise, onFulfilled, onRejected); 1801 } 1802 1803 return chainPromise; 1804 } 1805 1806 catch(onRejected) { 1807 return this.then(null, onRejected); 1808 } 1809 1810 finally(onFinally) { 1811 var _a; // See comment on the call to `then` about why thee `Symbol.species` is safely accessed. 1812 1813 1814 let C = (_a = this.constructor) === null || _a === void 0 ? void 0 : _a[Symbol.species]; 1815 1816 if (!C || typeof C !== 'function') { 1817 C = ZoneAwarePromise; 1818 } 1819 1820 const chainPromise = new C(noop); 1821 chainPromise[symbolFinally] = symbolFinally; 1822 const zone = Zone.current; 1823 1824 if (this[symbolState] == UNRESOLVED) { 1825 this[symbolValue].push(zone, chainPromise, onFinally, onFinally); 1826 } else { 1827 scheduleResolveOrReject(this, zone, chainPromise, onFinally, onFinally); 1828 } 1829 1830 return chainPromise; 1831 } 1832 1833 } // Protect against aggressive optimizers dropping seemingly unused properties. 1834 // E.g. Closure Compiler in advanced mode. 1835 1836 1837 ZoneAwarePromise['resolve'] = ZoneAwarePromise.resolve; 1838 ZoneAwarePromise['reject'] = ZoneAwarePromise.reject; 1839 ZoneAwarePromise['race'] = ZoneAwarePromise.race; 1840 ZoneAwarePromise['all'] = ZoneAwarePromise.all; 1841 const NativePromise = global[symbolPromise] = global['Promise']; 1842 global['Promise'] = ZoneAwarePromise; 1843 1844 const symbolThenPatched = __symbol__('thenPatched'); 1845 1846 function patchThen(Ctor) { 1847 const proto = Ctor.prototype; 1848 const prop = ObjectGetOwnPropertyDescriptor(proto, 'then'); 1849 1850 if (prop && (prop.writable === false || !prop.configurable)) { 1851 // check Ctor.prototype.then propertyDescriptor is writable or not 1852 // in meteor env, writable is false, we should ignore such case 1853 return; 1854 } 1855 1856 const originalThen = proto.then; // Keep a reference to the original method. 1857 1858 proto[symbolThen] = originalThen; 1859 1860 Ctor.prototype.then = function (onResolve, onReject) { 1861 const wrapped = new ZoneAwarePromise((resolve, reject) => { 1862 originalThen.call(this, resolve, reject); 1863 }); 1864 return wrapped.then(onResolve, onReject); 1865 }; 1866 1867 Ctor[symbolThenPatched] = true; 1868 } 1869 1870 api.patchThen = patchThen; 1871 1872 function zoneify(fn) { 1873 return function (self, args) { 1874 let resultPromise = fn.apply(self, args); 1875 1876 if (resultPromise instanceof ZoneAwarePromise) { 1877 return resultPromise; 1878 } 1879 1880 let ctor = resultPromise.constructor; 1881 1882 if (!ctor[symbolThenPatched]) { 1883 patchThen(ctor); 1884 } 1885 1886 return resultPromise; 1887 }; 1888 } 1889 1890 if (NativePromise) { 1891 patchThen(NativePromise); 1892 patchMethod(global, 'fetch', delegate => zoneify(delegate)); 1893 } // This is not part of public API, but it is useful for tests, so we expose it. 1894 1895 1896 Promise[Zone.__symbol__('uncaughtPromiseErrors')] = _uncaughtPromiseErrors; 1897 return ZoneAwarePromise; 1898}); 1899/** 1900 * @license 1901 * Copyright Google LLC All Rights Reserved. 1902 * 1903 * Use of this source code is governed by an MIT-style license that can be 1904 * found in the LICENSE file at https://angular.io/license 1905 */ 1906// override Function.prototype.toString to make zone.js patched function 1907// look like native function 1908 1909 1910Zone.__load_patch('toString', global => { 1911 // patch Func.prototype.toString to let them look like native 1912 const originalFunctionToString = Function.prototype.toString; 1913 const ORIGINAL_DELEGATE_SYMBOL = zoneSymbol('OriginalDelegate'); 1914 const PROMISE_SYMBOL = zoneSymbol('Promise'); 1915 const ERROR_SYMBOL = zoneSymbol('Error'); 1916 1917 const newFunctionToString = function toString() { 1918 if (typeof this === 'function') { 1919 const originalDelegate = this[ORIGINAL_DELEGATE_SYMBOL]; 1920 1921 if (originalDelegate) { 1922 if (typeof originalDelegate === 'function') { 1923 return originalFunctionToString.call(originalDelegate); 1924 } else { 1925 return Object.prototype.toString.call(originalDelegate); 1926 } 1927 } 1928 1929 if (this === Promise) { 1930 const nativePromise = global[PROMISE_SYMBOL]; 1931 1932 if (nativePromise) { 1933 return originalFunctionToString.call(nativePromise); 1934 } 1935 } 1936 1937 if (this === Error) { 1938 const nativeError = global[ERROR_SYMBOL]; 1939 1940 if (nativeError) { 1941 return originalFunctionToString.call(nativeError); 1942 } 1943 } 1944 } 1945 1946 return originalFunctionToString.call(this); 1947 }; 1948 1949 newFunctionToString[ORIGINAL_DELEGATE_SYMBOL] = originalFunctionToString; 1950 Function.prototype.toString = newFunctionToString; // patch Object.prototype.toString to let them look like native 1951 1952 const originalObjectToString = Object.prototype.toString; 1953 const PROMISE_OBJECT_TO_STRING = '[object Promise]'; 1954 1955 Object.prototype.toString = function () { 1956 if (typeof Promise === 'function' && this instanceof Promise) { 1957 return PROMISE_OBJECT_TO_STRING; 1958 } 1959 1960 return originalObjectToString.call(this); 1961 }; 1962}); 1963/** 1964 * @license 1965 * Copyright Google LLC All Rights Reserved. 1966 * 1967 * Use of this source code is governed by an MIT-style license that can be 1968 * found in the LICENSE file at https://angular.io/license 1969 */ 1970 1971 1972let passiveSupported = false; 1973 1974if (typeof window !== 'undefined') { 1975 try { 1976 const options = Object.defineProperty({}, 'passive', { 1977 get: function () { 1978 passiveSupported = true; 1979 } 1980 }); // Note: We pass the `options` object as the event handler too. This is not compatible with the 1981 // signature of `addEventListener` or `removeEventListener` but enables us to remove the handler 1982 // without an actual handler. 1983 1984 window.addEventListener('test', options, options); 1985 window.removeEventListener('test', options, options); 1986 } catch (err) { 1987 passiveSupported = false; 1988 } 1989} // an identifier to tell ZoneTask do not create a new invoke closure 1990 1991 1992const OPTIMIZED_ZONE_EVENT_TASK_DATA = { 1993 useG: true 1994}; 1995const zoneSymbolEventNames = {}; 1996const globalSources = {}; 1997const EVENT_NAME_SYMBOL_REGX = new RegExp('^' + ZONE_SYMBOL_PREFIX + '(\\w+)(true|false)$'); 1998const IMMEDIATE_PROPAGATION_SYMBOL = zoneSymbol('propagationStopped'); 1999 2000function prepareEventNames(eventName, eventNameToString) { 2001 const falseEventName = (eventNameToString ? eventNameToString(eventName) : eventName) + FALSE_STR; 2002 const trueEventName = (eventNameToString ? eventNameToString(eventName) : eventName) + TRUE_STR; 2003 const symbol = ZONE_SYMBOL_PREFIX + falseEventName; 2004 const symbolCapture = ZONE_SYMBOL_PREFIX + trueEventName; 2005 zoneSymbolEventNames[eventName] = {}; 2006 zoneSymbolEventNames[eventName][FALSE_STR] = symbol; 2007 zoneSymbolEventNames[eventName][TRUE_STR] = symbolCapture; 2008} 2009 2010function patchEventTarget(_global, api, apis, patchOptions) { 2011 const ADD_EVENT_LISTENER = patchOptions && patchOptions.add || ADD_EVENT_LISTENER_STR; 2012 const REMOVE_EVENT_LISTENER = patchOptions && patchOptions.rm || REMOVE_EVENT_LISTENER_STR; 2013 const LISTENERS_EVENT_LISTENER = patchOptions && patchOptions.listeners || 'eventListeners'; 2014 const REMOVE_ALL_LISTENERS_EVENT_LISTENER = patchOptions && patchOptions.rmAll || 'removeAllListeners'; 2015 const zoneSymbolAddEventListener = zoneSymbol(ADD_EVENT_LISTENER); 2016 const ADD_EVENT_LISTENER_SOURCE = '.' + ADD_EVENT_LISTENER + ':'; 2017 const PREPEND_EVENT_LISTENER = 'prependListener'; 2018 const PREPEND_EVENT_LISTENER_SOURCE = '.' + PREPEND_EVENT_LISTENER + ':'; 2019 2020 const invokeTask = function (task, target, event) { 2021 // for better performance, check isRemoved which is set 2022 // by removeEventListener 2023 if (task.isRemoved) { 2024 return; 2025 } 2026 2027 const delegate = task.callback; 2028 2029 if (typeof delegate === 'object' && delegate.handleEvent) { 2030 // create the bind version of handleEvent when invoke 2031 task.callback = event => delegate.handleEvent(event); 2032 2033 task.originalDelegate = delegate; 2034 } // invoke static task.invoke 2035 // need to try/catch error here, otherwise, the error in one event listener 2036 // will break the executions of the other event listeners. Also error will 2037 // not remove the event listener when `once` options is true. 2038 2039 2040 let error; 2041 2042 try { 2043 task.invoke(task, target, [event]); 2044 } catch (err) { 2045 error = err; 2046 } 2047 2048 const options = task.options; 2049 2050 if (options && typeof options === 'object' && options.once) { 2051 // if options.once is true, after invoke once remove listener here 2052 // only browser need to do this, nodejs eventEmitter will cal removeListener 2053 // inside EventEmitter.once 2054 const delegate = task.originalDelegate ? task.originalDelegate : task.callback; 2055 target[REMOVE_EVENT_LISTENER].call(target, event.type, delegate, options); 2056 } 2057 2058 return error; 2059 }; 2060 2061 function globalCallback(context, event, isCapture) { 2062 // https://github.com/angular/zone.js/issues/911, in IE, sometimes 2063 // event will be undefined, so we need to use window.event 2064 event = event || _global.event; 2065 2066 if (!event) { 2067 return; 2068 } // event.target is needed for Samsung TV and SourceBuffer 2069 // || global is needed https://github.com/angular/zone.js/issues/190 2070 2071 2072 const target = context || event.target || _global; 2073 const tasks = target[zoneSymbolEventNames[event.type][isCapture ? TRUE_STR : FALSE_STR]]; 2074 2075 if (tasks) { 2076 const errors = []; // invoke all tasks which attached to current target with given event.type and capture = false 2077 // for performance concern, if task.length === 1, just invoke 2078 2079 if (tasks.length === 1) { 2080 const err = invokeTask(tasks[0], target, event); 2081 err && errors.push(err); 2082 } else { 2083 // https://github.com/angular/zone.js/issues/836 2084 // copy the tasks array before invoke, to avoid 2085 // the callback will remove itself or other listener 2086 const copyTasks = tasks.slice(); 2087 2088 for (let i = 0; i < copyTasks.length; i++) { 2089 if (event && event[IMMEDIATE_PROPAGATION_SYMBOL] === true) { 2090 break; 2091 } 2092 2093 const err = invokeTask(copyTasks[i], target, event); 2094 err && errors.push(err); 2095 } 2096 } // Since there is only one error, we don't need to schedule microTask 2097 // to throw the error. 2098 2099 2100 if (errors.length === 1) { 2101 throw errors[0]; 2102 } else { 2103 for (let i = 0; i < errors.length; i++) { 2104 const err = errors[i]; 2105 api.nativeScheduleMicroTask(() => { 2106 throw err; 2107 }); 2108 } 2109 } 2110 } 2111 } // global shared zoneAwareCallback to handle all event callback with capture = false 2112 2113 2114 const globalZoneAwareCallback = function (event) { 2115 return globalCallback(this, event, false); 2116 }; // global shared zoneAwareCallback to handle all event callback with capture = true 2117 2118 2119 const globalZoneAwareCaptureCallback = function (event) { 2120 return globalCallback(this, event, true); 2121 }; 2122 2123 function patchEventTargetMethods(obj, patchOptions) { 2124 if (!obj) { 2125 return false; 2126 } 2127 2128 let useGlobalCallback = true; 2129 2130 if (patchOptions && patchOptions.useG !== undefined) { 2131 useGlobalCallback = patchOptions.useG; 2132 } 2133 2134 const validateHandler = patchOptions && patchOptions.vh; 2135 let checkDuplicate = true; 2136 2137 if (patchOptions && patchOptions.chkDup !== undefined) { 2138 checkDuplicate = patchOptions.chkDup; 2139 } 2140 2141 let returnTarget = false; 2142 2143 if (patchOptions && patchOptions.rt !== undefined) { 2144 returnTarget = patchOptions.rt; 2145 } 2146 2147 let proto = obj; 2148 2149 while (proto && !proto.hasOwnProperty(ADD_EVENT_LISTENER)) { 2150 proto = ObjectGetPrototypeOf(proto); 2151 } 2152 2153 if (!proto && obj[ADD_EVENT_LISTENER]) { 2154 // somehow we did not find it, but we can see it. This happens on IE for Window properties. 2155 proto = obj; 2156 } 2157 2158 if (!proto) { 2159 return false; 2160 } 2161 2162 if (proto[zoneSymbolAddEventListener]) { 2163 return false; 2164 } 2165 2166 const eventNameToString = patchOptions && patchOptions.eventNameToString; // a shared global taskData to pass data for scheduleEventTask 2167 // so we do not need to create a new object just for pass some data 2168 2169 const taskData = {}; 2170 const nativeAddEventListener = proto[zoneSymbolAddEventListener] = proto[ADD_EVENT_LISTENER]; 2171 const nativeRemoveEventListener = proto[zoneSymbol(REMOVE_EVENT_LISTENER)] = proto[REMOVE_EVENT_LISTENER]; 2172 const nativeListeners = proto[zoneSymbol(LISTENERS_EVENT_LISTENER)] = proto[LISTENERS_EVENT_LISTENER]; 2173 const nativeRemoveAllListeners = proto[zoneSymbol(REMOVE_ALL_LISTENERS_EVENT_LISTENER)] = proto[REMOVE_ALL_LISTENERS_EVENT_LISTENER]; 2174 let nativePrependEventListener; 2175 2176 if (patchOptions && patchOptions.prepend) { 2177 nativePrependEventListener = proto[zoneSymbol(patchOptions.prepend)] = proto[patchOptions.prepend]; 2178 } 2179 /** 2180 * This util function will build an option object with passive option 2181 * to handle all possible input from the user. 2182 */ 2183 2184 2185 function buildEventListenerOptions(options, passive) { 2186 if (!passiveSupported && typeof options === 'object' && options) { 2187 // doesn't support passive but user want to pass an object as options. 2188 // this will not work on some old browser, so we just pass a boolean 2189 // as useCapture parameter 2190 return !!options.capture; 2191 } 2192 2193 if (!passiveSupported || !passive) { 2194 return options; 2195 } 2196 2197 if (typeof options === 'boolean') { 2198 return { 2199 capture: options, 2200 passive: true 2201 }; 2202 } 2203 2204 if (!options) { 2205 return { 2206 passive: true 2207 }; 2208 } 2209 2210 if (typeof options === 'object' && options.passive !== false) { 2211 return Object.assign(Object.assign({}, options), { 2212 passive: true 2213 }); 2214 } 2215 2216 return options; 2217 } 2218 2219 const customScheduleGlobal = function (task) { 2220 // if there is already a task for the eventName + capture, 2221 // just return, because we use the shared globalZoneAwareCallback here. 2222 if (taskData.isExisting) { 2223 return; 2224 } 2225 2226 return nativeAddEventListener.call(taskData.target, taskData.eventName, taskData.capture ? globalZoneAwareCaptureCallback : globalZoneAwareCallback, taskData.options); 2227 }; 2228 2229 const customCancelGlobal = function (task) { 2230 // if task is not marked as isRemoved, this call is directly 2231 // from Zone.prototype.cancelTask, we should remove the task 2232 // from tasksList of target first 2233 if (!task.isRemoved) { 2234 const symbolEventNames = zoneSymbolEventNames[task.eventName]; 2235 let symbolEventName; 2236 2237 if (symbolEventNames) { 2238 symbolEventName = symbolEventNames[task.capture ? TRUE_STR : FALSE_STR]; 2239 } 2240 2241 const existingTasks = symbolEventName && task.target[symbolEventName]; 2242 2243 if (existingTasks) { 2244 for (let i = 0; i < existingTasks.length; i++) { 2245 const existingTask = existingTasks[i]; 2246 2247 if (existingTask === task) { 2248 existingTasks.splice(i, 1); // set isRemoved to data for faster invokeTask check 2249 2250 task.isRemoved = true; 2251 2252 if (existingTasks.length === 0) { 2253 // all tasks for the eventName + capture have gone, 2254 // remove globalZoneAwareCallback and remove the task cache from target 2255 task.allRemoved = true; 2256 task.target[symbolEventName] = null; 2257 } 2258 2259 break; 2260 } 2261 } 2262 } 2263 } // if all tasks for the eventName + capture have gone, 2264 // we will really remove the global event callback, 2265 // if not, return 2266 2267 2268 if (!task.allRemoved) { 2269 return; 2270 } 2271 2272 return nativeRemoveEventListener.call(task.target, task.eventName, task.capture ? globalZoneAwareCaptureCallback : globalZoneAwareCallback, task.options); 2273 }; 2274 2275 const customScheduleNonGlobal = function (task) { 2276 return nativeAddEventListener.call(taskData.target, taskData.eventName, task.invoke, taskData.options); 2277 }; 2278 2279 const customSchedulePrepend = function (task) { 2280 return nativePrependEventListener.call(taskData.target, taskData.eventName, task.invoke, taskData.options); 2281 }; 2282 2283 const customCancelNonGlobal = function (task) { 2284 return nativeRemoveEventListener.call(task.target, task.eventName, task.invoke, task.options); 2285 }; 2286 2287 const customSchedule = useGlobalCallback ? customScheduleGlobal : customScheduleNonGlobal; 2288 const customCancel = useGlobalCallback ? customCancelGlobal : customCancelNonGlobal; 2289 2290 const compareTaskCallbackVsDelegate = function (task, delegate) { 2291 const typeOfDelegate = typeof delegate; 2292 return typeOfDelegate === 'function' && task.callback === delegate || typeOfDelegate === 'object' && task.originalDelegate === delegate; 2293 }; 2294 2295 const compare = patchOptions && patchOptions.diff ? patchOptions.diff : compareTaskCallbackVsDelegate; 2296 const unpatchedEvents = Zone[zoneSymbol('UNPATCHED_EVENTS')]; 2297 2298 const passiveEvents = _global[zoneSymbol('PASSIVE_EVENTS')]; 2299 2300 const makeAddListener = function (nativeListener, addSource, customScheduleFn, customCancelFn, returnTarget = false, prepend = false) { 2301 return function () { 2302 const target = this || _global; 2303 let eventName = arguments[0]; 2304 2305 if (patchOptions && patchOptions.transferEventName) { 2306 eventName = patchOptions.transferEventName(eventName); 2307 } 2308 2309 let delegate = arguments[1]; 2310 2311 if (!delegate) { 2312 return nativeListener.apply(this, arguments); 2313 } 2314 2315 if (isNode && eventName === 'uncaughtException') { 2316 // don't patch uncaughtException of nodejs to prevent endless loop 2317 return nativeListener.apply(this, arguments); 2318 } // don't create the bind delegate function for handleEvent 2319 // case here to improve addEventListener performance 2320 // we will create the bind delegate when invoke 2321 2322 2323 let isHandleEvent = false; 2324 2325 if (typeof delegate !== 'function') { 2326 if (!delegate.handleEvent) { 2327 return nativeListener.apply(this, arguments); 2328 } 2329 2330 isHandleEvent = true; 2331 } 2332 2333 if (validateHandler && !validateHandler(nativeListener, delegate, target, arguments)) { 2334 return; 2335 } 2336 2337 const passive = passiveSupported && !!passiveEvents && passiveEvents.indexOf(eventName) !== -1; 2338 const options = buildEventListenerOptions(arguments[2], passive); 2339 2340 if (unpatchedEvents) { 2341 // check unpatched list 2342 for (let i = 0; i < unpatchedEvents.length; i++) { 2343 if (eventName === unpatchedEvents[i]) { 2344 if (passive) { 2345 return nativeListener.call(target, eventName, delegate, options); 2346 } else { 2347 return nativeListener.apply(this, arguments); 2348 } 2349 } 2350 } 2351 } 2352 2353 const capture = !options ? false : typeof options === 'boolean' ? true : options.capture; 2354 const once = options && typeof options === 'object' ? options.once : false; 2355 const zone = Zone.current; 2356 let symbolEventNames = zoneSymbolEventNames[eventName]; 2357 2358 if (!symbolEventNames) { 2359 prepareEventNames(eventName, eventNameToString); 2360 symbolEventNames = zoneSymbolEventNames[eventName]; 2361 } 2362 2363 const symbolEventName = symbolEventNames[capture ? TRUE_STR : FALSE_STR]; 2364 let existingTasks = target[symbolEventName]; 2365 let isExisting = false; 2366 2367 if (existingTasks) { 2368 // already have task registered 2369 isExisting = true; 2370 2371 if (checkDuplicate) { 2372 for (let i = 0; i < existingTasks.length; i++) { 2373 if (compare(existingTasks[i], delegate)) { 2374 // same callback, same capture, same event name, just return 2375 return; 2376 } 2377 } 2378 } 2379 } else { 2380 existingTasks = target[symbolEventName] = []; 2381 } 2382 2383 let source; 2384 const constructorName = target.constructor['name']; 2385 const targetSource = globalSources[constructorName]; 2386 2387 if (targetSource) { 2388 source = targetSource[eventName]; 2389 } 2390 2391 if (!source) { 2392 source = constructorName + addSource + (eventNameToString ? eventNameToString(eventName) : eventName); 2393 } // do not create a new object as task.data to pass those things 2394 // just use the global shared one 2395 2396 2397 taskData.options = options; 2398 2399 if (once) { 2400 // if addEventListener with once options, we don't pass it to 2401 // native addEventListener, instead we keep the once setting 2402 // and handle ourselves. 2403 taskData.options.once = false; 2404 } 2405 2406 taskData.target = target; 2407 taskData.capture = capture; 2408 taskData.eventName = eventName; 2409 taskData.isExisting = isExisting; 2410 const data = useGlobalCallback ? OPTIMIZED_ZONE_EVENT_TASK_DATA : undefined; // keep taskData into data to allow onScheduleEventTask to access the task information 2411 2412 if (data) { 2413 data.taskData = taskData; 2414 } 2415 2416 const task = zone.scheduleEventTask(source, delegate, data, customScheduleFn, customCancelFn); // should clear taskData.target to avoid memory leak 2417 // issue, https://github.com/angular/angular/issues/20442 2418 2419 taskData.target = null; // need to clear up taskData because it is a global object 2420 2421 if (data) { 2422 data.taskData = null; 2423 } // have to save those information to task in case 2424 // application may call task.zone.cancelTask() directly 2425 2426 2427 if (once) { 2428 options.once = true; 2429 } 2430 2431 if (!(!passiveSupported && typeof task.options === 'boolean')) { 2432 // if not support passive, and we pass an option object 2433 // to addEventListener, we should save the options to task 2434 task.options = options; 2435 } 2436 2437 task.target = target; 2438 task.capture = capture; 2439 task.eventName = eventName; 2440 2441 if (isHandleEvent) { 2442 // save original delegate for compare to check duplicate 2443 task.originalDelegate = delegate; 2444 } 2445 2446 if (!prepend) { 2447 existingTasks.push(task); 2448 } else { 2449 existingTasks.unshift(task); 2450 } 2451 2452 if (returnTarget) { 2453 return target; 2454 } 2455 }; 2456 }; 2457 2458 proto[ADD_EVENT_LISTENER] = makeAddListener(nativeAddEventListener, ADD_EVENT_LISTENER_SOURCE, customSchedule, customCancel, returnTarget); 2459 2460 if (nativePrependEventListener) { 2461 proto[PREPEND_EVENT_LISTENER] = makeAddListener(nativePrependEventListener, PREPEND_EVENT_LISTENER_SOURCE, customSchedulePrepend, customCancel, returnTarget, true); 2462 } 2463 2464 proto[REMOVE_EVENT_LISTENER] = function () { 2465 const target = this || _global; 2466 let eventName = arguments[0]; 2467 2468 if (patchOptions && patchOptions.transferEventName) { 2469 eventName = patchOptions.transferEventName(eventName); 2470 } 2471 2472 const options = arguments[2]; 2473 const capture = !options ? false : typeof options === 'boolean' ? true : options.capture; 2474 const delegate = arguments[1]; 2475 2476 if (!delegate) { 2477 return nativeRemoveEventListener.apply(this, arguments); 2478 } 2479 2480 if (validateHandler && !validateHandler(nativeRemoveEventListener, delegate, target, arguments)) { 2481 return; 2482 } 2483 2484 const symbolEventNames = zoneSymbolEventNames[eventName]; 2485 let symbolEventName; 2486 2487 if (symbolEventNames) { 2488 symbolEventName = symbolEventNames[capture ? TRUE_STR : FALSE_STR]; 2489 } 2490 2491 const existingTasks = symbolEventName && target[symbolEventName]; 2492 2493 if (existingTasks) { 2494 for (let i = 0; i < existingTasks.length; i++) { 2495 const existingTask = existingTasks[i]; 2496 2497 if (compare(existingTask, delegate)) { 2498 existingTasks.splice(i, 1); // set isRemoved to data for faster invokeTask check 2499 2500 existingTask.isRemoved = true; 2501 2502 if (existingTasks.length === 0) { 2503 // all tasks for the eventName + capture have gone, 2504 // remove globalZoneAwareCallback and remove the task cache from target 2505 existingTask.allRemoved = true; 2506 target[symbolEventName] = null; // in the target, we have an event listener which is added by on_property 2507 // such as target.onclick = function() {}, so we need to clear this internal 2508 // property too if all delegates all removed 2509 2510 if (typeof eventName === 'string') { 2511 const onPropertySymbol = ZONE_SYMBOL_PREFIX + 'ON_PROPERTY' + eventName; 2512 target[onPropertySymbol] = null; 2513 } 2514 } 2515 2516 existingTask.zone.cancelTask(existingTask); 2517 2518 if (returnTarget) { 2519 return target; 2520 } 2521 2522 return; 2523 } 2524 } 2525 } // issue 930, didn't find the event name or callback 2526 // from zone kept existingTasks, the callback maybe 2527 // added outside of zone, we need to call native removeEventListener 2528 // to try to remove it. 2529 2530 2531 return nativeRemoveEventListener.apply(this, arguments); 2532 }; 2533 2534 proto[LISTENERS_EVENT_LISTENER] = function () { 2535 const target = this || _global; 2536 let eventName = arguments[0]; 2537 2538 if (patchOptions && patchOptions.transferEventName) { 2539 eventName = patchOptions.transferEventName(eventName); 2540 } 2541 2542 const listeners = []; 2543 const tasks = findEventTasks(target, eventNameToString ? eventNameToString(eventName) : eventName); 2544 2545 for (let i = 0; i < tasks.length; i++) { 2546 const task = tasks[i]; 2547 let delegate = task.originalDelegate ? task.originalDelegate : task.callback; 2548 listeners.push(delegate); 2549 } 2550 2551 return listeners; 2552 }; 2553 2554 proto[REMOVE_ALL_LISTENERS_EVENT_LISTENER] = function () { 2555 const target = this || _global; 2556 let eventName = arguments[0]; 2557 2558 if (!eventName) { 2559 const keys = Object.keys(target); 2560 2561 for (let i = 0; i < keys.length; i++) { 2562 const prop = keys[i]; 2563 const match = EVENT_NAME_SYMBOL_REGX.exec(prop); 2564 let evtName = match && match[1]; // in nodejs EventEmitter, removeListener event is 2565 // used for monitoring the removeListener call, 2566 // so just keep removeListener eventListener until 2567 // all other eventListeners are removed 2568 2569 if (evtName && evtName !== 'removeListener') { 2570 this[REMOVE_ALL_LISTENERS_EVENT_LISTENER].call(this, evtName); 2571 } 2572 } // remove removeListener listener finally 2573 2574 2575 this[REMOVE_ALL_LISTENERS_EVENT_LISTENER].call(this, 'removeListener'); 2576 } else { 2577 if (patchOptions && patchOptions.transferEventName) { 2578 eventName = patchOptions.transferEventName(eventName); 2579 } 2580 2581 const symbolEventNames = zoneSymbolEventNames[eventName]; 2582 2583 if (symbolEventNames) { 2584 const symbolEventName = symbolEventNames[FALSE_STR]; 2585 const symbolCaptureEventName = symbolEventNames[TRUE_STR]; 2586 const tasks = target[symbolEventName]; 2587 const captureTasks = target[symbolCaptureEventName]; 2588 2589 if (tasks) { 2590 const removeTasks = tasks.slice(); 2591 2592 for (let i = 0; i < removeTasks.length; i++) { 2593 const task = removeTasks[i]; 2594 let delegate = task.originalDelegate ? task.originalDelegate : task.callback; 2595 this[REMOVE_EVENT_LISTENER].call(this, eventName, delegate, task.options); 2596 } 2597 } 2598 2599 if (captureTasks) { 2600 const removeTasks = captureTasks.slice(); 2601 2602 for (let i = 0; i < removeTasks.length; i++) { 2603 const task = removeTasks[i]; 2604 let delegate = task.originalDelegate ? task.originalDelegate : task.callback; 2605 this[REMOVE_EVENT_LISTENER].call(this, eventName, delegate, task.options); 2606 } 2607 } 2608 } 2609 } 2610 2611 if (returnTarget) { 2612 return this; 2613 } 2614 }; // for native toString patch 2615 2616 2617 attachOriginToPatched(proto[ADD_EVENT_LISTENER], nativeAddEventListener); 2618 attachOriginToPatched(proto[REMOVE_EVENT_LISTENER], nativeRemoveEventListener); 2619 2620 if (nativeRemoveAllListeners) { 2621 attachOriginToPatched(proto[REMOVE_ALL_LISTENERS_EVENT_LISTENER], nativeRemoveAllListeners); 2622 } 2623 2624 if (nativeListeners) { 2625 attachOriginToPatched(proto[LISTENERS_EVENT_LISTENER], nativeListeners); 2626 } 2627 2628 return true; 2629 } 2630 2631 let results = []; 2632 2633 for (let i = 0; i < apis.length; i++) { 2634 results[i] = patchEventTargetMethods(apis[i], patchOptions); 2635 } 2636 2637 return results; 2638} 2639 2640function findEventTasks(target, eventName) { 2641 if (!eventName) { 2642 const foundTasks = []; 2643 2644 for (let prop in target) { 2645 const match = EVENT_NAME_SYMBOL_REGX.exec(prop); 2646 let evtName = match && match[1]; 2647 2648 if (evtName && (!eventName || evtName === eventName)) { 2649 const tasks = target[prop]; 2650 2651 if (tasks) { 2652 for (let i = 0; i < tasks.length; i++) { 2653 foundTasks.push(tasks[i]); 2654 } 2655 } 2656 } 2657 } 2658 2659 return foundTasks; 2660 } 2661 2662 let symbolEventName = zoneSymbolEventNames[eventName]; 2663 2664 if (!symbolEventName) { 2665 prepareEventNames(eventName); 2666 symbolEventName = zoneSymbolEventNames[eventName]; 2667 } 2668 2669 const captureFalseTasks = target[symbolEventName[FALSE_STR]]; 2670 const captureTrueTasks = target[symbolEventName[TRUE_STR]]; 2671 2672 if (!captureFalseTasks) { 2673 return captureTrueTasks ? captureTrueTasks.slice() : []; 2674 } else { 2675 return captureTrueTasks ? captureFalseTasks.concat(captureTrueTasks) : captureFalseTasks.slice(); 2676 } 2677} 2678 2679function patchEventPrototype(global, api) { 2680 const Event = global['Event']; 2681 2682 if (Event && Event.prototype) { 2683 api.patchMethod(Event.prototype, 'stopImmediatePropagation', delegate => function (self, args) { 2684 self[IMMEDIATE_PROPAGATION_SYMBOL] = true; // we need to call the native stopImmediatePropagation 2685 // in case in some hybrid application, some part of 2686 // application will be controlled by zone, some are not 2687 2688 delegate && delegate.apply(self, args); 2689 }); 2690 } 2691} 2692/** 2693 * @license 2694 * Copyright Google LLC All Rights Reserved. 2695 * 2696 * Use of this source code is governed by an MIT-style license that can be 2697 * found in the LICENSE file at https://angular.io/license 2698 */ 2699 2700 2701function patchCallbacks(api, target, targetName, method, callbacks) { 2702 const symbol = Zone.__symbol__(method); 2703 2704 if (target[symbol]) { 2705 return; 2706 } 2707 2708 const nativeDelegate = target[symbol] = target[method]; 2709 2710 target[method] = function (name, opts, options) { 2711 if (opts && opts.prototype) { 2712 callbacks.forEach(function (callback) { 2713 const source = `${targetName}.${method}::` + callback; 2714 const prototype = opts.prototype; // Note: the `patchCallbacks` is used for patching the `document.registerElement` and 2715 // `customElements.define`. We explicitly wrap the patching code into try-catch since 2716 // callbacks may be already patched by other web components frameworks (e.g. LWC
2716), and they 2717 // make those properties non-writable. This means that patching callback will throw an error 2718 // `cannot assign to read-only property`. See this code as an example: 2719 // https://github.com/salesforce/lwc/blob/master/packages/@lwc/engine-core/src/framework/base-bridge-element.ts#L180-L186 2720 // We don't want to stop the application rendering if we couldn't patch some 2721 // callback, e.g. `attributeChangedCallback`. 2722 2723 try { 2724 if (prototype.hasOwnProperty(callback)) { 2725 const descriptor = api.ObjectGetOwnPropertyDescriptor(prototype, callback); 2726 2727 if (descriptor && descriptor.value) { 2728 descriptor.value = api.wrapWithCurrentZone(descriptor.value, source); 2729 2730 api._redefineProperty(opts.prototype, callback, descriptor); 2731 } else if (prototype[callback]) { 2732 prototype[callback] = api.wrapWithCurrentZone(prototype[callback], source); 2733 } 2734 } else if (prototype[callback]) { 2735 prototype[callback] = api.wrapWithCurrentZone(prototype[callback], source); 2736 } 2737 }
vendor: 6,048 bytes, lines 2737-2912
2737 catch (_a) {// Note: we leave the catch block empty since there's no way to handle the error related 2738 // to non-writable property. 2739 } 2740 }); 2741 } 2742 2743 return nativeDelegate.call(target, name, opts, options); 2744 }; 2745 2746 api.attachOriginToPatched(target[method], nativeDelegate); 2747} 2748/** 2749 * @license 2750 * Copyright Google LLC All Rights Reserved. 2751 * 2752 * Use of this source code is governed by an MIT-style license that can be 2753 * found in the LICENSE file at https://angular.io/license 2754 */ 2755 2756 2757function filterProperties(target, onProperties, ignoreProperties) { 2758 if (!ignoreProperties || ignoreProperties.length === 0) { 2759 return onProperties; 2760 } 2761 2762 const tip = ignoreProperties.filter(ip => ip.target === target); 2763 2764 if (!tip || tip.length === 0) { 2765 return onProperties; 2766 } 2767 2768 const targetIgnoreProperties = tip[0].ignoreProperties; 2769 return onProperties.filter(op => targetIgnoreProperties.indexOf(op) === -1); 2770} 2771 2772function patchFilteredProperties(target, onProperties, ignoreProperties, prototype) { 2773 // check whether target is available, sometimes target will be undefined 2774 // because different browser or some 3rd party plugin. 2775 if (!target) { 2776 return; 2777 } 2778 2779 const filteredProperties = filterProperties(target, onProperties, ignoreProperties); 2780 patchOnProperties(target, filteredProperties, prototype); 2781} 2782/** 2783 * Get all event name properties which the event name startsWith `on` 2784 * from the target object itself, inherited properties are not considered. 2785 */ 2786 2787 2788function getOnEventNames(target) { 2789 return Object.getOwnPropertyNames(target).filter(name => name.startsWith('on') && name.length > 2).map(name => name.substring(2)); 2790} 2791 2792function propertyDescriptorPatch(api, _global) { 2793 if (isNode && !isMix) { 2794 return; 2795 } 2796 2797 if (Zone[api.symbol('patchEvents')]) { 2798 // events are already been patched by legacy patch. 2799 return; 2800 } 2801 2802 const ignoreProperties = _global['__Zone_ignore_on_properties']; // for browsers that we can patch the descriptor: Chrome & Firefox 2803 2804 let patchTargets = []; 2805 2806 if (isBrowser) { 2807 const internalWindow = window; 2808 patchTargets = patchTargets.concat(['Document', 'SVGElement', 'Element', 'HTMLElement', 'HTMLBodyElement', 'HTMLMediaElement', 'HTMLFrameSetElement', 'HTMLFrameElement', 'HTMLIFrameElement', 'HTMLMarqueeElement', 'Worker']); 2809 const ignoreErrorProperties = isIE() ? [{ 2810 target: internalWindow, 2811 ignoreProperties: ['error'] 2812 }] : []; // in IE/Edge, onProp not exist in window object, but in WindowPrototype 2813 // so we need to pass WindowPrototype to check onProp exist or not 2814 2815 patchFilteredProperties(internalWindow, getOnEventNames(internalWindow), ignoreProperties ? ignoreProperties.concat(ignoreErrorProperties) : ignoreProperties, ObjectGetPrototypeOf(internalWindow)); 2816 } 2817 2818 patchTargets = patchTargets.concat(['XMLHttpRequest', 'XMLHttpRequestEventTarget', 'IDBIndex', 'IDBRequest', 'IDBOpenDBRequest', 'IDBDatabase', 'IDBTransaction', 'IDBCursor', 'WebSocket']); 2819 2820 for (let i = 0; i < patchTargets.length; i++) { 2821 const target = _global[patchTargets[i]]; 2822 target && target.prototype && patchFilteredProperties(target.prototype, getOnEventNames(target.prototype), ignoreProperties); 2823 } 2824} 2825/** 2826 * @license 2827 * Copyright Google LLC All Rights Reserved. 2828 * 2829 * Use of this source code is governed by an MIT-style license that can be 2830 * found in the LICENSE file at https://angular.io/license 2831 */ 2832 2833 2834Zone.__load_patch('util', (global, Zone, api) => { 2835 // Collect native event names by looking at properties 2836 // on the global namespace, e.g. 'onclick'. 2837 const eventNames = getOnEventNames(global); 2838 api.patchOnProperties = patchOnProperties; 2839 api.patchMethod = patchMethod; 2840 api.bindArguments = bindArguments; 2841 api.patchMacroTask = patchMacroTask; // In earlier version of zone.js (<0.9.0), we use env name `__zone_symbol__BLACK_LISTED_EVENTS` to 2842 // define which events will not be patched by `Zone.js`. 2843 // In newer version (>=0.9.0), we change the env name to `__zone_symbol__UNPATCHED_EVENTS` to keep 2844 // the name consistent with angular repo. 2845 // The `__zone_symbol__BLACK_LISTED_EVENTS` is deprecated, but it is still be supported for 2846 // backwards compatibility. 2847 2848 const SYMBOL_BLACK_LISTED_EVENTS = Zone.__symbol__('BLACK_LISTED_EVENTS'); 2849 2850 const SYMBOL_UNPATCHED_EVENTS = Zone.__symbol__('UNPATCHED_EVENTS'); 2851 2852 if (global[SYMBOL_UNPATCHED_EVENTS]) { 2853 global[SYMBOL_BLACK_LISTED_EVENTS] = global[SYMBOL_UNPATCHED_EVENTS]; 2854 } 2855 2856 if (global[SYMBOL_BLACK_LISTED_EVENTS]) { 2857 Zone[SYMBOL_BLACK_LISTED_EVENTS] = Zone[SYMBOL_UNPATCHED_EVENTS] = global[SYMBOL_BLACK_LISTED_EVENTS]; 2858 } 2859 2860 api.patchEventPrototype = patchEventPrototype; 2861 api.patchEventTarget = patchEventTarget; 2862 api.isIEOrEdge = isIEOrEdge; 2863 api.ObjectDefineProperty = ObjectDefineProperty; 2864 api.ObjectGetOwnPropertyDescriptor = ObjectGetOwnPropertyDescriptor; 2865 api.ObjectCreate = ObjectCreate; 2866 api.ArraySlice = ArraySlice; 2867 api.patchClass = patchClass; 2868 api.wrapWithCurrentZone = wrapWithCurrentZone; 2869 api.filterProperties = filterProperties; 2870 api.attachOriginToPatched = attachOriginToPatched; 2871 api._redefineProperty = Object.defineProperty; 2872 api.patchCallbacks = patchCallbacks; 2873 2874 api.getGlobalObjects = () => ({ 2875 globalSources, 2876 zoneSymbolEventNames, 2877 eventNames, 2878 isBrowser, 2879 isMix, 2880 isNode, 2881 TRUE_STR, 2882 FALSE_STR, 2883 ZONE_SYMBOL_PREFIX, 2884 ADD_EVENT_LISTENER_STR, 2885 REMOVE_EVENT_LISTENER_STR 2886 }); 2887}); 2888/** 2889 * @license 2890 * Copyright Google LLC All Rights Reserved. 2891 * 2892 * Use of this source code is governed by an MIT-style license that can be 2893 * found in the LICENSE file at https://angular.io/license 2894 */ 2895 2896 2897const taskSymbol = zoneSymbol('zoneTask'); 2898 2899function patchTimer(window, setName, cancelName, nameSuffix) { 2900 let setNative = null; 2901 let clearNative = null; 2902 setName += nameSuffix; 2903 cancelName += nameSuffix; 2904 const tasksByHandleId = {}; 2905 2906 function scheduleTask(task) { 2907 const data = task.data; 2908 2909 data.args[0] = function () { 2910 return task.invoke.apply(this, arguments); 2911 }; 2912
2913 data.handleId = setNative.apply(window, data.args); 2914 return task; 2915 } 2916 2917 function clearTask(task) { 2918 return clearNative.call(window, task.data.handleId); 2919 } 2920 2921 setNative = patchMethod(window, setName, delegate => function (self, args) { 2922 if (typeof args[0] === 'function') { 2923 const options = { 2924 isPeriodic: nameSuffix === 'Interval', 2925 delay: nameSuffix === 'Timeout' || nameSuffix === 'Interval' ? args[1] || 0 : undefined, 2926 args: args 2927 }; 2928 const callback = args[0]; 2929 2930 args[0] = function timer() { 2931 try { 2932 return callback.apply(this, arguments); 2933 } finally { 2934 // issue-934, task will be cancelled 2935 // even it is a periodic task such as 2936 // setInterval 2937 // https://github.com/angular/angular/issues/40387 2938 // Cleanup tasksByHandleId should be handled before scheduleTask 2939 // Since some zoneSpec may intercept and doesn't trigger 2940 // scheduleFn(scheduleTask) provided here. 2941 if (!options.isPeriodic) { 2942 if (typeof options.handleId === 'number') { 2943 // in non-nodejs env, we remove timerId 2944 // from local cache 2945 delete tasksByHandleId[options.handleId]; 2946 } else if (options.handleId) { 2947 // Node returns complex objects as handleIds 2948 // we remove task reference from timer object 2949 options.handleId[taskSymbol] = null; 2950 } 2951 } 2952 } 2953 }; 2954 2955 const task = scheduleMacroTaskWithCurrentZone(setName, args[0], options, scheduleTask, clearTask); 2956 2957 if (!task) { 2958 return task; 2959 } // Node.js must additionally support the ref and unref functions. 2960 2961 2962 const handle = task.data.handleId; 2963 2964 if (typeof handle === 'number') { 2965 // for non nodejs env, we save handleId: task 2966 // mapping in local cache for clearTimeout 2967 tasksByHandleId[handle] = task; 2968 } else if (handle) { 2969 // for nodejs env, we save task 2970 // reference in timerId Object for clearTimeout 2971 handle[taskSymbol] = task; 2972 } // check whether handle is null, because some polyfill or browser 2973 // may return undefined from setTimeout/setInterval/setImmediate/requestAnimationFrame 2974 2975 2976 if (handle && handle.ref && handle.unref && typeof handle.ref === 'function' && typeof handle.unref === 'function') { 2977 task.ref = handle.ref.bind(handle); 2978 task.unref = handle.unref.bind(handle); 2979 } 2980 2981 if (typeof handle === 'number' || handle) { 2982 return handle; 2983 } 2984 2985 return task; 2986 } else { 2987 // cause an error by calling it directly. 2988 return delegate.apply(window, args); 2989 } 2990 }); 2991 clearNative = patchMethod(window, cancelName, delegate => function (self, args) { 2992 const id = args[0]; 2993 let task; 2994 2995 if (typeof id === 'number') { 2996 // non nodejs env. 2997 task = tasksByHandleId[id]; 2998 } else { 2999 // nodejs env. 3000 task = id && id[taskSymbol]; // other environments. 3001 3002 if (!task) { 3003 task = id; 3004 } 3005 } 3006 3007 if (task && typeof task.type === 'string') { 3008 if (task.state !== 'notScheduled' && (task.cancelFn && task.data.isPeriodic || task.runCount === 0)) { 3009 if (typeof id === 'number') { 3010 delete tasksByHandleId[id]; 3011 } else if (id) { 3012 id[taskSymbol] = null; 3013 } // Do not cancel already canceled functions 3014 3015 3016 task.zone.cancelTask(task); 3017 } 3018 } else { 3019 // cause an error by calling it directly. 3020 delegate.apply(window, args); 3021 } 3022 }); 3023} 3024/** 3025 * @license 3026 * Copyright Google LLC All Rights Reserved. 3027 * 3028 * Use of this source code is governed by an MIT-style license that can be 3029 * found in the LICENSE file at https://angular.io/license 3030 */ 3031 3032 3033function patchCustomElements(_global, api) { 3034 const { 3035 isBrowser, 3036 isMix 3037 } = api.getGlobalObjects(); 3038 3039 if (!isBrowser && !isMix || !_global['customElements'] || !('customElements' in _global)) { 3040 return; 3041 } 3042 3043 const callbacks = ['connectedCallback', 'disconnectedCallback', 'adoptedCallback', 'attributeChangedCallback']; 3044 api.patchCallbacks(api, _global.customElements, 'customElements', 'define', callbacks); 3045} 3046/** 3047 * @license 3048 * Copyright Google LLC All Rights Reserved. 3049 * 3050 * Use of this source code is governed by an MIT-style license that can be 3051 * found in the LICENSE file at https://angular.io/license 3052 */ 3053 3054 3055function eventTargetPatch(_global, api) {
vendor: 14,275 bytes, lines 3056-3431
3056 if (Zone[api.symbol('patchEventTarget')]) { 3057 // EventTarget is already patched. 3058 return; 3059 } 3060 3061 const { 3062 eventNames, 3063 zoneSymbolEventNames, 3064 TRUE_STR, 3065 FALSE_STR, 3066 ZONE_SYMBOL_PREFIX 3067 } = api.getGlobalObjects(); // predefine all __zone_symbol__ + eventName + true/false string 3068 3069 for (let i = 0; i < eventNames.length; i++) { 3070 const eventName = eventNames[i]; 3071 const falseEventName = eventName + FALSE_STR; 3072 const trueEventName = eventName + TRUE_STR; 3073 const symbol = ZONE_SYMBOL_PREFIX + falseEventName; 3074 const symbolCapture = ZONE_SYMBOL_PREFIX + trueEventName; 3075 zoneSymbolEventNames[eventName] = {}; 3076 zoneSymbolEventNames[eventName][FALSE_STR] = symbol; 3077 zoneSymbolEventNames[eventName][TRUE_STR] = symbolCapture; 3078 } 3079 3080 const EVENT_TARGET = _global['EventTarget']; 3081 3082 if (!EVENT_TARGET || !EVENT_TARGET.prototype) { 3083 return; 3084 } 3085 3086 api.patchEventTarget(_global, api, [EVENT_TARGET && EVENT_TARGET.prototype]); 3087 return true; 3088} 3089 3090function patchEvent(global, api) { 3091 api.patchEventPrototype(global, api); 3092} 3093/** 3094 * @license 3095 * Copyright Google LLC All Rights Reserved. 3096 * 3097 * Use of this source code is governed by an MIT-style license that can be 3098 * found in the LICENSE file at https://angular.io/license 3099 */ 3100 3101 3102Zone.__load_patch('legacy', global => { 3103 const legacyPatch = global[Zone.__symbol__('legacyPatch')]; 3104 3105 if (legacyPatch) { 3106 legacyPatch(); 3107 } 3108}); 3109 3110Zone.__load_patch('queueMicrotask', (global, Zone, api) => { 3111 api.patchMethod(global, 'queueMicrotask', delegate => { 3112 return function (self, args) { 3113 Zone.current.scheduleMicroTask('queueMicrotask', args[0]); 3114 }; 3115 }); 3116}); 3117 3118Zone.__load_patch('timers', global => { 3119 const set = 'set'; 3120 const clear = 'clear'; 3121 patchTimer(global, set, clear, 'Timeout'); 3122 patchTimer(global, set, clear, 'Interval'); 3123 patchTimer(global, set, clear, 'Immediate'); 3124}); 3125 3126Zone.__load_patch('requestAnimationFrame', global => { 3127 patchTimer(global, 'request', 'cancel', 'AnimationFrame'); 3128 patchTimer(global, 'mozRequest', 'mozCancel', 'AnimationFrame'); 3129 patchTimer(global, 'webkitRequest', 'webkitCancel', 'AnimationFrame'); 3130}); 3131 3132Zone.__load_patch('blocking', (global, Zone) => { 3133 const blockingMethods = ['alert', 'prompt', 'confirm']; 3134 3135 for (let i = 0; i < blockingMethods.length; i++) { 3136 const name = blockingMethods[i]; 3137 patchMethod(global, name, (delegate, symbol, name) => { 3138 return function (s, args) { 3139 return Zone.current.run(delegate, global, args, name); 3140 }; 3141 }); 3142 } 3143}); 3144 3145Zone.__load_patch('EventTarget', (global, Zone, api) => { 3146 patchEvent(global, api); 3147 eventTargetPatch(global, api); // patch XMLHttpRequestEventTarget's addEventListener/removeEventListener 3148 3149 const XMLHttpRequestEventTarget = global['XMLHttpRequestEventTarget']; 3150 3151 if (XMLHttpRequestEventTarget && XMLHttpRequestEventTarget.prototype) { 3152 api.patchEventTarget(global, api, [XMLHttpRequestEventTarget.prototype]); 3153 } 3154}); 3155 3156Zone.__load_patch('MutationObserver', (global, Zone, api) => { 3157 patchClass('MutationObserver'); 3158 patchClass('WebKitMutationObserver'); 3159}); 3160 3161Zone.__load_patch('IntersectionObserver', (global, Zone, api) => { 3162 patchClass('IntersectionObserver'); 3163}); 3164 3165Zone.__load_patch('FileReader', (global, Zone, api) => { 3166 patchClass('FileReader'); 3167}); 3168 3169Zone.__load_patch('on_property', (global, Zone, api) => { 3170 propertyDescriptorPatch(api, global); 3171}); 3172 3173Zone.__load_patch('customElements', (global, Zone, api) => { 3174 patchCustomElements(global, api); 3175}); 3176 3177Zone.__load_patch('XHR', (global, Zone) => { 3178 // Treat XMLHttpRequest as a macrotask. 3179 patchXHR(global); 3180 const XHR_TASK = zoneSymbol('xhrTask'); 3181 const XHR_SYNC = zoneSymbol('xhrSync'); 3182 const XHR_LISTENER = zoneSymbol('xhrListener'); 3183 const XHR_SCHEDULED = zoneSymbol('xhrScheduled'); 3184 const XHR_URL = zoneSymbol('xhrURL'); 3185 const XHR_ERROR_BEFORE_SCHEDULED = zoneSymbol('xhrErrorBeforeScheduled'); 3186 3187 function patchXHR(window) { 3188 const XMLHttpRequest = window['XMLHttpRequest']; 3189 3190 if (!XMLHttpRequest) { 3191 // XMLHttpRequest is not available in service worker 3192 return; 3193 } 3194 3195 const XMLHttpRequestPrototype = XMLHttpRequest.prototype; 3196 3197 function findPendingTask(target) { 3198 return target[XHR_TASK]; 3199 } 3200 3201 let oriAddListener = XMLHttpRequestPrototype[ZONE_SYMBOL_ADD_EVENT_LISTENER]; 3202 let oriRemoveListener = XMLHttpRequestPrototype[ZONE_SYMBOL_REMOVE_EVENT_LISTENER]; 3203 3204 if (!oriAddListener) { 3205 const XMLHttpRequestEventTarget = window['XMLHttpRequestEventTarget']; 3206 3207 if (XMLHttpRequestEventTarget) { 3208 const XMLHttpRequestEventTargetPrototype = XMLHttpRequestEventTarget.prototype; 3209 oriAddListener = XMLHttpRequestEventTargetPrototype[ZONE_SYMBOL_ADD_EVENT_LISTENER]; 3210 oriRemoveListener = XMLHttpRequestEventTargetPrototype[ZONE_SYMBOL_REMOVE_EVENT_LISTENER]; 3211 } 3212 } 3213 3214 const READY_STATE_CHANGE = 'readystatechange'; 3215 const SCHEDULED = 'scheduled'; 3216 3217 function scheduleTask(task) { 3218 const data = task.data; 3219 const target = data.target; 3220 target[XHR_SCHEDULED] = false; 3221 target[XHR_ERROR_BEFORE_SCHEDULED] = false; // remove existing event listener 3222 3223 const listener = target[XHR_LISTENER]; 3224 3225 if (!oriAddListener) { 3226 oriAddListener = target[ZONE_SYMBOL_ADD_EVENT_LISTENER]; 3227 oriRemoveListener = target[ZONE_SYMBOL_REMOVE_EVENT_LISTENER]; 3228 } 3229 3230 if (listener) { 3231 oriRemoveListener.call(target, READY_STATE_CHANGE, listener); 3232 } 3233 3234 const newListener = target[XHR_LISTENER] = () => { 3235 if (target.readyState === target.DONE) { 3236 // sometimes on some browsers XMLHttpRequest will fire onreadystatechange with 3237 // readyState=4 multiple times, so we need to check task state here 3238 if (!data.aborted && target[XHR_SCHEDULED] && task.state === SCHEDULED) { 3239 // check whether the xhr has registered onload listener 3240 // if that is the case, the task should invoke after all 3241 // onload listeners finish. 3242 // Also if the request failed without response (status = 0), the load event handler 3243 // will not be triggered, in that case, we should also invoke the placeholder callback 3244 // to close the XMLHttpRequest::send macroTask. 3245 // https://github.com/angular/angular/issues/38795 3246 const loadTasks = target[Zone.__symbol__('loadfalse')]; 3247 3248 if (target.status !== 0 && loadTasks && loadTasks.length > 0) { 3249 const oriInvoke = task.invoke; 3250 3251 task.invoke = function () { 3252 // need to load the tasks again, because in other 3253 // load listener, they may remove themselves 3254 const loadTasks = target[Zone.__symbol__('loadfalse')]; 3255 3256 for (let i = 0; i < loadTasks.length; i++) { 3257 if (loadTasks[i] === task) { 3258 loadTasks.splice(i, 1); 3259 } 3260 } 3261 3262 if (!data.aborted && task.state === SCHEDULED) { 3263 oriInvoke.call(task); 3264 } 3265 }; 3266 3267 loadTasks.push(task); 3268 } else { 3269 task.invoke(); 3270 } 3271 } else if (!data.aborted && target[XHR_SCHEDULED] === false) { 3272 // error occurs when xhr.send() 3273 target[XHR_ERROR_BEFORE_SCHEDULED] = true; 3274 } 3275 } 3276 }; 3277 3278 oriAddListener.call(target, READY_STATE_CHANGE, newListener); 3279 const storedTask = target[XHR_TASK]; 3280 3281 if (!storedTask) { 3282 target[XHR_TASK] = task; 3283 } 3284 3285 sendNative.apply(target, data.args); 3286 target[XHR_SCHEDULED] = true; 3287 return task; 3288 } 3289 3290 function placeholderCallback() {} 3291 3292 function clearTask(task) { 3293 const data = task.data; // Note - ideally, we would call data.target.removeEventListener here, but it's too late 3294 // to prevent it from firing. So instead, we store info for the event listener. 3295 3296 data.aborted = true; 3297 return abortNative.apply(data.target, data.args); 3298 } 3299 3300 const openNative = patchMethod(XMLHttpRequestPrototype, 'open', () => function (self, args) { 3301 self[XHR_SYNC] = args[2] == false; 3302 self[XHR_URL] = args[1]; 3303 return openNative.apply(self, args); 3304 }); 3305 const XMLHTTPREQUEST_SOURCE = 'XMLHttpRequest.send'; 3306 const fetchTaskAborting = zoneSymbol('fetchTaskAborting'); 3307 const fetchTaskScheduling = zoneSymbol('fetchTaskScheduling'); 3308 const sendNative = patchMethod(XMLHttpRequestPrototype, 'send', () => function (self, args) { 3309 if (Zone.current[fetchTaskScheduling] === true) { 3310 // a fetch is scheduling, so we are using xhr to polyfill fetch 3311 // and because we already schedule macroTask for fetch, we should 3312 // not schedule a macroTask for xhr again 3313 return sendNative.apply(self, args); 3314 } 3315 3316 if (self[XHR_SYNC]) { 3317 // if the XHR is sync there is no task to schedule, just execute the code. 3318 return sendNative.apply(self, args); 3319 } else { 3320 const options = { 3321 target: self, 3322 url: self[XHR_URL], 3323 isPeriodic: false, 3324 args: args, 3325 aborted: false 3326 }; 3327 const task = scheduleMacroTaskWithCurrentZone(XMLHTTPREQUEST_SOURCE, placeholderCallback, options, scheduleTask, clearTask); 3328 3329 if (self && self[XHR_ERROR_BEFORE_SCHEDULED] === true && !options.aborted && task.state === SCHEDULED) { 3330 // xhr request throw error when send 3331 // we should invoke task instead of leaving a scheduled 3332 // pending macroTask 3333 task.invoke(); 3334 } 3335 } 3336 }); 3337 const abortNative = patchMethod(XMLHttpRequestPrototype, 'abort', () => function (self, args) { 3338 const task = findPendingTask(self); 3339 3340 if (task && typeof task.type == 'string') { 3341 // If the XHR has already completed, do nothing. 3342 // If the XHR has already been aborted, do nothing. 3343 // Fix #569, call abort multiple times before done will cause 3344 // macroTask task count be negative number 3345 if (task.cancelFn == null || task.data && task.data.aborted) { 3346 return; 3347 } 3348 3349 task.zone.cancelTask(task); 3350 } else if (Zone.current[fetchTaskAborting] === true) { 3351 // the abort is called from fetch polyfill, we need to call native abort of XHR. 3352 return abortNative.apply(self, args); 3353 } // Otherwise, we are trying to abort an XHR which has not yet been sent, so there is no 3354 // task 3355 // to cancel. Do nothing. 3356 3357 }); 3358 } 3359}); 3360 3361Zone.__load_patch('geolocation', global => { 3362 /// GEO_LOCATION 3363 if (global['navigator'] && global['navigator'].geolocation) { 3364 patchPrototype(global['navigator'].geolocation, ['getCurrentPosition', 'watchPosition']); 3365 } 3366}); 3367 3368Zone.__load_patch('PromiseRejectionEvent', (global, Zone) => { 3369 // handle unhandled promise rejection 3370 function findPromiseRejectionHandler(evtName) { 3371 return function (e) { 3372 const eventTasks = findEventTasks(global, evtName); 3373 eventTasks.forEach(eventTask => { 3374 // windows has added unhandledrejection event listener 3375 // trigger the event listener 3376 const PromiseRejectionEvent = global['PromiseRejectionEvent']; 3377 3378 if (PromiseRejectionEvent) { 3379 const evt = new PromiseRejectionEvent(evtName, { 3380 promise: e.promise, 3381 reason: e.rejection 3382 }); 3383 eventTask.invoke(evt); 3384 } 3385 }); 3386 }; 3387 } 3388 3389 if (global['PromiseRejectionEvent']) { 3390 Zone[zoneSymbol('unhandledPromiseRejectionHandler')] = findPromiseRejectionHandler('unhandledrejection'); 3391 Zone[zoneSymbol('rejectionHandledHandler')] = findPromiseRejectionHandler('rejectionhandled'); 3392 } 3393}); 3394 3395/***/ }), 3396 3397/***/ 8781: 3398/*!**************************************************************!*\ 3399 !*** ./node_modules/@angular/compiler/fesm2020/compiler.mjs ***! 3400 \**************************************************************/ 3401/***/ ((__unused_webpack___webpack_module__, __webpack_exports__, __webpack_require__) => { 3402 3403__webpack_require__.r(__webpack_exports__); 3404/* harmony export */ __webpack_require__.d(__webpack_exports__, { 3405/* harmony export */ "AST": () => (/* binding */ AST), 3406/* harmony export */ "ASTWithName": () => (/* binding */ ASTWithName), 3407/* harmony export */ "ASTWithSource": () => (/* binding */ ASTWithSource), 3408/* harmony export */ "AbsoluteSourceSpan": () => (/* binding */ AbsoluteSourceSpan), 3409/* harmony export */ "ArrayType": () => (/* binding */ ArrayType), 3410/* harmony export */ "AstMemoryEfficientTransformer": () => (/* binding */ AstMemoryEfficientTransformer), 3411/* harmony export */ "AstTransformer": () => (/* binding */ AstTransformer), 3412/* harmony export */ "Attribute": () => (/* binding */ Attribute), 3413/* harmony export */ "Binary": () => (/* binding */ Binary), 3414/* harmony export */ "BinaryOperator": () => (/* binding */ BinaryOperator), 3415/* harmony export */ "BinaryOperatorExpr": () => (/* binding */ BinaryOperatorExpr), 3416/* harmony export */ "BindingPipe": () => (/* binding */ BindingPipe), 3417/* harmony export */ "BoundElementProperty": () => (/* binding */ BoundElementProperty), 3418/* harmony export */ "BuiltinType": () => (/* binding */ BuiltinType), 3419/* harmony export */ "BuiltinTypeName": () => (/* binding */ BuiltinTypeName), 3420/* harmony export */ "CUSTOM_ELEMENTS_SCHEMA": () => (/* binding */ CUSTOM_ELEMENTS_SCHEMA), 3421/* harmony export */ "Call": () => (/* binding */ Call), 3422/* harmony export */ "Chain": () => (/* binding */ Chain), 3423/* harmony export */ "ChangeDetectionStrategy": () => (/* binding */ ChangeDetectionStrategy), 3424/* harmony export */ "CommaExpr": () => (/* binding */ CommaExpr), 3425/* harmony export */ "Comment": () => (/* binding */ Comment), 3426/* harmony export */ "CompilerConfig": () => (/* binding */ CompilerConfig), 3427/* harmony export */ "Conditional": () => (/* binding */ Conditional), 3428/* harmony export */ "ConditionalExpr": () => (/* binding */ ConditionalExpr), 3429/* harmony export */ "ConstantPool": () => (/* binding */ ConstantPool), 3430/* harmony export */ "CssSelector": () => (/* binding */ CssSelector), 3431/* harmony export */ "DEFAULT_INTERPOLATION_CONFIG": () => (/* binding */ DEFAULT_INTERPOLATION_CONFIG),
3432/* harmony export */ "DYNAMIC_TYPE": () => (/* binding */ DYNAMIC_TYPE), 3433/* harmony export */ "DeclareFunctionStmt": () => (/* binding */ DeclareFunctionStmt), 3434/* harmony export */ "DeclareVarStmt": () => (/* binding */ DeclareVarStmt), 3435/* harmony export */ "DomElementSchemaRegistry": () => (/* binding */ DomElementSchemaRegistry), 3436/* harmony export */ "EOF": () => (/* binding */ EOF), 3437/* harmony export */ "Element": () => (/* binding */ Element), 3438/* harmony export */ "ElementSchemaRegistry": () => (/* binding */ ElementSchemaRegistry), 3439/* harmony export */ "EmitterVisitorContext": () => (/* binding */ EmitterVisitorContext), 3440/* harmony export */ "EmptyExpr": () => (/* binding */ EmptyExpr), 3441/* harmony export */ "Expansion": () => (/* binding */ Expansion), 3442/* harmony export */ "ExpansionCase": () => (/* binding */ ExpansionCase), 3443/* harmony export */ "Expression": () => (/* binding */ Expression), 3444/* harmony export */ "ExpressionBinding": () => (/* binding */ ExpressionBinding), 3445/* harmony export */ "ExpressionStatement": () => (/* binding */ ExpressionStatement), 3446/* harmony export */ "ExpressionType": () => (/* binding */ ExpressionType), 3447/* harmony export */ "ExternalExpr": () => (/* binding */ ExternalExpr), 3448/* harmony export */ "ExternalReference": () => (/* binding */ ExternalReference), 3449/* harmony export */ "FactoryTarget": () => (/* binding */ FactoryTarget$1), 3450/* harmony export */ "FunctionExpr": () => (/* binding */ FunctionExpr), 3451/* harmony export */ "HtmlParser": () => (/* binding */ HtmlParser), 3452/* harmony export */ "HtmlTagDefinition": () => (/* binding */ HtmlTagDefinition), 3453/* harmony export */ "I18NHtmlParser": () => (/* binding */ I18NHtmlParser), 3454/* harmony export */ "IfStmt": () => (/* binding */ IfStmt), 3455/* harmony export */ "ImplicitReceiver": () => (/* binding */ ImplicitReceiver), 3456/* harmony export */ "InstantiateExpr": () => (/* binding */ InstantiateExpr), 3457/* harmony export */ "Interpolation": () => (/* binding */ Interpolation), 3458/* harmony export */ "InterpolationConfig": () => (/* binding */ InterpolationConfig), 3459/* harmony export */ "InvokeFunctionExpr": () => (/* binding */ InvokeFunctionExpr), 3460/* harmony export */ "JSDocComment": () => (/* binding */ JSDocComment), 3461/* harmony export */ "JitEvaluator": () => (/* binding */ JitEvaluator), 3462/* harmony export */ "KeyedRead": () => (/* binding */ KeyedRead), 3463/* harmony export */ "KeyedWrite": () => (/* binding */ KeyedWrite), 3464/* harmony export */ "LeadingComment": () => (/* binding */ LeadingComment), 3465/* harmony export */ "Lexer": () => (/* binding */ Lexer), 3466/* harmony export */ "LiteralArray": () => (/* binding */ LiteralArray), 3467/* harmony export */ "LiteralArrayExpr": () => (/* binding */ LiteralArrayExpr), 3468/* harmony export */ "LiteralExpr": () => (/* binding */ LiteralExpr), 3469/* harmony export */ "LiteralMap": () => (/* binding */ LiteralMap), 3470/* harmony export */ "LiteralMapExpr": () => (/* binding */ LiteralMapExpr), 3471/* harmony export */ "LiteralPrimitive": () => (/* binding */ LiteralPrimitive), 3472/* harmony export */ "LocalizedString": () => (/* binding */ LocalizedString), 3473/* harmony export */ "MapType": () => (/* binding */ MapType), 3474/* harmony export */ "MessageBundle": () => (/* binding */ MessageBundle), 3475/* harmony export */ "NONE_TYPE": () => (/* binding */ NONE_TYPE), 3476/* harmony export */ "NO_ERRORS_SCHEMA": () => (/* binding */ NO_ERRORS_SCHEMA), 3477/* harmony export */ "NodeWithI18n": () => (/* binding */ NodeWithI18n), 3478/* harmony export */ "NonNullAssert": () => (/* binding */ NonNullAssert), 3479/* harmony export */ "NotExpr": () => (/* binding */ NotExpr), 3480/* harmony export */ "ParseError": () => (/* binding */ ParseError), 3481/* harmony export */ "ParseErrorLevel": () => (/* binding */ ParseErrorLevel), 3482/* harmony export */ "ParseLocation": () => (/* binding */ ParseLocation), 3483/* harmony export */ "ParseSourceFile": () => (/* binding */ ParseSourceFile), 3484/* harmony export */ "ParseSourceSpan": () => (/* binding */ ParseSourceSpan), 3485/* harmony export */ "ParseSpan": () => (/* binding */ ParseSpan), 3486/* harmony export */ "ParseTreeResult": () => (/* binding */ ParseTreeResult), 3487/* harmony export */ "ParsedEvent": () => (/* binding */ ParsedEvent), 3488/* harmony export */ "ParsedProperty": () => (/* binding */ ParsedProperty), 3489/* harmony export */ "ParsedPropertyType": () => (/* binding */ ParsedPropertyType), 3490/* harmony export */ "ParsedVariable": () => (/* binding */ ParsedVariable), 3491/* harmony export */ "Parser": () => (/* binding */ Parser$1), 3492/* harmony export */ "ParserError": () => (/* binding */ ParserError), 3493/* harmony export */ "PrefixNot": () => (/* binding */ PrefixNot), 3494/* harmony export */ "PropertyRead": () => (/* binding */ PropertyRead), 3495/* harmony export */ "PropertyWrite": () => (/* binding */ PropertyWrite), 3496/* harmony export */ "R3BoundTarget": () => (/* binding */ R3BoundTarget), 3497/* harmony export */ "R3Identifiers": () => (/* binding */ Identifiers), 3498/* harmony export */ "R3SelectorScopeMode": () => (/* binding */ R3SelectorScopeMode), 3499/* harmony export */ "R3TargetBinder": () => (/* binding */ R3TargetBinder), 3500/* harmony export */ "R3TemplateDependencyKind": () => (/* binding */ R3TemplateDependencyKind), 3501/* harmony export */ "ReadKeyExpr": () => (/* binding */ ReadKeyExpr),
3502/* harmony export */ "ReadPropExpr": () => (/* binding */ ReadPropExpr), 3503/* harmony export */ "ReadVarExpr": () => (/* binding */ ReadVarExpr), 3504/* harmony export */ "RecursiveAstVisitor": () => (/* binding */ RecursiveAstVisitor), 3505/* harmony export */ "RecursiveVisitor": () => (/* binding */ RecursiveVisitor), 3506/* harmony export */ "ResourceLoader": () => (/* binding */ ResourceLoader), 3507/* harmony export */ "ReturnStatement": () => (/* binding */ ReturnStatement), 3508/* harmony export */ "STRING_TYPE": () => (/* binding */ STRING_TYPE), 3509/* harmony export */ "SafeCall": () => (/* binding */ SafeCall), 3510/* harmony export */ "SafeKeyedRead": () => (/* binding */ SafeKeyedRead), 3511/* harmony export */ "SafePropertyRead": () => (/* binding */ SafePropertyRead), 3512/* harmony export */ "SelectorContext": () => (/* binding */ SelectorContext), 3513/* harmony export */ "SelectorListContext": () => (/* binding */ SelectorListContext), 3514/* harmony export */ "SelectorMatcher": () => (/* binding */ SelectorMatcher), 3515/* harmony export */ "Serializer": () => (/* binding */ Serializer), 3516/* harmony export */ "SplitInterpolation": () => (/* binding */ SplitInterpolation), 3517/* harmony export */ "Statement": () => (/* binding */ Statement), 3518/* harmony export */ "StmtModifier": () => (/* binding */ StmtModifier), 3519/* harmony export */ "TagContentType": () => (/* binding */ TagContentType), 3520/* harmony export */ "TaggedTemplateExpr": () => (/* binding */ TaggedTemplateExpr), 3521/* harmony export */ "TemplateBindingParseResult": () => (/* binding */ TemplateBindingParseResult), 3522/* harmony export */ "TemplateLiteral": () => (/* binding */ TemplateLiteral), 3523/* harmony export */ "TemplateLiteralElement": () => (/* binding */ TemplateLiteralElement), 3524/* harmony export */ "Text": () => (/* binding */ Text), 3525/* harmony export */ "ThisReceiver": () => (/* binding */ ThisReceiver), 3526/* harmony export */ "TmplAstBoundAttribute": () => (/* binding */ BoundAttribute), 3527/* harmony export */ "TmplAstBoundEvent": () => (/* binding */ BoundEvent), 3528/* harmony export */ "TmplAstBoundText": () => (/* binding */ BoundText), 3529/* harmony export */ "TmplAstContent": () => (/* binding */ Content), 3530/* harmony export */ "TmplAstElement": () => (/* binding */ Element$1), 3531/* harmony export */ "TmplAstIcu": () => (/* binding */ Icu$1), 3532/* harmony export */ "TmplAstRecursiveVisitor": () => (/* binding */ RecursiveVisitor$1), 3533/* harmony export */ "TmplAstReference": () => (/* binding */ Reference), 3534/* harmony export */ "TmplAstTemplate": () => (/* binding */ Template), 3535/* harmony export */ "TmplAstText": () => (/* binding */ Text$3), 3536/* harmony export */ "TmplAstTextAttribute": () => (/* binding */ TextAttribute), 3537/* harmony export */ "TmplAstVariable": () => (/* binding */ Variable), 3538/* harmony export */ "Token": () => (/* binding */ Token), 3539/* harmony export */ "TokenType": () => (/* binding */ TokenType), 3540/* harmony export */ "TreeError": () => (/* binding */ TreeError), 3541/* harmony export */ "Type": () => (/* binding */ Type), 3542/* harmony export */ "TypeModifier": () => (/* binding */ TypeModifier), 3543/* harmony export */ "TypeofExpr": () => (/* binding */ TypeofExpr), 3544/* harmony export */ "Unary": () => (/* binding */ Unary), 3545/* harmony export */ "UnaryOperator": () => (/* binding */ UnaryOperator), 3546/* harmony export */ "UnaryOperatorExpr": () => (/* binding */ UnaryOperatorExpr), 3547/* harmony export */ "VERSION": () => (/* binding */ VERSION), 3548/* harmony export */ "VariableBinding": () => (/* binding */ VariableBinding), 3549/* harmony export */ "Version": () => (/* binding */ Version), 3550/* harmony export */ "ViewEncapsulation": () => (/* binding */ ViewEncapsulation), 3551/* harmony export */ "WrappedNodeExpr": () => (/* binding */ WrappedNodeExpr), 3552/* harmony export */ "WriteKeyExpr": () => (/* binding */ WriteKeyExpr), 3553/* harmony export */ "WritePropExpr": () => (/* binding */ WritePropExpr),
3554/* harmony export */ "WriteVarExpr": () => (/* binding */ WriteVarExpr), 3555/* harmony export */ "Xliff": () => (/* binding */ Xliff), 3556/* harmony export */ "Xliff2": () => (/* binding */ Xliff2), 3557/* harmony export */ "Xmb": () => (/* binding */ Xmb), 3558/* harmony export */ "XmlParser": () => (/* binding */ XmlParser), 3559/* harmony export */ "Xtb": () => (/* binding */ Xtb), 3560/* harmony export */ "_ParseAST": () => (/* binding */ _ParseAST), 3561/* harmony export */ "compileClassMetadata": () => (/* binding */ compileClassMetadata), 3562/* harmony export */ "compileComponentFromMetadata": () => (/* binding */ compileComponentFromMetadata), 3563/* harmony export */ "compileDeclareClassMetadata": () => (/* binding */ compileDeclareClassMetadata), 3564/* harmony export */ "compileDeclareComponentFromMetadata": () => (/* binding */ compileDeclareComponentFromMetadata), 3565/* harmony export */ "compileDeclareDirectiveFromMetadata": () => (/* binding */ compileDeclareDirectiveFromMetadata), 3566/* harmony export */ "compileDeclareFactoryFunction": () => (/* binding */ compileDeclareFactoryFunction), 3567/* harmony export */ "compileDeclareInjectableFromMetadata": () => (/* binding */ compileDeclareInjectableFromMetadata), 3568/* harmony export */ "compileDeclareInjectorFromMetadata": () => (/* binding */ compileDeclareInjectorFromMetadata), 3569/* harmony export */ "compileDeclareNgModuleFromMetadata": () => (/* binding */ compileDeclareNgModuleFromMetadata), 3570/* harmony export */ "compileDeclarePipeFromMetadata": () => (/* binding */ compileDeclarePipeFromMetadata), 3571/* harmony export */ "compileDirectiveFromMetadata": () => (/* binding */ compileDirectiveFromMetadata), 3572/* harmony export */ "compileFactoryFunction": () => (/* binding */ compileFactoryFunction), 3573/* harmony export */ "compileInjectable": () => (/* binding */ compileInjectable), 3574/* harmony export */ "compileInjector": () => (/* binding */ compileInjector), 3575/* harmony export */ "compileNgModule": () => (/* binding */ compileNgModule), 3576/* harmony export */ "compilePipeFromMetadata": () => (/* binding */ compilePipeFromMetadata), 3577/* harmony export */ "computeMsgId": () => (/* binding */ computeMsgId), 3578/* harmony export */ "core": () => (/* binding */ core), 3579/* harmony export */ "createInjectableType": () => (/* binding */ createInjectableType), 3580/* harmony export */ "createMayBeForwardRefExpression": () => (/* binding */ createMayBeForwardRefExpression), 3581/* harmony export */ "devOnlyGuardedExpression": () => (/* binding */ devOnlyGuardedExpression), 3582/* harmony export */ "emitDistinctChangesOnlyDefaultValue": () => (/* binding */ emitDistinctChangesOnlyDefaultValue), 3583/* harmony export */ "getHtmlTagDefinition": () => (/* binding */ getHtmlTagDefinition), 3584/* harmony export */ "getNsPrefix": () => (/* binding */ getNsPrefix), 3585/* harmony export */ "getSafePropertyAccessString": () => (/* binding */ getSafePropertyAccessString), 3586/* harmony export */ "identifierName": () => (/* binding */ identifierName), 3587/* harmony export */ "isIdentifier": () => (/* binding */ isIdentifier), 3588/* harmony export */ "isNgContainer": () => (/* binding */ isNgContainer), 3589/* harmony export */ "isNgContent": () => (/* binding */ isNgContent), 3590/* harmony export */ "isNgTemplate": () => (/* binding */ isNgTemplate), 3591/* harmony export */ "jsDocComment": () => (/* binding */ jsDocComment), 3592/* harmony export */ "leadingComment": () => (/* binding */ leadingComment), 3593/* harmony export */ "literalMap": () => (/* binding */ literalMap), 3594/* harmony export */ "makeBindingParser": () => (/* binding */ makeBindingParser), 3595/* harmony export */ "mergeNsAndName": () => (/* binding */ mergeNsAndName), 3596/* harmony export */ "outputAst": () => (/* binding */ output_ast), 3597/* harmony export */ "parseHostBindings": () => (/* binding */ parseHostBindings), 3598/* harmony export */ "parseTemplate": () => (/* binding */ parseTemplate), 3599/* harmony export */ "preserveWhitespacesDefault": () => (/* binding */ preserveWhitespacesDefault), 3600/* harmony export */ "publishFacade": () => (/* binding */ publishFacade), 3601/* harmony export */ "r3JitTypeSourceSpan": () => (/* binding */ r3JitTypeSourceSpan), 3602/* harmony export */ "sanitizeIdentifier": () => (/* binding */ sanitizeIdentifier), 3603/* harmony export */ "splitNsName": () => (/* binding */ splitNsName), 3604/* harmony export */ "verifyHostBindings": () => (/* binding */ verifyHostBindings), 3605/* harmony export */ "visitAll": () => (/* binding */ visitAll) 3606/* harmony export */ }); 3607/** 3608 * @license Angular v14.2.12 3609 * (c) 2010-2022 Google LLC. https://angular.io/ 3610 * License: MIT 3611 */ 3612 3613/** 3614 * @license 3615 * Copyright Google LLC All Rights Reserved. 3616 * 3617 * Use of this source code is governed by an MIT-style license that can be 3618 * found in the LICENSE file at https://angular.io/license 3619 */ 3620var TagContentType; 3621 3622(function (TagContentType) { 3623 TagContentType[TagContentType["RAW_TEXT"] = 0] = "RAW_TEXT"; 3624 TagContentType[TagContentType["ESCAPABLE_RAW_TEXT"] = 1] = "ESCAPABLE_RAW_TEXT"; 3625 TagContentType[TagContentType["PARSABLE_DATA"] = 2] = "PARSABLE_DATA"; 3626})(TagContentType || (TagContentType = {})); 3627 3628function splitNsName(elementName) { 3629 if (elementName[0] != ':') { 3630 return [null, elementName]; 3631 } 3632 3633 const colonIndex = elementName.indexOf(':', 1); 3634 3635 if (colonIndex === -1) { 3636 throw new Error(`Unsupported format "${elementName}" expecting ":namespace:name"`); 3637 } 3638 3639 return [elementName.slice(1, colonIndex), elementName.slice(colonIndex + 1)]; 3640} // `<ng-container>` tags work the same regardless the namespace 3641 3642 3643function isNgContainer(tagName) { 3644 return splitNsName(tagName)[1] === 'ng-container'; 3645} // `<ng-content>` tags work the same regardless the namespace 3646 3647 3648function isNgContent(tagName) { 3649 return splitNsName(tagName)[1] === 'ng-content'; 3650} // `<ng-template>` tags work the same regardless the namespace 3651 3652 3653function isNgTemplate(tagName) { 3654 return splitNsName(tagName)[1] === 'ng-template'; 3655} 3656 3657function getNsPrefix(fullName) { 3658 return fullName === null ? null : splitNsName(fullName)[0]; 3659} 3660 3661function mergeNsAndName(prefix, localName) { 3662 return prefix ? `:${prefix}:${localName}` : localName; 3663} 3664/** 3665 * @license 3666 * Copyright Google LLC All Rights Reserved. 3667 * 3668 * Use of this source code is governed by an MIT-style license that can be 3669 * found in the LICENSE file at https://angular.io/license 3670 */ 3671 3672 3673class HtmlTagDefinition { 3674 constructor({ 3675 closedByChildren, 3676 implicitNamespacePrefix, 3677 contentType = TagContentType.PARSABLE_DATA, 3678 closedByParent = false, 3679 isVoid = false, 3680 ignoreFirstLf = false, 3681 preventNamespaceInheritance = false 3682 }
3682 = {}) { 3683 this.closedByChildren = {}; 3684 this.closedByParent = false; 3685 this.canSelfClose = false; 3686 3687 if (closedByChildren && closedByChildren.length > 0) { 3688 closedByChildren.forEach(tagName => this.closedByChildren[tagName] = true); 3689 } 3690 3691 this.isVoid = isVoid; 3692 this.closedByParent = closedByParent || isVoid; 3693 this.implicitNamespacePrefix = implicitNamespacePrefix || null; 3694 this.contentType = contentType; 3695 this.ignoreFirstLf = ignoreFirstLf; 3696 this.preventNamespaceInheritance = preventNamespaceInheritance; 3697 } 3698 3699 isClosedByChild(name) { 3700 return this.isVoid || name.toLowerCase() in this.closedByChildren; 3701 } 3702 3703 getContentType(prefix) { 3704 if (typeof this.contentType === 'object') { 3705 const overrideType = prefix === undefined ? undefined : this.contentType[prefix]; 3706 return overrideType ?? this.contentType.default; 3707 } 3708 3709 return this.contentType; 3710 } 3711 3712} 3713 3714let _DEFAULT_TAG_DEFINITION; // see https://www.w3.org/TR/html51/syntax.html#optional-tags 3715// This implementation does not fully conform to the HTML5 spec. 3716 3717 3718let TAG_DEFINITIONS; 3719 3720function getHtmlTagDefinition(tagName) { 3721 if (!TAG_DEFINITIONS) { 3722 _DEFAULT_TAG_DEFINITION = new HtmlTagDefinition(); 3723 TAG_DEFINITIONS = { 3724 'base': new HtmlTagDefinition({ 3725 isVoid: true 3726 }), 3727 'meta': new HtmlTagDefinition({ 3728 isVoid: true 3729 }), 3730 'area': new HtmlTagDefinition({ 3731 isVoid: true 3732 }), 3733 'embed': new HtmlTagDefinition({ 3734 isVoid: true 3735 }), 3736 'link': new HtmlTagDefinition({ 3737 isVoid: true 3738 }), 3739 'img': new HtmlTagDefinition({ 3740 isVoid: true 3741 }), 3742 'input': new HtmlTagDefinition({ 3743 isVoid: true 3744 }), 3745 'param': new HtmlTagDefinition({ 3746 isVoid: true 3747 }), 3748 'hr': new HtmlTagDefinition({ 3749 isVoid: true 3750 }), 3751 'br': new HtmlTagDefinition({ 3752 isVoid: true 3753 }), 3754 'source': new HtmlTagDefinition({ 3755 isVoid: true 3756 }), 3757 'track': new HtmlTagDefinition({ 3758 isVoid: true 3759 }), 3760 'wbr': new HtmlTagDefinition({ 3761 isVoid: true 3762 }), 3763 'p': new HtmlTagDefinition({ 3764 closedByChildren: ['address', 'article', 'aside', 'blockquote', 'div', 'dl', 'fieldset', 'footer', 'form', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'header', 'hgroup', 'hr', 'main', 'nav', 'ol', 'p', 'pre', 'section', 'table', 'ul'], 3765 closedByParent: true 3766 }), 3767 'thead': new HtmlTagDefinition({ 3768 closedByChildren: ['tbody', 'tfoot'] 3769 }), 3770 'tbody': new HtmlTagDefinition({ 3771 closedByChildren: ['tbody', 'tfoot'], 3772 closedByParent: true 3773 }), 3774 'tfoot': new HtmlTagDefinition({ 3775 closedByChildren: ['tbody'], 3776 closedByParent: true 3777 }), 3778 'tr': new HtmlTagDefinition({ 3779 closedByChildren: ['tr'], 3780 closedByParent: true 3781 }), 3782 'td': new HtmlTagDefinition({ 3783 closedByChildren: ['td', 'th'], 3784 closedByParent: true 3785 }), 3786 'th': new HtmlTagDefinition({ 3787 closedByChildren: ['td', 'th'], 3788 closedByParent: true 3789 }), 3790 'col': new HtmlTagDefinition({ 3791 isVoid: true 3792 }), 3793 'svg': new HtmlTagDefinition({ 3794 implicitNamespacePrefix: 'svg' 3795 }), 3796 'foreignObject': new HtmlTagDefinition({ 3797 // Usually the implicit namespace here would be redundant since it will be inherited from 3798 // the parent `svg`, but we have to do it for `foreignObject`, because the way the parser 3799 // works is that the parent node of an end tag is its own start tag which means that 3800 // the `preventNamespaceInheritance` on `foreignObject` would have it default to the 3801 // implicit namespace which is `html`, unless specified otherwise. 3802 implicitNamespacePrefix: 'svg', 3803 // We want to prevent children of foreignObject from inheriting its namespace, because 3804 // the point of the element is to allow nodes from other namespaces to be inserted. 3805 preventNamespaceInheritance: true 3806 }), 3807 'math': new HtmlTagDefinition({ 3808 implicitNamespacePrefix: 'math' 3809 }), 3810 'li': new HtmlTagDefinition({ 3811 closedByChildren: ['li'], 3812 closedByParent: true 3813 }), 3814 'dt': new HtmlTagDefinition({ 3815 closedByChildren: ['dt', 'dd'] 3816 }), 3817 'dd': new HtmlTagDefinition({ 3818 closedByChildren: ['dt', 'dd'], 3819 closedByParent: true 3820 }), 3821 'rb': new HtmlTagDefinition({ 3822 closedByChildren: ['rb', 'rt', 'rtc', 'rp'], 3823 closedByParent: true 3824 }), 3825 'rt': new HtmlTagDefinition({ 3826 closedByChildren: ['rb', 'rt', 'rtc', 'rp'], 3827 closedByParent: true 3828 }), 3829 'rtc': new HtmlTagDefinition({ 3830 closedByChildren: ['rb', 'rtc', 'rp'], 3831 closedByParent: true 3832 }), 3833 'rp': new HtmlTagDefinition({ 3834 closedByChildren: ['rb', 'rt', 'rtc', 'rp'], 3835 closedByParent: true 3836 }), 3837 'optgroup': new HtmlTagDefinition({ 3838 closedByChildren: ['optgroup'], 3839 closedByParent: true 3840 }), 3841 'option': new HtmlTagDefinition({ 3842 closedByChildren: ['option', 'optgroup'], 3843 closedByParent: true 3844 }), 3845 'pre': new HtmlTagDefinition({ 3846 ignoreFirstLf: true 3847 }), 3848 'listing': new HtmlTagDefinition({ 3849 ignoreFirstLf: true 3850 }), 3851 'style': new HtmlTagDefinition({ 3852 contentType: TagContentType.RAW_TEXT 3853 }), 3854 'script': new HtmlTagDefinition({ 3855 contentType: TagContentType.RAW_TEXT 3856 }), 3857 'title': new HtmlTagDefinition({ 3858 // The browser supports two separate `title` tags which have to use
3859 // a different content type: `HTMLTitleElement` and `SVGTitleElement` 3860 contentType: { 3861 default: TagContentType.ESCAPABLE_RAW_TEXT, 3862 svg: TagContentType.PARSABLE_DATA 3863 } 3864 }), 3865 'textarea': new HtmlTagDefinition({ 3866 contentType: TagContentType.ESCAPABLE_RAW_TEXT, 3867 ignoreFirstLf: true 3868 }) 3869 }; 3870 } // We have to make both a case-sensitive and a case-insensitive lookup, because 3871 // HTML tag names are case insensitive, whereas some SVG tags are case sensitive. 3872 3873 3874 return TAG_DEFINITIONS[tagName] ?? TAG_DEFINITIONS[tagName.toLowerCase()] ?? _DEFAULT_TAG_DEFINITION; 3875} 3876/** 3877 * @license 3878 * Copyright Google LLC All Rights Reserved. 3879 * 3880 * Use of this source code is governed by an MIT-style license that can be 3881 * found in the LICENSE file at https://angular.io/license 3882 */ 3883 3884 3885const _SELECTOR_REGEXP = new RegExp('(\\:not\\()|' + // 1: ":not(" 3886'(([\\.\\#]?)[-\\w]+)|' + // 2: "tag"; 3: "."/"#"; 3887// "-" should appear first in the regexp below as FF31 parses "[.-\w]" as a range 3888// 4: attribute; 5: attribute_string; 6: attribute_value 3889'(?:\\[([-.\\w*\\\\$]+)(?:=([\"\']?)([^\\]\"\']*)\\5)?\\])|' + // "[name]", "[name=value]", 3890// "[name="value"]", 3891// "[name='value']" 3892'(\\))|' + // 7: ")" 3893'(\\s*,\\s*)', // 8: "," 3894'g'); 3895/** 3896 * A css selector contains an element name, 3897 * css classes and attribute/value pairs with the purpose 3898 * of selecting subsets out of them. 3899 */ 3900 3901 3902class CssSelector { 3903 constructor() { 3904 this.element = null; 3905 this.classNames = []; 3906 /** 3907 * The selectors are encoded in pairs where: 3908 * - even locations are attribute names 3909 * - odd locations are attribute values. 3910 * 3911 * Example: 3912 * Selector: `[key1=value1][key2]` would parse to: 3913 * ``` 3914 * ['key1', 'value1', 'key2', ''] 3915 * ``` 3916 */ 3917 3918 this.attrs = []; 3919 this.notSelectors = []; 3920 } 3921 3922 static parse(selector) { 3923 const results = []; 3924 3925 const _addResult = (res, cssSel) => { 3926 if (cssSel.notSelectors.length > 0 && !cssSel.element && cssSel.classNames.length == 0 && cssSel.attrs.length == 0) { 3927 cssSel.element = '*'; 3928 } 3929 3930 res.push(cssSel); 3931 }; 3932 3933 let cssSelector = new CssSelector(); 3934 let match; 3935 let current = cssSelector; 3936 let inNot = false; 3937 _SELECTOR_REGEXP.lastIndex = 0; 3938 3939 while (match = _SELECTOR_REGEXP.exec(selector)) { 3940 if (match[1 3941 /* SelectorRegexp.NOT */ 3942 ]) { 3943 if (inNot) { 3944 throw new Error('Nesting :not in a selector is not allowed'); 3945 } 3946 3947 inNot = true; 3948 current = new CssSelector(); 3949 cssSelector.notSelectors.push(current); 3950 } 3951 3952 const tag = match[2 3953 /* SelectorRegexp.TAG */ 3954 ]; 3955 3956 if (tag) { 3957 const prefix = match[3 3958 /* SelectorRegexp.PREFIX */ 3959 ]; 3960 3961 if (prefix === '#') { 3962 // #hash 3963 current.addAttribute('id', tag.slice(1)); 3964 } else if (prefix === '.') { 3965 // Class 3966 current.addClassName(tag.slice(1)); 3967 } else { 3968 // Element 3969 current.setElement(tag); 3970 } 3971 } 3972 3973 const attribute = match[4 3974 /* SelectorRegexp.ATTRIBUTE */ 3975 ]; 3976 3977 if (attribute) { 3978 current.addAttribute(current.unescapeAttribute(attribute), match[6 3979 /* SelectorRegexp.ATTRIBUTE_VALUE */ 3980 ]); 3981 } 3982 3983 if (match[7 3984 /* SelectorRegexp.NOT_END */ 3985 ]) { 3986 inNot = false; 3987 current = cssSelector; 3988 } 3989 3990 if (match[8 3991 /* SelectorRegexp.SEPARATOR */ 3992 ]) { 3993 if (inNot) { 3994 throw new Error('Multiple selectors in :not are not supported'); 3995 } 3996 3997 _addResult(results, cssSelector); 3998 3999 cssSelector = current = new CssSelector(); 4000 } 4001 } 4002 4003 _addResult(results, cssSelector); 4004 4005 return results; 4006 } 4007 /** 4008 * Unescape `\$` sequences from the CSS attribute selector. 4009 * 4010 * This is needed because `$` can have a special meaning in CSS selectors, 4011 * but we might want to match an attribute that contains `$`. 4012 * [MDN web link for more 4013 * info](https://developer.mozilla.org/en-US/docs/Web/CSS/Attribute_selectors). 4014 * @param attr the attribute to unescape. 4015 * @returns the unescaped string. 4016 */ 4017 4018 4019 unescapeAttribute(attr) { 4020 let result = ''; 4021 let escaping = false;
4022 4023 for (let i = 0; i < attr.length; i++) { 4024 const char = attr.charAt(i); 4025 4026 if (char === '\\') { 4027 escaping = true; 4028 continue; 4029 } 4030 4031 if (char === '$' && !escaping) { 4032 throw new Error(`Error in attribute selector "${attr}". ` + `Unescaped "$" is not supported. Please escape with "\\$".`); 4033 } 4034 4035 escaping = false; 4036 result += char; 4037 } 4038 4039 return result; 4040 } 4041 /** 4042 * Escape `$` sequences from the CSS attribute selector. 4043 * 4044 * This is needed because `$` can have a special meaning in CSS selectors, 4045 * with this method we are escaping `$` with `\$'. 4046 * [MDN web link for more 4047 * info](https://developer.mozilla.org/en-US/docs/Web/CSS/Attribute_selectors). 4048 * @param attr the attribute to escape. 4049 * @returns the escaped string. 4050 */ 4051 4052 4053 escapeAttribute(attr) { 4054 return attr.replace(/\\/g, '\\\\').replace(/\$/g, '\\$'); 4055 } 4056 4057 isElementSelector() { 4058 return this.hasElementSelector() && this.classNames.length == 0 && this.attrs.length == 0 && this.notSelectors.length === 0; 4059 } 4060 4061 hasElementSelector() { 4062 return !!this.element; 4063 } 4064 4065 setElement(element = null) { 4066 this.element = element; 4067 } 4068 /** Gets a template string for an element that matches the selector. */ 4069 4070 4071 getMatchingElementTemplate() { 4072 const tagName = this.element || 'div'; 4073 const classAttr = this.classNames.length > 0 ? ` class="${this.classNames.join(' ')}"` : ''; 4074 let attrs = ''; 4075 4076 for (let i = 0; i < this.attrs.length; i += 2) { 4077 const attrName = this.attrs[i]; 4078 const attrValue = this.attrs[i + 1] !== '' ? `="${this.attrs[i + 1]}"` : ''; 4079 attrs += ` ${attrName}${attrValue}`; 4080 } 4081 4082 return getHtmlTagDefinition(tagName).isVoid ? `<${tagName}${classAttr}${attrs}/>` : `<${tagName}${classAttr}${attrs}></${tagName}>`; 4083 } 4084 4085 getAttrs() { 4086 const result = []; 4087 4088 if (this.classNames.length > 0) { 4089 result.push('class', this.classNames.join(' ')); 4090 } 4091 4092 return result.concat(this.attrs); 4093 } 4094 4095 addAttribute(name, value = '') { 4096 this.attrs.push(name, value && value.toLowerCase() || ''); 4097 } 4098 4099 addClassName(name) { 4100 this.classNames.push(name.toLowerCase()); 4101 } 4102 4103 toString() { 4104 let res = this.element || ''; 4105 4106 if (this.classNames) { 4107 this.classNames.forEach(klass => res += `.${klass}`); 4108 } 4109 4110 if (this.attrs) { 4111 for (let i = 0; i < this.attrs.length; i += 2) { 4112 const name = this.escapeAttribute(this.attrs[i]); 4113 const value = this.attrs[i + 1]; 4114 res += `[${name}${value ? '=' + value : ''}]`; 4115 } 4116 } 4117 4118 this.notSelectors.forEach(notSelector => res += `:not(${notSelector})`); 4119 return res; 4120 } 4121 4122} 4123/** 4124 * Reads a list of CssSelectors and allows to calculate which ones 4125 * are contained in a given CssSelector. 4126 */ 4127 4128 4129class SelectorMatcher { 4130 constructor() { 4131 this._elementMap = new Map(); 4132 this._elementPartialMap = new Map(); 4133 this._classMap = new Map(); 4134 this._classPartialMap = new Map(); 4135 this._attrValueMap = new Map(); 4136 this._attrValuePartialMap = new Map(); 4137 this._listContexts = []; 4138 } 4139 4140 static createNotMatcher(notSelectors) { 4141 const notMatcher = new SelectorMatcher(); 4142 notMatcher.addSelectables(notSelectors, null); 4143 return notMatcher; 4144 } 4145 4146 addSelectables(cssSelectors, callbackCtxt) { 4147 let listContext = null; 4148 4149 if (cssSelectors.length > 1) { 4150 listContext = new SelectorListContext(cssSelectors); 4151 4152 this._listContexts.push(listContext); 4153 } 4154 4155 for (let i = 0; i < cssSelectors.length; i++) { 4156 this._addSelectable(cssSelectors[i], callbackCtxt, listContext); 4157 } 4158 } 4159 /** 4160 * Add an object that can be found later on by calling `match`. 4161 * @param cssSelector A css selector 4162 * @param callbackCtxt An opaque object that will be given to the callback of the `match` function 4163 */ 4164 4165 4166 _addSelectable(cssSelector, callbackCtxt, listContext) { 4167 let matcher = this; 4168 const element = cssSelector.element; 4169 const classNames = cssSelector.classNames; 4170 const attrs = cssSelector.attrs; 4171 const selectable = new SelectorContext(cssSelector, callbackCtxt, listContext); 4172 4173 if (element) { 4174 const isTerminal = attrs.length === 0 && classNames.length === 0; 4175 4176 if (isTerminal) { 4177 this._addTerminal(matcher._elementMap, element, selectable); 4178 } else { 4179 matcher = this._addPartial(matcher._elementPartialMap, element); 4180 } 4181 } 4182 4183 if (classNames) { 4184 for (let i = 0; i < classNames.length; i++) { 4185 const isTerminal = attrs.length === 0 && i === classNames.length - 1; 4186 const className = classNames[i]; 4187 4188 if (isTerminal) { 4189 this._addTerminal(matcher._classMap, className, selectable); 4190 } else { 4191 matcher = this._addPartial(matcher._classPartialMap, className); 4192 } 4193 } 4194 } 4195 4196 if (attrs) { 4197 for (let i = 0; i < attrs.length; i += 2) { 4198 const isTerminal = i === attrs.length - 2; 4199 const name = attrs[i]; 4200 const value = attrs[i + 1]; 4201 4202 if (isTerminal) { 4203 const terminalMap = matcher._attrValueMap;
4204 let terminalValuesMap = terminalMap.get(name); 4205 4206 if (!terminalValuesMap) { 4207 terminalValuesMap = new Map(); 4208 terminalMap.set(name, terminalValuesMap); 4209 } 4210 4211 this._addTerminal(terminalValuesMap, value, selectable); 4212 } else { 4213 const partialMap = matcher._attrValuePartialMap; 4214 let partialValuesMap = partialMap.get(name); 4215 4216 if (!partialValuesMap) { 4217 partialValuesMap = new Map(); 4218 partialMap.set(name, partialValuesMap); 4219 } 4220 4221 matcher = this._addPartial(partialValuesMap, value); 4222 } 4223 } 4224 } 4225 } 4226 4227 _addTerminal(map, name, selectable) { 4228 let terminalList = map.get(name); 4229 4230 if (!terminalList) { 4231 terminalList = []; 4232 map.set(name, terminalList); 4233 } 4234 4235 terminalList.push(selectable); 4236 } 4237 4238 _addPartial(map, name) { 4239 let matcher = map.get(name); 4240 4241 if (!matcher) { 4242 matcher = new SelectorMatcher(); 4243 map.set(name, matcher); 4244 } 4245 4246 return matcher; 4247 } 4248 /** 4249 * Find the objects that have been added via `addSelectable` 4250 * whose css selector is contained in the given css selector. 4251 * @param cssSelector A css selector 4252 * @param matchedCallback This callback will be called with the object handed into `addSelectable` 4253 * @return boolean true if a match was found 4254 */ 4255 4256 4257 match(cssSelector, matchedCallback) { 4258 let result = false;
4259 const element = cssSelector.element; 4260 const classNames = cssSelector.classNames; 4261 const attrs = cssSelector.attrs; 4262 4263 for (let i = 0; i < this._listContexts.length; i++) { 4264 this._listContexts[i].alreadyMatched = false; 4265 } 4266 4267 result = this._matchTerminal(this._elementMap, element, cssSelector, matchedCallback) || result; 4268 result = this._matchPartial(this._elementPartialMap, element, cssSelector, matchedCallback) || result; 4269 4270 if (classNames) { 4271 for (let i = 0; i < classNames.length; i++) { 4272 const className = classNames[i]; 4273 result = this._matchTerminal(this._classMap, className, cssSelector, matchedCallback) || result; 4274 result = this._matchPartial(this._classPartialMap, className, cssSelector, matchedCallback) || result; 4275 } 4276 } 4277 4278 if (attrs) { 4279 for (let i = 0; i < attrs.length; i += 2) { 4280 const name = attrs[i]; 4281 const value = attrs[i + 1]; 4282 4283 const terminalValuesMap = this._attrValueMap.get(name); 4284 4285 if (value) { 4286 result = this._matchTerminal(terminalValuesMap, '', cssSelector, matchedCallback) || result; 4287 } 4288 4289 result = this._matchTerminal(terminalValuesMap, value, cssSelector, matchedCallback) || result; 4290 4291 const partialValuesMap = this._attrValuePartialMap.get(name); 4292 4293 if (value) { 4294 result = this._matchPartial(partialValuesMap, '', cssSelector, matchedCallback) || result; 4295 } 4296 4297 result = this._matchPartial(partialValuesMap, value, cssSelector, matchedCallback) || result; 4298 } 4299 } 4300 4301 return result; 4302 } 4303 /** @internal */ 4304 4305 4306 _matchTerminal(map, name, cssSelector, matchedCallback) { 4307 if (!map || typeof name !== 'string') { 4308 return false; 4309 } 4310 4311 let selectables = map.get(name) || []; 4312 const starSelectables = map.get('*'); 4313 4314 if (starSelectables) { 4315 selectables = selectables.concat(starSelectables); 4316 } 4317 4318 if (selectables.length === 0) { 4319 return false; 4320 } 4321 4322 let selectable; 4323 let result = false;
4324 4325 for (let i = 0; i < selectables.length; i++) { 4326 selectable = selectables[i]; 4327 result = selectable.finalize(cssSelector, matchedCallback) || result; 4328 } 4329 4330 return result; 4331 } 4332 /** @internal */ 4333 4334 4335 _matchPartial(map, name, cssSelector, matchedCallback) { 4336 if (!map || typeof name !== 'string') { 4337 return false; 4338 } 4339 4340 const nestedSelector = map.get(name); 4341 4342 if (!nestedSelector) { 4343 return false; 4344 } // TODO(perf): get rid of recursion and measure again 4345 // TODO(perf): don't pass the whole selector into the recursion, 4346 // but only the not processed parts 4347 4348 4349 return nestedSelector.match(cssSelector, matchedCallback); 4350 } 4351 4352} 4353 4354class SelectorListContext { 4355 constructor(selectors) { 4356 this.selectors = selectors; 4357 this.alreadyMatched = false; 4358 } 4359 4360} // Store context to pass back selector and context when a selector is matched 4361 4362 4363class SelectorContext { 4364 constructor(selector, cbContext, listContext) { 4365 this.selector = selector; 4366 this.cbContext = cbContext; 4367 this.listContext = listContext; 4368 this.notSelectors = selector.notSelectors; 4369 } 4370 4371 finalize(cssSelector, callback) { 4372 let result = true; 4373 4374 if (this.notSelectors.length > 0 && (!this.listContext || !this.listContext.alreadyMatched)) { 4375 const notMatcher = SelectorMatcher.createNotMatcher(this.notSelectors); 4376 result = !notMatcher.match(cssSelector, null); 4377 } 4378 4379 if (result && callback && (!this.listContext || !this.listContext.alreadyMatched)) { 4380 if (this.listContext) { 4381 this.listContext.alreadyMatched = true; 4382 } 4383 4384 callback(this.selector, this.cbContext); 4385 } 4386 4387 return result; 4388 } 4389 4390} 4391/** 4392 * @license 4393 * Copyright Google LLC All Rights Reserved. 4394 * 4395 * Use of this source code is governed by an MIT-style license that can be 4396 * found in the LICENSE file at https://angular.io/license 4397 */ 4398// Stores the default value of `emitDistinctChangesOnly` when the `emitDistinctChangesOnly` is not 4399// explicitly set. 4400 4401 4402const emitDistinctChangesOnlyDefaultValue = true; 4403var ViewEncapsulation; 4404 4405(function (ViewEncapsulation) { 4406 ViewEncapsulation[ViewEncapsulation["Emulated"] = 0] = "Emulated"; // Historically the 1 value was for `Native` encapsulation which has been removed as of v11. 4407 4408 ViewEncapsulation[ViewEncapsulation["None"] = 2] = "None"; 4409 ViewEncapsulation[ViewEncapsulation["ShadowDom"] = 3] = "ShadowDom"; 4410})(ViewEncapsulation || (ViewEncapsulation = {})); 4411 4412var ChangeDetectionStrategy; 4413 4414(function (ChangeDetectionStrategy) { 4415 ChangeDetectionStrategy[ChangeDetectionStrategy["OnPush"] = 0] = "OnPush"; 4416 ChangeDetectionStrategy[ChangeDetectionStrategy["Default"] = 1] = "Default"; 4417})(ChangeDetectionStrategy || (ChangeDetectionStrategy = {})); 4418 4419const CUSTOM_ELEMENTS_SCHEMA = { 4420 name: 'custom-elements' 4421}; 4422const NO_ERRORS_SCHEMA = { 4423 name: 'no-errors-schema' 4424}; 4425const Type$1 = Function; 4426var SecurityContext; 4427 4428(function (SecurityContext) { 4429 SecurityContext[SecurityContext["NONE"] = 0] = "NONE"; 4430 SecurityContext[SecurityContext["HTML"] = 1] = "HTML"; 4431 SecurityContext[SecurityContext["STYLE"] = 2] = "STYLE"; 4432 SecurityContext[SecurityContext["SCRIPT"] = 3] = "SCRIPT"; 4433 SecurityContext[SecurityContext["URL"] = 4] = "URL"; 4434 SecurityContext[SecurityContext["RESOURCE_URL"] = 5] = "RESOURCE_URL"; 4435})(SecurityContext || (SecurityContext = {})); 4436 4437var MissingTranslationStrategy; 4438 4439(function (MissingTranslationStrategy) { 4440 MissingTranslationStrategy[MissingTranslationStrategy["Error"] = 0] = "Error"; 4441 MissingTranslationStrategy[MissingTranslationStrategy["Warning"] = 1] = "Warning"; 4442 MissingTranslationStrategy[MissingTranslationStrategy["Ignore"] = 2] = "Ignore"; 4443})(MissingTranslationStrategy || (MissingTranslationStrategy = {})); 4444 4445function parserSelectorToSimpleSelector(selector) { 4446 const classes = selector.classNames && selector.classNames.length ? [8 4447 /* SelectorFlags.CLASS */ 4448 , ...selector.classNames] : []; 4449 const elementName = selector.element && selector.element !== '*' ? selector.element : ''; 4450 return [elementName, ...selector.attrs, ...classes]; 4451} 4452 4453function parserSelectorToNegativeSelector(selector) { 4454 const classes = selector.classNames && selector.classNames.length ? [8 4455 /* SelectorFlags.CLASS */ 4456 , ...selector.classNames] : []; 4457 4458 if (selector.element) { 4459 return [1 4460 /* SelectorFlags.NOT */ 4461 | 4 4462 /* SelectorFlags.ELEMENT */ 4463 , selector.element, ...selector.attrs, ...classes]; 4464 } else if (selector.attrs.length) { 4465 return [1 4466 /* SelectorFlags.NOT */ 4467 | 2 4468 /* SelectorFlags.ATTRIBUTE */ 4469 , ...selector.attrs, ...classes]; 4470 } else { 4471 return selector.classNames && selector.classNames.length ? [1 4472 /* SelectorFlags.NOT */ 4473 | 8 4474 /* SelectorFlags.CLASS */ 4475 , ...selector.classNames] : []; 4476 } 4477} 4478 4479function parserSelectorToR3Selector(selector) { 4480 const positive = parserSelectorToSimpleSelector(selector); 4481 const negative = selector.notSelectors && selector.notSelectors.length ? selector.notSelectors.map(notSelector => parserSelectorToNegativeSelector(notSelector)) : []; 4482 return positive.concat(...negative); 4483} 4484 4485function parseSelectorToR3Selector(selector) { 4486 return selector ? CssSelector.parse(selector).map(parserSelectorToR3Selector) : []; 4487} 4488 4489var core = /*#__PURE__*/Object.freeze({ 4490 __proto__: null, 4491 emitDistinctChangesOnlyDefaultValue: emitDistinctChangesOnlyDefaultValue, 4492 4493 get ViewEncapsulation() { 4494 return ViewEncapsulation; 4495 }, 4496 4497 get ChangeDetectionStrategy() { 4498 return ChangeDetectionStrategy; 4499 }, 4500 4501 CUSTOM_ELEMENTS_SCHEMA: CUSTOM_ELEMENTS_SCHEMA,
4502 NO_ERRORS_SCHEMA: NO_ERRORS_SCHEMA, 4503 Type: Type$1, 4504 4505 get SecurityContext() { 4506 return SecurityContext; 4507 }, 4508 4509 get MissingTranslationStrategy() { 4510 return MissingTranslationStrategy; 4511 }, 4512 4513 parseSelectorToR3Selector: parseSelectorToR3Selector 4514}); 4515/** 4516 * @license 4517 * Copyright Google LLC All Rights Reserved. 4518 * 4519 * Use of this source code is governed by an MIT-style license that can be 4520 * found in the LICENSE file at https://angular.io/license 4521 */ 4522 4523const DASH_CASE_REGEXP = /-+([a-z0-9])/g; 4524 4525function dashCaseToCamelCase(input) { 4526 return input.replace(DASH_CASE_REGEXP, (...m) => m[1].toUpperCase()); 4527} 4528 4529function splitAtColon(input, defaultValues) { 4530 return _splitAt(input, ':', defaultValues); 4531} 4532 4533function splitAtPeriod(input, defaultValues) { 4534 return _splitAt(input, '.', defaultValues); 4535} 4536 4537function _splitAt(input, character, defaultValues) { 4538 const characterIndex = input.indexOf(character); 4539 if (characterIndex == -1) return defaultValues; 4540 return [input.slice(0, characterIndex).trim(), input.slice(characterIndex + 1).trim()]; 4541} 4542 4543function noUndefined(val) { 4544 return val === undefined ? null : val; 4545} 4546 4547function error(msg) { 4548 throw new Error(`Internal Error: ${msg}`); 4549} // Escape characters that have a special meaning in Regular Expressions 4550 4551 4552function escapeRegExp(s) { 4553 return s.replace(/([.*+?^=!:${}()|[\]\/\\])/g, '\\$1'); 4554} 4555 4556function utf8Encode(str) { 4557 let encoded = []; 4558 4559 for (let index = 0; index < str.length; index++) {
4560 let codePoint = str.charCodeAt(index); // decode surrogate 4561 // see https://mathiasbynens.be/notes/javascript-encoding#surrogate-formulae 4562 4563 if (codePoint >= 0xd800 && codePoint <= 0xdbff && str.length > index + 1) { 4564 const low = str.charCodeAt(index + 1); 4565 4566 if (low >= 0xdc00 && low <= 0xdfff) { 4567 index++; 4568 codePoint = (codePoint - 0xd800 << 10) + low - 0xdc00 + 0x10000; 4569 } 4570 } 4571 4572 if (codePoint <= 0x7f) { 4573 encoded.push(codePoint); 4574 } else if (codePoint <= 0x7ff) { 4575 encoded.push(codePoint >> 6 & 0x1F | 0xc0, codePoint & 0x3f | 0x80); 4576 } else if (codePoint <= 0xffff) { 4577 encoded.push(codePoint >> 12 | 0xe0, codePoint >> 6 & 0x3f | 0x80, codePoint & 0x3f | 0x80); 4578 } else if (codePoint <= 0x1fffff) { 4579 encoded.push(codePoint >> 18 & 0x07 | 0xf0, codePoint >> 12 & 0x3f | 0x80, codePoint >> 6 & 0x3f | 0x80, codePoint & 0x3f | 0x80); 4580 } 4581 } 4582 4583 return encoded; 4584} 4585 4586function stringify(token) { 4587 if (typeof token === 'string') { 4588 return token; 4589 } 4590 4591 if (Array.isArray(token)) { 4592 return '[' + token.map(stringify).join(', ') + ']'; 4593 } 4594 4595 if (token == null) { 4596 return '' + token; 4597 } 4598 4599 if (token.overriddenName) { 4600 return `${token.overriddenName}`; 4601 } 4602 4603 if (token.name) { 4604 return `${token.name}`; 4605 } 4606 4607 if (!token.toString) { 4608 return 'object'; 4609 } // WARNING: do not try to `JSON.stringify(token)` here 4610 // see https://github.com/angular/angular/issues/23440 4611 4612 4613 const res = token.toString(); 4614 4615 if (res == null) { 4616 return '' + res; 4617 } 4618 4619 const newLineIndex = res.indexOf('\n'); 4620 return newLineIndex === -1 ? res : res.substring(0, newLineIndex); 4621} 4622 4623class Version { 4624 constructor(full) { 4625 this.full = full; 4626 const splits = full.split('.'); 4627 this.major = splits[0]; 4628 this.minor = splits[1]; 4629 this.patch = splits.slice(2).join('.'); 4630 } 4631 4632} // Check `global` first, because in Node tests both `global` and `window` may be defined and our 4633// `_global` variable should point to the NodeJS `global` in that case. Note: Typeof/Instanceof 4634// checks are considered side-effects in Terser. We explicitly mark this as side-effect free: 4635// https://github.com/terser/terser/issues/250. 4636 4637 4638const _global = /* @__PURE__ */(() => typeof global !== 'undefined' && global || typeof window !== 'undefined' && window || typeof self !== 'undefined' && typeof WorkerGlobalScope !== 'undefined' && self instanceof WorkerGlobalScope && self)(); 4639 4640function newArray(size, value) { 4641 const list = []; 4642 4643 for (let i = 0; i < size; i++) { 4644 list.push(value); 4645 } 4646 4647 return list; 4648} 4649/** 4650 * Partitions a given array into 2 arrays, based on a boolean value returned by the condition 4651 * function. 4652 * 4653 * @param arr Input array that should be partitioned 4654 * @param conditionFn Condition function that is called for each item in a given array and returns a 4655 * boolean value. 4656 */ 4657 4658 4659function partitionArray(arr, conditionFn) { 4660 const truthy = []; 4661 const falsy = []; 4662 4663 for (const item of arr) { 4664 (conditionFn(item) ? truthy : falsy).push(item); 4665 } 4666 4667 return [truthy, falsy]; 4668} 4669/** 4670 * @license 4671 * Copyright Google LLC All Rights Reserved. 4672 * 4673 * Use of this source code is governed by an MIT-style license that can be 4674 * found in the LICENSE file at https://angular.io/license 4675 */ 4676 4677/** 4678 * Represents a big integer using a buffer of its individual digits, with the least significant 4679 * digit stored at the beginning of the array (little endian). 4680 * 4681 * For performance reasons, each instance is mutable. The addition operation can be done in-place 4682 * to reduce memory pressure of allocation for the digits array. 4683 */ 4684 4685 4686class BigInteger { 4687 /** 4688 * Creates a big integer using its individual digits in little endian storage. 4689 */ 4690 constructor(digits) { 4691 this.digits = digits; 4692 } 4693 4694 static zero() { 4695 return new BigInteger([0]); 4696 } 4697 4698 static one() { 4699 return new BigInteger([1]); 4700 } 4701 /** 4702 * Creates a clone of this instance. 4703 */ 4704 4705 4706 clone() { 4707 return new BigInteger(this.digits.slice()); 4708 } 4709 /** 4710 * Returns a new big integer with the sum of `this` and `other` as its value. This does not mutate 4711 * `this` but instead returns a new instance, unlike `addToSelf`. 4712 */ 4713 4714 4715 add(other) { 4716 const result = this.clone(); 4717 result.addToSelf(other); 4718 return result; 4719 } 4720 /** 4721 * Adds `other` to the instance itself, thereby mutating its value. 4722 */ 4723 4724 4725 addToSelf(other) { 4726 const maxNrOfDigits = Math.max(this.digits.length, other.digits.length);
4727 let carry = 0; 4728 4729 for (let i = 0; i < maxNrOfDigits; i++) { 4730 let digitSum = carry; 4731 4732 if (i < this.digits.length) { 4733 digitSum += this.digits[i]; 4734 } 4735 4736 if (i < other.digits.length) { 4737 digitSum += other.digits[i]; 4738 } 4739 4740 if (digitSum >= 10) { 4741 this.digits[i] = digitSum - 10; 4742 carry = 1; 4743 } else { 4744 this.digits[i] = digitSum; 4745 carry = 0; 4746 } 4747 } // Apply a remaining carry if needed. 4748 4749 4750 if (carry > 0) { 4751 this.digits[maxNrOfDigits] = 1; 4752 } 4753 } 4754 /** 4755 * Builds the decimal string representation of the big integer. As this is stored in 4756 * little endian, the digits are concatenated in reverse order. 4757 */ 4758 4759 4760 toString() { 4761 let res = ''; 4762 4763 for (let i = this.digits.length - 1; i >= 0; i--) { 4764 res += this.digits[i]; 4765 } 4766 4767 return res; 4768 } 4769 4770} 4771/** 4772 * Represents a big integer which is optimized for multiplication operations, as its power-of-twos 4773 * are memoized. See `multiplyBy()` for details on the multiplication algorithm. 4774 */ 4775 4776 4777class BigIntForMultiplication { 4778 constructor(value) { 4779 this.powerOfTwos = [value]; 4780 } 4781 /** 4782 * Returns the big integer itself. 4783 */ 4784 4785 4786 getValue() { 4787 return this.powerOfTwos[0]; 4788 } 4789 /** 4790 * Computes the value for `num * b`, where `num` is a JS number and `b` is a big integer. The 4791 * value for `b` is represented by a storage model that is optimized for this computation. 4792 * 4793 * This operation is implemented in N(log2(num)) by continuous halving of the number, where the 4794 * least-significant bit (LSB) is tested in each iteration. If the bit is set, the bit's index is 4795 * used as exponent into the power-of-two multiplication of `b`. 4796 * 4797 * As an example, consider the multiplication num=42, b=1337. In binary 42 is 0b00101010 and the 4798 * algorithm unrolls into the following iterations: 4799 * 4800 * Iteration | num | LSB | b * 2^iter | Add? | product 4801 * -----------|------------|------|------------|------|-------- 4802 * 0 | 0b00101010 | 0 | 1337 | No | 0 4803 * 1 | 0b00010101 | 1 | 2674 | Yes | 2674 4804 * 2 | 0b00001010 | 0 | 5348 | No | 2674 4805 * 3 | 0b00000101 | 1 | 10696 | Yes | 13370 4806 * 4 | 0b00000010 | 0 | 21392 | No | 13370 4807 * 5 | 0b00000001 | 1 | 42784 | Yes | 56154 4808 * 6 | 0b00000000 | 0 | 85568 | No | 56154 4809 * 4810 * The computed product of 56154 is indeed the correct result. 4811 * 4812 * The `BigIntForMultiplication` representation for a big integer provides memoized access to the 4813 * power-of-two values to reduce the workload in computing those values. 4814 */ 4815 4816 4817 multiplyBy(num) { 4818 const product = BigInteger.zero(); 4819 this.multiplyByAndAddTo(num, product); 4820 return product; 4821 } 4822 /** 4823 * See `multiplyBy()` for details. This function allows for the computed product to be added 4824 * directly to the provided result big integer. 4825 */ 4826 4827 4828 multiplyByAndAddTo(num, result) { 4829 for (let exponent = 0; num !== 0; num = num >>> 1, exponent++) { 4830 if (num & 1) { 4831 const value = this.getMultipliedByPowerOfTwo(exponent); 4832 result.addToSelf(value); 4833 } 4834 } 4835 } 4836 /** 4837 * Computes and memoizes the big integer value for `this.number * 2^exponent`. 4838 */ 4839 4840 4841 getMultipliedByPowerOfTwo(exponent) { 4842 // Compute the powers up until the requested exponent, where each value is computed from its 4843 // predecessor. This is simple as `this.number * 2^(exponent - 1)` only has to be doubled (i.e. 4844 // added to itself) to reach `this.number * 2^exponent`. 4845 for (let i = this.powerOfTwos.length; i <= exponent; i++) { 4846 const previousPower = this.powerOfTwos[i - 1]; 4847 this.powerOfTwos[i] = previousPower.add(previousPower); 4848 } 4849 4850 return this.powerOfTwos[exponent]; 4851 } 4852 4853} 4854/** 4855 * Represents an exponentiation operation for the provided base, of which exponents are computed and 4856 * memoized. The results are represented by a `BigIntForMultiplication` which is tailored for 4857 * multiplication operations by memoizing the power-of-twos. This effectively results in a matrix 4858 * representation that is lazily computed upon request. 4859 */ 4860 4861 4862class BigIntExponentiation { 4863 constructor(base) { 4864 this.base = base; 4865 this.exponents = [new BigIntForMultiplication(BigInteger.one())]; 4866 } 4867 /** 4868 * Compute the value for `this.base^exponent`, resulting in a big integer that is optimized for 4869 * further multiplication operations. 4870 */ 4871 4872
4873 toThePowerOf(exponent) { 4874 // Compute the results up until the requested exponent, where every value is computed from its 4875 // predecessor. This is because `this.base^(exponent - 1)` only has to be multiplied by `base` 4876 // to reach `this.base^exponent`. 4877 for (let i = this.exponents.length; i <= exponent; i++) { 4878 const value = this.exponents[i - 1].multiplyBy(this.base); 4879 this.exponents[i] = new BigIntForMultiplication(value); 4880 } 4881 4882 return this.exponents[exponent]; 4883 } 4884 4885} 4886/** 4887 * @license 4888 * Copyright Google LLC All Rights Reserved. 4889 * 4890 * Use of this source code is governed by an MIT-style license that can be 4891 * found in the LICENSE file at https://angular.io/license 4892 */ 4893 4894/** 4895 * Return the message id or compute it using the XLIFF1 digest. 4896 */ 4897 4898 4899function digest$1(message) { 4900 return message.id || computeDigest(message); 4901} 4902/** 4903 * Compute the message id using the XLIFF1 digest. 4904 */ 4905 4906 4907function computeDigest(message) { 4908 return sha1(serializeNodes(message.nodes).join('') + `[${message.meaning}]`); 4909} 4910/** 4911 * Return the message id or compute it using the XLIFF2/XMB/$localize digest. 4912 */ 4913 4914 4915function decimalDigest(message) { 4916 return message.id || computeDecimalDigest(message); 4917} 4918/** 4919 * Compute the message id using the XLIFF2/XMB/$localize digest. 4920 */ 4921 4922 4923function computeDecimalDigest(message) { 4924 const visitor = new _SerializerIgnoreIcuExpVisitor(); 4925 const parts = message.nodes.map(a => a.visit(visitor, null)); 4926 return computeMsgId(parts.join(''), message.meaning); 4927} 4928/** 4929 * Serialize the i18n ast to something xml-like in order to generate an UID. 4930 * 4931 * The visitor is also used in the i18n parser tests 4932 * 4933 * @internal 4934 */ 4935 4936 4937class _SerializerVisitor { 4938 visitText(text, context) { 4939 return text.value; 4940 } 4941 4942 visitContainer(container, context) { 4943 return `[${container.children.map(child => child.visit(this)).join(', ')}]`; 4944 } 4945 4946 visitIcu(icu, context) { 4947 const strCases = Object.keys(icu.cases).map(k => `${k} {${icu.cases[k].visit(this)}}`); 4948 return `{${icu.expression}, ${icu.type}, ${strCases.join(', ')}}`; 4949 } 4950 4951 visitTagPlaceholder(ph, context) { 4952 return ph.isVoid ? `<ph tag name="${ph.startName}"/>` : `<ph tag name="${ph.startName}">${ph.children.map(child => child.visit(this)).join(', ')}</ph name="${ph.closeName}">`; 4953 } 4954 4955 visitPlaceholder(ph, context) { 4956 return ph.value ? `<ph name="${ph.name}">${ph.value}</ph>` : `<ph name="${ph.name}"/>`; 4957 } 4958 4959 visitIcuPlaceholder(ph, context) { 4960 return `<ph icu name="${ph.name}">${ph.value.visit(this)}</ph>`; 4961 } 4962 4963} 4964 4965const serializerVisitor$1 = new _SerializerVisitor(); 4966 4967function serializeNodes(nodes) { 4968 return nodes.map(a => a.visit(serializerVisitor$1, null)); 4969} 4970/** 4971 * Serialize the i18n ast to something xml-like in order to generate an UID. 4972 * 4973 * Ignore the ICU expressions so that message IDs stays identical if only the expression changes. 4974 * 4975 * @internal 4976 */ 4977 4978 4979class _SerializerIgnoreIcuExpVisitor extends _SerializerVisitor { 4980 visitIcu(icu, context) { 4981 let strCases = Object.keys(icu.cases).map(k => `${k} {${icu.cases[k].visit(this)}}`); // Do not take the expression into account 4982 4983 return `{${icu.type}, ${strCases.join(', ')}}`; 4984 } 4985 4986} 4987/** 4988 * Compute the SHA1 of the given string 4989 * 4990 * see https://csrc.nist.gov/publications/fips/fips180-4/fips-180-4.pdf 4991 * 4992 * WARNING: this function has not been designed not tested with security in mind. 4993 * DO NOT USE IT IN A SECURITY SENSITIVE CONTEXT. 4994 */ 4995 4996 4997function sha1(str) { 4998 const utf8 = utf8Encode(str); 4999 const words32 = bytesToWords32(utf8, Endian.Big); 5000 const len = utf8.length * 8; 5001 const w = newArray(80); 5002 let a = 0x67452301, 5003 b = 0xefcdab89, 5004 c = 0x98badcfe, 5005 d = 0x10325476, 5006 e = 0xc3d2e1f0; 5007 words32[len >> 5] |= 0x80 << 24 - len % 32; 5008 words32[(len + 64 >> 9 << 4) + 15] = len; 5009 5010 for (let i = 0; i < words32.length; i += 16) { 5011 const h0 = a, 5012 h1 = b, 5013 h2 = c, 5014 h3 = d, 5015 h4 = e; 5016 5017 for (let j = 0; j < 80; j++) { 5018 if (j < 16) { 5019 w[j] = words32[i + j]; 5020 } else { 5021 w[j] = rol32(w[j - 3] ^ w[j - 8] ^ w[j - 14] ^ w[j - 16], 1); 5022 } 5023 5024 const fkVal = fk(j, b, c, d); 5025 const f = fkVal[0];
5026 const k = fkVal[1]; 5027 const temp = [rol32(a, 5), f, e, k, w[j]].reduce(add32); 5028 e = d; 5029 d = c; 5030 c = rol32(b, 30); 5031 b = a; 5032 a = temp; 5033 } 5034 5035 a = add32(a, h0); 5036 b = add32(b, h1); 5037 c = add32(c, h2); 5038 d = add32(d, h3); 5039 e = add32(e, h4); 5040 } 5041 5042 return bytesToHexString(words32ToByteString([a, b, c, d, e])); 5043} 5044 5045function fk(index, b, c, d) { 5046 if (index < 20) { 5047 return [b & c | ~b & d, 0x5a827999]; 5048 } 5049 5050 if (index < 40) { 5051 return [b ^ c ^ d, 0x6ed9eba1]; 5052 } 5053 5054 if (index < 60) { 5055 return [b & c | b & d | c & d, 0x8f1bbcdc]; 5056 } 5057 5058 return [b ^ c ^ d, 0xca62c1d6]; 5059} 5060/** 5061 * Compute the fingerprint of the given string 5062 * 5063 * The output is 64 bit number encoded as a decimal string 5064 * 5065 * based on: 5066 * https://github.com/google/closure-compiler/blob/master/src/com/google/javascript/jscomp/GoogleJsMessageIdGenerator.java 5067 */ 5068 5069 5070function fingerprint(str) { 5071 const utf8 = utf8Encode(str); 5072 let hi = hash32(utf8, 0); 5073 let lo = hash32(utf8, 102072); 5074 5075 if (hi == 0 && (lo == 0 || lo == 1)) { 5076 hi = hi ^ 0x130f9bef; 5077 lo = lo ^ -0x6b5f56d8; 5078 } 5079 5080 return [hi, lo]; 5081} 5082 5083function computeMsgId(msg, meaning = '') { 5084 let msgFingerprint = fingerprint(msg); 5085 5086 if (meaning) { 5087 const meaningFingerprint = fingerprint(meaning); 5088 msgFingerprint = add64(rol64(msgFingerprint, 1), meaningFingerprint); 5089 } 5090 5091 const hi = msgFingerprint[0]; 5092 const lo = msgFingerprint[1]; 5093 return wordsToDecimalString(hi & 0x7fffffff, lo); 5094} 5095 5096function hash32(bytes, c) { 5097 let a = 0x9e3779b9, 5098 b = 0x9e3779b9; 5099 let i; 5100 const len = bytes.length; 5101 5102 for (i = 0; i + 12 <= len; i += 12) { 5103 a = add32(a, wordAt(bytes, i, Endian.Little)); 5104 b = add32(b, wordAt(bytes, i + 4, Endian.Little)); 5105 c = add32(c, wordAt(bytes, i + 8, Endian.Little)); 5106 const res = mix(a, b, c); 5107 a = res[0], b = res[1], c = res[2]; 5108 } 5109 5110 a = add32(a, wordAt(bytes, i, Endian.Little)); 5111 b = add32(b, wordAt(bytes, i + 4, Endian.Little)); // the first byte of c is reserved for the length 5112 5113 c = add32(c, len); 5114 c = add32(c, wordAt(bytes, i + 8, Endian.Little) << 8); 5115 return mix(a, b, c)[2]; 5116} // clang-format off 5117 5118 5119function mix(a, b, c) { 5120 a = sub32(a, b); 5121 a = sub32(a, c); 5122 a ^= c >>> 13; 5123 b = sub32(b, c); 5124 b = sub32(b, a); 5125 b ^= a << 8; 5126 c = sub32(c, a); 5127 c = sub32(c, b); 5128 c ^= b >>> 13; 5129 a = sub32(a, b); 5130 a = sub32(a, c); 5131 a ^= c >>> 12; 5132 b = sub32(b, c); 5133 b = sub32(b, a); 5134 b ^= a << 16; 5135 c = sub32(c, a); 5136 c = sub32(c, b); 5137 c ^= b >>> 5; 5138 a = sub32(a, b); 5139 a = sub32(a, c); 5140 a ^= c >>> 3; 5141 b = sub32(b, c); 5142 b = sub32(b, a); 5143 b ^= a << 10; 5144 c = sub32(c, a); 5145 c = sub32(c, b); 5146 c ^= b >>> 15; 5147 return [a, b, c]; 5148} // clang-format on 5149// Utils 5150 5151 5152var Endian; 5153 5154(function (Endian) { 5155 Endian[Endian["Little"] = 0] = "Little"; 5156 Endian[Endian["Big"] = 1] = "Big"; 5157})(Endian || (Endian = {})); 5158 5159function add32(a, b) { 5160 return add32to64(a, b)[1]; 5161} 5162 5163function add32to64(a, b) { 5164 const low = (a & 0xffff) + (b & 0xffff); 5165 const high = (a >>> 16) + (b >>> 16) + (low >>> 16); 5166 return [high >>> 16, high << 16 | low & 0xffff]; 5167} 5168 5169function add64(a, b) { 5170 const ah = a[0], 5171 al = a[1]; 5172 const bh = b[0], 5173 bl = b[1]; 5174 const result = add32to64(al, bl); 5175 const carry = result[0]; 5176 const l = result[1]; 5177 const h = add32(add32(ah, bh), carry); 5178 return [h, l]; 5179} 5180 5181function sub32(a, b) { 5182 const low = (a & 0xffff) - (b & 0xffff); 5183 const high = (a >> 16) - (b >> 16) + (low >> 16); 5184 return high << 16 | low & 0xffff; 5185} // Rotate a 32b number left `count` position 5186 5187 5188function rol32(a, count) { 5189 return a << count | a >>> 32 - count; 5190} // Rotate a 64b number left `count` position 5191 5192 5193function rol64(num, count) { 5194 const hi = num[0], 5195 lo = num[1]; 5196 const h = hi << count | lo >>> 32 - count; 5197 const l = lo << count | hi >>> 32 - count; 5198 return [h, l]; 5199} 5200 5201function bytesToWords32(bytes, endian) { 5202 const size = bytes.length + 3 >>> 2; 5203 const words32 = []; 5204 5205 for (let i = 0; i < size; i++) { 5206 words32[i] = wordAt(bytes, i * 4, endian); 5207 } 5208 5209 return words32; 5210} 5211 5212function byteAt(bytes, index) { 5213 return index >= bytes.length ? 0 : bytes[index]; 5214} 5215 5216function wordAt(bytes, index, endian) { 5217 let word = 0; 5218 5219 if (endian === Endian.Big) { 5220 for (let i = 0; i < 4; i++) {
5221 word += byteAt(bytes, index + i) << 24 - 8 * i; 5222 } 5223 } else { 5224 for (let i = 0; i < 4; i++) { 5225 word += byteAt(bytes, index + i) << 8 * i; 5226 } 5227 } 5228 5229 return word; 5230} 5231 5232function words32ToByteString(words32) { 5233 return words32.reduce((bytes, word) => bytes.concat(word32ToByteString(word)), []); 5234} 5235 5236function word32ToByteString(word) { 5237 let bytes = []; 5238 5239 for (let i = 0; i < 4; i++) { 5240 bytes.push(word >>> 8 * (3 - i) & 0xff); 5241 } 5242 5243 return bytes; 5244} 5245 5246function bytesToHexString(bytes) { 5247 let hex = ''; 5248 5249 for (let i = 0; i < bytes.length; i++) { 5250 const b = byteAt(bytes, i); 5251 hex += (b >>> 4).toString(16) + (b & 0x0f).toString(16); 5252 } 5253 5254 return hex.toLowerCase(); 5255} 5256/** 5257 * Create a shared exponentiation pool for base-256 computations. This shared pool provides memoized 5258 * power-of-256 results with memoized power-of-two computations for efficient multiplication. 5259 * 5260 * For our purposes, this can be safely stored as a global without memory concerns. The reason is 5261 * that we encode two words, so only need the 0th (for the low word) and 4th (for the high word) 5262 * exponent. 5263 */ 5264 5265 5266const base256 = new BigIntExponentiation(256); 5267/** 5268 * Represents two 32-bit words as a single decimal number. This requires a big integer storage 5269 * model as JS numbers are not accurate enough to represent the 64-bit number. 5270 * 5271 * Based on https://www.danvk.org/hex2dec.html 5272 */ 5273 5274function wordsToDecimalString(hi, lo) { 5275 // Encode the four bytes in lo in the lower digits of the decimal number. 5276 // Note: the multiplication results in lo itself but represented by a big integer using its 5277 // decimal digits. 5278 const decimal = base256.toThePowerOf(0).multiplyBy(lo); // Encode the four bytes in hi above the four lo bytes. lo is a maximum of (2^8)^4, which is why 5279 // this multiplication factor is applied. 5280 5281 base256.toThePowerOf(4).multiplyByAndAddTo(hi, decimal); 5282 return decimal.toString(); 5283} 5284/** 5285 * @license 5286 * Copyright Google LLC All Rights Reserved. 5287 * 5288 * Use of this source code is governed by an MIT-style license that can be 5289 * found in the LICENSE file at https://angular.io/license 5290 */ 5291//// Types 5292 5293 5294var TypeModifier; 5295 5296(function (TypeModifier) { 5297 TypeModifier[TypeModifier["None"] = 0] = "None"; 5298 TypeModifier[TypeModifier["Const"] = 1] = "Const"; 5299})(TypeModifier || (TypeModifier = {})); 5300 5301class Type { 5302 constructor(modifiers = TypeModifier.None) { 5303 this.modifiers = modifiers; 5304 } 5305 5306 hasModifier(modifier) { 5307 return (this.modifiers & modifier) !== 0; 5308 } 5309 5310} 5311 5312var BuiltinTypeName; 5313 5314(function (BuiltinTypeName) { 5315 BuiltinTypeName[BuiltinTypeName["Dynamic"] = 0] = "Dynamic"; 5316 BuiltinTypeName[BuiltinTypeName["Bool"] = 1] = "Bool"; 5317 BuiltinTypeName[BuiltinTypeName["String"] = 2] = "String"; 5318 BuiltinTypeName[BuiltinTypeName["Int"] = 3] = "Int"; 5319 BuiltinTypeName[BuiltinTypeName["Number"] = 4] = "Number"; 5320 BuiltinTypeName[BuiltinTypeName["Function"] = 5] = "Function"; 5321 BuiltinTypeName[BuiltinTypeName["Inferred"] = 6] = "Inferred"; 5322 BuiltinTypeName[BuiltinTypeName["None"] = 7] = "None"; 5323})(BuiltinTypeName || (BuiltinTypeName = {})); 5324 5325class BuiltinType extends Type { 5326 constructor(name, modifiers) { 5327 super(modifiers); 5328 this.name = name; 5329 } 5330 5331 visitType(visitor, context) { 5332 return visitor.visitBuiltinType(this, context); 5333 } 5334 5335} 5336 5337class ExpressionType extends Type { 5338 constructor(value, modifiers, typeParams = null) { 5339 super(modifiers); 5340 this.value = value; 5341 this.typeParams = typeParams; 5342 } 5343 5344 visitType(visitor, context) { 5345 return visitor.visitExpressionType(this, context); 5346 } 5347 5348} 5349 5350class ArrayType extends Type { 5351 constructor(of, modifiers) { 5352 super(modifiers); 5353 this.of = of; 5354 } 5355 5356 visitType(visitor, context) { 5357 return visitor.visitArrayType(this, context); 5358 } 5359 5360} 5361 5362class MapType extends Type { 5363 constructor(valueType, modifiers) { 5364 super(modifiers); 5365 this.valueType = valueType || null; 5366 } 5367 5368 visitType(visitor, context) { 5369 return visitor.visitMapType(this, context); 5370 } 5371 5372} 5373 5374const DYNAMIC_TYPE = new BuiltinType(BuiltinTypeName.Dynamic); 5375const INFERRED_TYPE = new BuiltinType(BuiltinTypeName.Inferred); 5376const BOOL_TYPE = new BuiltinType(BuiltinTypeName.Bool); 5377const INT_TYPE = new BuiltinType(BuiltinTypeName.Int); 5378const NUMBER_TYPE = new BuiltinType(BuiltinTypeName.Number); 5379const STRING_TYPE = new BuiltinType(BuiltinTypeName.String); 5380const FUNCTION_TYPE = new BuiltinType(BuiltinTypeName.Function); 5381const NONE_TYPE = new BuiltinType(BuiltinTypeName.None); ///// Expressions 5382 5383var UnaryOperator; 5384 5385(function (UnaryOperator) { 5386 UnaryOperator[UnaryOperator["Minus"] = 0] = "Minus"; 5387 UnaryOperator[UnaryOperator["Plus"] = 1] = "Plus"; 5388})(UnaryOperator || (UnaryOperator = {})); 5389 5390var BinaryOperator; 5391 5392(function (BinaryOperator) { 5393 BinaryOperator[BinaryOperator["Equals"] = 0] = "Equals"; 5394 BinaryOperator[BinaryOperator["NotEquals"] = 1] = "NotEquals"; 5395 BinaryOperator[BinaryOperator["Identical"] = 2] = "Identical"; 5396 BinaryOperator[BinaryOperator["NotIdentical"] = 3] = "NotIdentical"; 5397 BinaryOperator[BinaryOperator["Minus"] = 4] = "Minus"; 5398 BinaryOperator[BinaryOperator["Plus"] = 5] = "Plus"; 5399 BinaryOperator[BinaryOperator["Divide"] = 6] = "Divide"; 5400 BinaryOperator[BinaryOperator["Multiply"] = 7] = "Multiply"; 5401 BinaryOperator[BinaryOperator["Modulo"] = 8] = "Modulo"; 5402 BinaryOperator[BinaryOperator["And"] = 9] = "And"; 5403 BinaryOperator[BinaryOperator["Or"] = 10] = "Or"; 5404 BinaryOperator[BinaryOperator["BitwiseAnd"] = 11] = "BitwiseAnd"; 5405 BinaryOperator[BinaryOperator["Lower"] = 12] = "Lower"; 5406 BinaryOperator[BinaryOperator["LowerEquals"] = 13] = "LowerEquals"; 5407 BinaryOperator[BinaryOperator["Bigger"] = 14] = "Bigger"; 5408 BinaryOperator[BinaryOperator["BiggerEquals"] = 15] = "BiggerEquals"; 5409 BinaryOperator[BinaryOperator["NullishCoalesce"] = 16] = "NullishCoalesce"; 5410})(BinaryOperator || (BinaryOperator = {})); 5411 5412function nullSafeIsEquivalent(base, other) { 5413 if (base == null || other == null) { 5414 return base == other; 5415 } 5416 5417 return base.isEquivalent(other); 5418} 5419 5420function areAllEquivalentPredicate(base, other, equivalentPredicate) { 5421 const len = base.length; 5422 5423 if (len !== other.length) { 5424 return false;
5425 } 5426 5427 for (let i = 0; i < len; i++) { 5428 if (!equivalentPredicate(base[i], other[i])) { 5429 return false; 5430 } 5431 } 5432 5433 return true; 5434} 5435 5436function areAllEquivalent(base, other) { 5437 return areAllEquivalentPredicate(base, other, (baseElement, otherElement) => baseElement.isEquivalent(otherElement)); 5438} 5439 5440class Expression { 5441 constructor(type, sourceSpan) { 5442 this.type = type || null; 5443 this.sourceSpan = sourceSpan || null; 5444 } 5445 5446 prop(name, sourceSpan) { 5447 return new ReadPropExpr(this, name, null, sourceSpan); 5448 } 5449 5450 key(index, type, sourceSpan) { 5451 return new ReadKeyExpr(this, index, type, sourceSpan); 5452 } 5453 5454 callFn(params, sourceSpan, pure) { 5455 return new InvokeFunctionExpr(this, params, null, sourceSpan, pure); 5456 } 5457 5458 instantiate(params, type, sourceSpan) { 5459 return new InstantiateExpr(this, params, type, sourceSpan); 5460 } 5461 5462 conditional(trueCase, falseCase = null, sourceSpan) { 5463 return new ConditionalExpr(this, trueCase, falseCase, null, sourceSpan); 5464 } 5465 5466 equals(rhs, sourceSpan) { 5467 return new BinaryOperatorExpr(BinaryOperator.Equals, this, rhs, null, sourceSpan); 5468 } 5469 5470 notEquals(rhs, sourceSpan) { 5471 return new BinaryOperatorExpr(BinaryOperator.NotEquals, this, rhs, null, sourceSpan); 5472 } 5473 5474 identical(rhs, sourceSpan) { 5475 return new BinaryOperatorExpr(BinaryOperator.Identical, this, rhs, null, sourceSpan); 5476 } 5477 5478 notIdentical(rhs, sourceSpan) { 5479 return new BinaryOperatorExpr(BinaryOperator.NotIdentical, this, rhs, null, sourceSpan); 5480 } 5481 5482 minus(rhs, sourceSpan) { 5483 return new BinaryOperatorExpr(BinaryOperator.Minus, this, rhs, null, sourceSpan); 5484 } 5485 5486 plus(rhs, sourceSpan) { 5487 return new BinaryOperatorExpr(BinaryOperator.Plus, this, rhs, null, sourceSpan); 5488 } 5489 5490 divide(rhs, sourceSpan) { 5491 return new BinaryOperatorExpr(BinaryOperator.Divide, this, rhs, null, sourceSpan); 5492 } 5493 5494 multiply(rhs, sourceSpan) { 5495 return new BinaryOperatorExpr(BinaryOperator.Multiply, this, rhs, null, sourceSpan); 5496 } 5497 5498 modulo(rhs, sourceSpan) { 5499 return new BinaryOperatorExpr(BinaryOperator.Modulo, this, rhs, null, sourceSpan); 5500 } 5501 5502 and(rhs, sourceSpan) { 5503 return new BinaryOperatorExpr(BinaryOperator.And, this, rhs, null, sourceSpan); 5504 } 5505 5506 bitwiseAnd(rhs, sourceSpan, parens = true) { 5507 return new BinaryOperatorExpr(BinaryOperator.BitwiseAnd, this, rhs, null, sourceSpan, parens); 5508 } 5509 5510 or(rhs, sourceSpan) { 5511 return new BinaryOperatorExpr(BinaryOperator.Or, this, rhs, null, sourceSpan); 5512 } 5513 5514 lower(rhs, sourceSpan) { 5515 return new BinaryOperatorExpr(BinaryOperator.Lower, this, rhs, null, sourceSpan); 5516 } 5517 5518 lowerEquals(rhs, sourceSpan) { 5519 return new BinaryOperatorExpr(BinaryOperator.LowerEquals, this, rhs, null, sourceSpan); 5520 } 5521 5522 bigger(rhs, sourceSpan) { 5523 return new BinaryOperatorExpr(BinaryOperator.Bigger, this, rhs, null, sourceSpan); 5524 } 5525 5526 biggerEquals(rhs, sourceSpan) { 5527 return new BinaryOperatorExpr(BinaryOperator.BiggerEquals, this, rhs, null, sourceSpan); 5528 } 5529 5530 isBlank(sourceSpan) { 5531 // Note: We use equals by purpose here to compare to null and undefined in JS. 5532 // We use the typed null to allow strictNullChecks to narrow types. 5533 return this.equals(TYPED_NULL_EXPR, sourceSpan); 5534 } 5535 5536 nullishCoalesce(rhs, sourceSpan) { 5537 return new BinaryOperatorExpr(BinaryOperator.NullishCoalesce, this, rhs, null, sourceSpan); 5538 } 5539 5540 toStmt() { 5541 return new ExpressionStatement(this, null); 5542 } 5543 5544} 5545 5546class ReadVarExpr extends Expression { 5547 constructor(name, type, sourceSpan) { 5548 super(type, sourceSpan); 5549 this.name = name; 5550 } 5551 5552 isEquivalent(e) { 5553 return e instanceof ReadVarExpr && this.name === e.name; 5554 } 5555 5556 isConstant() { 5557 return false; 5558 } 5559 5560 visitExpression(visitor, context) { 5561 return visitor.visitReadVarExpr(this, context); 5562 } 5563 5564 set(value) { 5565 return new WriteVarExpr(this.name, value, null, this.sourceSpan); 5566 } 5567 5568} 5569 5570class TypeofExpr extends Expression { 5571 constructor(expr, type, sourceSpan) { 5572 super(type, sourceSpan); 5573 this.expr = expr; 5574 } 5575 5576 visitExpression(visitor, context) { 5577 return visitor.visitTypeofExpr(this, context); 5578 } 5579 5580 isEquivalent(e) { 5581 return e instanceof TypeofExpr && e.expr.isEquivalent(this.expr); 5582 } 5583 5584 isConstant() { 5585 return this.expr.isConstant(); 5586 } 5587 5588} 5589
5590class WrappedNodeExpr extends Expression { 5591 constructor(node, type, sourceSpan) { 5592 super(type, sourceSpan); 5593 this.node = node; 5594 } 5595 5596 isEquivalent(e) { 5597 return e instanceof WrappedNodeExpr && this.node === e.node; 5598 } 5599 5600 isConstant() { 5601 return false; 5602 } 5603 5604 visitExpression(visitor, context) { 5605 return visitor.visitWrappedNodeExpr(this, context); 5606 } 5607 5608} 5609 5610class WriteVarExpr extends Expression { 5611 constructor(name, value, type, sourceSpan) { 5612 super(type || value.type, sourceSpan); 5613 this.name = name; 5614 this.value = value; 5615 } 5616 5617 isEquivalent(e) { 5618 return e instanceof WriteVarExpr && this.name === e.name && this.value.isEquivalent(e.value); 5619 } 5620 5621 isConstant() { 5622 return false; 5623 } 5624 5625 visitExpression(visitor, context) { 5626 return visitor.visitWriteVarExpr(this, context); 5627 } 5628 5629 toDeclStmt(type, modifiers) { 5630 return new DeclareVarStmt(this.name, this.value, type, modifiers, this.sourceSpan); 5631 } 5632 5633 toConstDecl() { 5634 return this.toDeclStmt(INFERRED_TYPE, StmtModifier.Final); 5635 } 5636 5637} 5638 5639class WriteKeyExpr extends Expression { 5640 constructor(receiver, index, value, type, sourceSpan) { 5641 super(type || value.type, sourceSpan); 5642 this.receiver = receiver; 5643 this.index = index; 5644 this.value = value; 5645 } 5646 5647 isEquivalent(e) { 5648 return e instanceof WriteKeyExpr && this.receiver.isEquivalent(e.receiver) && this.index.isEquivalent(e.index) && this.value.isEquivalent(e.value); 5649 } 5650 5651 isConstant() { 5652 return false; 5653 } 5654 5655 visitExpression(visitor, context) { 5656 return visitor.visitWriteKeyExpr(this, context); 5657 } 5658 5659} 5660 5661class WritePropExpr extends Expression { 5662 constructor(receiver, name, value, type, sourceSpan) { 5663 super(type || value.type, sourceSpan); 5664 this.receiver = receiver; 5665 this.name = name; 5666 this.value = value; 5667 } 5668 5669 isEquivalent(e) { 5670 return e instanceof WritePropExpr && this.receiver.isEquivalent(e.receiver) && this.name === e.name && this.value.isEquivalent(e.value); 5671 } 5672 5673 isConstant() { 5674 return false; 5675 } 5676 5677 visitExpression(visitor, context) { 5678 return visitor.visitWritePropExpr(this, context); 5679 } 5680 5681} 5682 5683class InvokeFunctionExpr extends Expression { 5684 constructor(fn, args, type, sourceSpan, pure = false) { 5685 super(type, sourceSpan); 5686 this.fn = fn; 5687 this.args = args; 5688 this.pure = pure; 5689 } 5690 5691 isEquivalent(e) { 5692 return e instanceof InvokeFunctionExpr && this.fn.isEquivalent(e.fn) && areAllEquivalent(this.args, e.args) && this.pure === e.pure; 5693 } 5694 5695 isConstant() { 5696 return false; 5697 } 5698 5699 visitExpression(visitor, context) { 5700 return visitor.visitInvokeFunctionExpr(this, context); 5701 } 5702 5703} 5704 5705class TaggedTemplateExpr extends Expression { 5706 constructor(tag, template, type, sourceSpan) { 5707 super(type, sourceSpan); 5708 this.tag = tag; 5709 this.template = template; 5710 } 5711 5712 isEquivalent(e) { 5713 return e instanceof TaggedTemplateExpr && this.tag.isEquivalent(e.tag) && areAllEquivalentPredicate(this.template.elements, e.template.elements, (a, b) => a.text === b.text) && areAllEquivalent(this.template.expressions, e.template.expressions); 5714 } 5715 5716 isConstant() { 5717 return false; 5718 } 5719 5720 visitExpression(visitor, context) { 5721 return visitor.visitTaggedTemplateExpr(this, context); 5722 } 5723 5724} 5725 5726class InstantiateExpr extends Expression { 5727 constructor(classExpr, args, type, sourceSpan) { 5728 super(type, sourceSpan); 5729 this.classExpr = classExpr; 5730 this.args = args; 5731 } 5732 5733 isEquivalent(e) { 5734 return e instanceof InstantiateExpr && this.classExpr.isEquivalent(e.classExpr) && areAllEquivalent(this.args, e.args); 5735 } 5736 5737 isConstant() { 5738 return false; 5739 } 5740 5741 visitExpression(visitor, context) { 5742 return visitor.visitInstantiateExpr(this, context); 5743 } 5744 5745} 5746 5747class LiteralExpr extends Expression { 5748 constructor(value, type, sourceSpan) { 5749 super(type, sourceSpan); 5750 this.value = value; 5751 } 5752 5753 isEquivalent(e) { 5754 return e instanceof LiteralExpr && this.value === e.value; 5755 } 5756 5757 isConstant() { 5758 return true; 5759 } 5760 5761 visitExpression(visitor, context) { 5762 return visitor.visitLiteralExpr(this, context); 5763 } 5764 5765} 5766 5767class TemplateLiteral { 5768 constructor(elements, expressions) { 5769 this.elements = elements; 5770 this.expressions = expressions; 5771 } 5772 5773} 5774 5775class TemplateLiteralElement { 5776 constructor(text, sourceSpan, rawText) { 5777 this.text = text; 5778 this.sourceSpan = sourceSpan; // If `rawText` is not provided, try to extract the raw string from its 5779 // associated `sourceSpan`. If that is also not available, "fake" the raw 5780 // string instead by escaping the following control sequences: 5781 // - "\" would otherwise indicate that the next character is a control character. 5782 // - "`" and "${" are template string control sequences that would otherwise prematurely 5783 // indicate the end of the template literal element. 5784 5785 this.rawText = rawText ?? sourceSpan?.toString() ?? escapeForTemplateLiteral(escapeSlashes(text)); 5786 } 5787 5788} 5789 5790class LiteralPiece { 5791 constructor(text, sourceSpan) { 5792 this.text = text; 5793 this.sourceSpan = sourceSpan; 5794 } 5795 5796} 5797 5798class PlaceholderPiece { 5799 /** 5800 * Create a new instance of a `PlaceholderPiece`. 5801 * 5802 * @param text the name of this placeholder (e.g. `PH_1`).
5803 * @param sourceSpan the location of this placeholder in its localized message the source code. 5804 * @param associatedMessage reference to another message that this placeholder is associated with. 5805 * The `associatedMessage` is mainly used to provide a relationship to an ICU message that has 5806 * been extracted out from the message containing the placeholder. 5807 */ 5808 constructor(text, sourceSpan, associatedMessage) { 5809 this.text = text; 5810 this.sourceSpan = sourceSpan; 5811 this.associatedMessage = associatedMessage; 5812 } 5813 5814} 5815 5816const MEANING_SEPARATOR$1 = '|'; 5817const ID_SEPARATOR$1 = '@@'; 5818const LEGACY_ID_INDICATOR = 'â'; 5819 5820class LocalizedString extends Expression { 5821 constructor(metaBlock, messageParts, placeHolderNames, expressions, sourceSpan) { 5822 super(STRING_TYPE, sourceSpan); 5823 this.metaBlock = metaBlock; 5824 this.messageParts = messageParts; 5825 this.placeHolderNames = placeHolderNames; 5826 this.expressions = expressions; 5827 } 5828 5829 isEquivalent(e) { 5830 // return e instanceof LocalizedString && this.message === e.message; 5831 return false; 5832 } 5833 5834 isConstant() { 5835 return false; 5836 } 5837 5838 visitExpression(visitor, context) { 5839 return visitor.visitLocalizedString(this, context); 5840 } 5841 /** 5842 * Serialize the given `meta` and `messagePart` into "cooked" and "raw" strings that can be used 5843 * in a `$localize` tagged string. The format of the metadata is the same as that parsed by 5844 * `parseI18nMeta()`. 5845 * 5846 * @param meta The metadata to serialize 5847 * @param messagePart The first part of the tagged string 5848 */ 5849 5850 5851 serializeI18nHead() { 5852 let metaBlock = this.metaBlock.description || ''; 5853 5854 if (this.metaBlock.meaning) { 5855 metaBlock = `${this.metaBlock.meaning}${MEANING_SEPARATOR$1}${metaBlock}`; 5856 } 5857 5858 if (this.metaBlock.customId) { 5859 metaBlock = `${metaBlock}${ID_SEPARATOR$1}${this.metaBlock.customId}`; 5860 } 5861 5862 if (this.metaBlock.legacyIds) { 5863 this.metaBlock.legacyIds.forEach(legacyId => { 5864 metaBlock = `${metaBlock}${LEGACY_ID_INDICATOR}${legacyId}`; 5865 }); 5866 } 5867 5868 return createCookedRawString(metaBlock, this.messageParts[0].text, this.getMessagePartSourceSpan(0)); 5869 } 5870 5871 getMessagePartSourceSpan(i) { 5872 return this.messageParts[i]?.sourceSpan ?? this.sourceSpan; 5873 } 5874 5875 getPlaceholderSourceSpan(i) { 5876 return this.placeHolderNames[i]?.sourceSpan ?? this.expressions[i]?.sourceSpan ?? this.sourceSpan; 5877 } 5878 /** 5879 * Serialize the given `placeholderName` and `messagePart` into "cooked" and "raw" strings that 5880 * can be used in a `$localize` tagged string. 5881 * 5882 * The format is `:<placeholder-name>[@@<associated-id>]:`. 5883 * 5884 * The `associated-id` is the message id of the (usually an ICU) message to which this placeholder 5885 * refers. 5886 * 5887 * @param partIndex The index of the message part to serialize. 5888 */ 5889 5890 5891 serializeI18nTemplatePart(partIndex) { 5892 const placeholder = this.placeHolderNames[partIndex - 1]; 5893 const messagePart = this.messageParts[partIndex]; 5894 let metaBlock = placeholder.text; 5895 5896 if (placeholder.associatedMessage?.legacyIds.length === 0) { 5897 metaBlock += `${ID_SEPARATOR$1}${computeMsgId(placeholder.associatedMessage.messageString, placeholder.associatedMessage.meaning)}`; 5898 } 5899 5900 return createCookedRawString(metaBlock, messagePart.text, this.getMessagePartSourceSpan(partIndex)); 5901 } 5902 5903} 5904 5905const escapeSlashes = str => str.replace(/\\/g, '\\\\'); 5906 5907const escapeStartingColon = str => str.replace(/^:/, '\\:'); 5908 5909const escapeColons = str => str.replace(/:/g, '\\:'); 5910 5911const escapeForTemplateLiteral = str => str.replace(/`/g, '\\`').replace(/\${/g, '$\\{'); 5912/** 5913 * Creates a `{cooked, raw}` object from the `metaBlock` and `messagePart`. 5914 * 5915 * The `raw` text must have various character sequences escaped: 5916 * * "\" would otherwise indicate that the next character is a control character. 5917 * * "`" and "${" are template string control sequences that would otherwise prematurely indicate 5918 * the end of a message part. 5919 * * ":" inside a metablock would prematurely indicate the end of the metablock. 5920 * * ":" at the start of a messagePart with no metablock would erroneously indicate the start of a 5921 * metablock. 5922 * 5923 * @param metaBlock Any metadata that should be prepended to the string 5924 * @param messagePart The message part of the string 5925 */ 5926 5927 5928function createCookedRawString(metaBlock, messagePart, range) { 5929 if (metaBlock === '') { 5930 return { 5931 cooked: messagePart, 5932 raw: escapeForTemplateLiteral(escapeStartingColon(escapeSlashes(messagePart))), 5933 range 5934 }; 5935 } else { 5936 return { 5937 cooked: `:${metaBlock}:${messagePart}`, 5938 raw: escapeForTemplateLiteral(`:${escapeColons(escapeSlashes(metaBlock))}:${escapeSlashes(messagePart)}`), 5939 range 5940 }; 5941 } 5942} 5943
5944class ExternalExpr extends Expression { 5945 constructor(value, type, typeParams = null, sourceSpan) { 5946 super(type, sourceSpan); 5947 this.value = value; 5948 this.typeParams = typeParams; 5949 } 5950 5951 isEquivalent(e) { 5952 return e instanceof ExternalExpr && this.value.name === e.value.name && this.value.moduleName === e.value.moduleName && this.value.runtime === e.value.runtime; 5953 } 5954 5955 isConstant() { 5956 return false; 5957 } 5958 5959 visitExpression(visitor, context) { 5960 return visitor.visitExternalExpr(this, context); 5961 } 5962 5963} 5964 5965class ExternalReference { 5966 constructor(moduleName, name, runtime) { 5967 this.moduleName = moduleName; 5968 this.name = name; 5969 this.runtime = runtime; 5970 } 5971 5972} 5973 5974class ConditionalExpr extends Expression { 5975 constructor(condition, trueCase, falseCase = null, type, sourceSpan) { 5976 super(type || trueCase.type, sourceSpan); 5977 this.condition = condition; 5978 this.falseCase = falseCase; 5979 this.trueCase = trueCase; 5980 } 5981 5982 isEquivalent(e) { 5983 return e instanceof ConditionalExpr && this.condition.isEquivalent(e.condition) && this.trueCase.isEquivalent(e.trueCase) && nullSafeIsEquivalent(this.falseCase, e.falseCase); 5984 } 5985 5986 isConstant() { 5987 return false; 5988 } 5989 5990 visitExpression(visitor, context) { 5991 return visitor.visitConditionalExpr(this, context); 5992 } 5993 5994} 5995 5996class NotExpr extends Expression { 5997 constructor(condition, sourceSpan) { 5998 super(BOOL_TYPE, sourceSpan); 5999 this.condition = condition; 6000 } 6001 6002 isEquivalent(e) { 6003 return e instanceof NotExpr && this.condition.isEquivalent(e.condition); 6004 } 6005 6006 isConstant() { 6007 return false; 6008 } 6009 6010 visitExpression(visitor, context) { 6011 return visitor.visitNotExpr(this, context); 6012 } 6013 6014} 6015 6016class FnParam { 6017 constructor(name, type = null) { 6018 this.name = name; 6019 this.type = type; 6020 } 6021 6022 isEquivalent(param) { 6023 return this.name === param.name; 6024 } 6025 6026} 6027 6028class FunctionExpr extends Expression { 6029 constructor(params, statements, type, sourceSpan, name) { 6030 super(type, sourceSpan); 6031 this.params = params; 6032 this.statements = statements; 6033 this.name = name; 6034 } 6035 6036 isEquivalent(e) { 6037 return e instanceof FunctionExpr && areAllEquivalent(this.params, e.params) && areAllEquivalent(this.statements, e.statements); 6038 } 6039 6040 isConstant() { 6041 return false; 6042 } 6043 6044 visitExpression(visitor, context) { 6045 return visitor.visitFunctionExpr(this, context); 6046 } 6047 6048 toDeclStmt(name, modifiers) { 6049 return new DeclareFunctionStmt(name, this.params, this.statements, this.type, modifiers, this.sourceSpan); 6050 } 6051 6052} 6053 6054class UnaryOperatorExpr extends Expression { 6055 constructor(operator, expr, type, sourceSpan, parens = true) { 6056 super(type || NUMBER_TYPE, sourceSpan); 6057 this.operator = operator; 6058 this.expr = expr; 6059 this.parens = parens; 6060 } 6061 6062 isEquivalent(e) { 6063 return e instanceof UnaryOperatorExpr && this.operator === e.operator && this.expr.isEquivalent(e.expr); 6064 } 6065 6066 isConstant() { 6067 return false; 6068 } 6069 6070 visitExpression(visitor, context) { 6071 return visitor.visitUnaryOperatorExpr(this, context); 6072 } 6073 6074} 6075 6076class BinaryOperatorExpr extends Expression { 6077 constructor(operator, lhs, rhs, type, sourceSpan, parens = true) { 6078 super(type || lhs.type, sourceSpan); 6079 this.operator = operator; 6080 this.rhs = rhs; 6081 this.parens = parens; 6082 this.lhs = lhs; 6083 } 6084 6085 isEquivalent(e) { 6086 return e instanceof BinaryOperatorExpr && this.operator === e.operator && this.lhs.isEquivalent(e.lhs) && this.rhs.isEquivalent(e.rhs); 6087 } 6088 6089 isConstant() { 6090 return false; 6091 } 6092 6093 visitExpression(visitor, context) { 6094 return visitor.visitBinaryOperatorExpr(this, context); 6095 } 6096 6097} 6098 6099class ReadPropExpr extends Expression { 6100 constructor(receiver, name, type, sourceSpan) { 6101 super(type, sourceSpan); 6102 this.receiver = receiver; 6103 this.name = name; 6104 } 6105 6106 isEquivalent(e) { 6107 return e instanceof ReadPropExpr && this.receiver.isEquivalent(e.receiver) && this.name === e.name; 6108 } 6109 6110 isConstant() { 6111 return false; 6112 } 6113 6114 visitExpression(visitor, context) { 6115 return visitor.visitReadPropExpr(this, context); 6116 } 6117 6118 set(value) { 6119 return new WritePropExpr(this.receiver, this.name, value, null, this.sourceSpan); 6120 } 6121 6122} 6123
6124class ReadKeyExpr extends Expression { 6125 constructor(receiver, index, type, sourceSpan) { 6126 super(type, sourceSpan); 6127 this.receiver = receiver; 6128 this.index = index; 6129 } 6130 6131 isEquivalent(e) { 6132 return e instanceof ReadKeyExpr && this.receiver.isEquivalent(e.receiver) && this.index.isEquivalent(e.index); 6133 } 6134 6135 isConstant() { 6136 return false; 6137 } 6138 6139 visitExpression(visitor, context) { 6140 return visitor.visitReadKeyExpr(this, context); 6141 } 6142 6143 set(value) { 6144 return new WriteKeyExpr(this.receiver, this.index, value, null, this.sourceSpan); 6145 } 6146 6147} 6148 6149class LiteralArrayExpr extends Expression { 6150 constructor(entries, type, sourceSpan) { 6151 super(type, sourceSpan); 6152 this.entries = entries; 6153 } 6154 6155 isConstant() { 6156 return this.entries.every(e => e.isConstant()); 6157 } 6158 6159 isEquivalent(e) { 6160 return e instanceof LiteralArrayExpr && areAllEquivalent(this.entries, e.entries); 6161 } 6162 6163 visitExpression(visitor, context) { 6164 return visitor.visitLiteralArrayExpr(this, context); 6165 } 6166 6167} 6168 6169class LiteralMapEntry { 6170 constructor(key, value, quoted) { 6171 this.key = key; 6172 this.value = value; 6173 this.quoted = quoted; 6174 } 6175 6176 isEquivalent(e) { 6177 return this.key === e.key && this.value.isEquivalent(e.value); 6178 } 6179 6180} 6181 6182class LiteralMapExpr extends Expression { 6183 constructor(entries, type, sourceSpan) { 6184 super(type, sourceSpan); 6185 this.entries = entries; 6186 this.valueType = null; 6187 6188 if (type) { 6189 this.valueType = type.valueType; 6190 } 6191 } 6192 6193 isEquivalent(e) { 6194 return e instanceof LiteralMapExpr && areAllEquivalent(this.entries, e.entries); 6195 } 6196 6197 isConstant() { 6198 return this.entries.every(e => e.value.isConstant()); 6199 } 6200 6201 visitExpression(visitor, context) { 6202 return visitor.visitLiteralMapExpr(this, context); 6203 } 6204 6205} 6206 6207class CommaExpr extends Expression { 6208 constructor(parts, sourceSpan) { 6209 super(parts[parts.length - 1].type, sourceSpan); 6210 this.parts = parts; 6211 } 6212 6213 isEquivalent(e) { 6214 return e instanceof CommaExpr && areAllEquivalent(this.parts, e.parts); 6215 } 6216 6217 isConstant() { 6218 return false; 6219 } 6220 6221 visitExpression(visitor, context) { 6222 return visitor.visitCommaExpr(this, context); 6223 } 6224 6225} 6226 6227const NULL_EXPR = new LiteralExpr(null, null, null); 6228const TYPED_NULL_EXPR = new LiteralExpr(null, INFERRED_TYPE, null); //// Statements 6229 6230var StmtModifier; 6231 6232(function (StmtModifier) { 6233 StmtModifier[StmtModifier["None"] = 0] = "None"; 6234 StmtModifier[StmtModifier["Final"] = 1] = "Final"; 6235 StmtModifier[StmtModifier["Private"] = 2] = "Private"; 6236 StmtModifier[StmtModifier["Exported"] = 4] = "Exported"; 6237 StmtModifier[StmtModifier["Static"] = 8] = "Static"; 6238})(StmtModifier || (StmtModifier = {})); 6239 6240class LeadingComment { 6241 constructor(text, multiline, trailingNewline) { 6242 this.text = text; 6243 this.multiline = multiline; 6244 this.trailingNewline = trailingNewline; 6245 } 6246 6247 toString() { 6248 return this.multiline ? ` ${this.text} ` : this.text; 6249 } 6250 6251} 6252 6253class JSDocComment extends LeadingComment { 6254 constructor(tags) { 6255 super('', 6256 /* multiline */ 6257 true, 6258 /* trailingNewline */ 6259 true); 6260 this.tags = tags; 6261 } 6262 6263 toString() { 6264 return serializeTags(this.tags); 6265 } 6266 6267} 6268 6269class Statement { 6270 constructor(modifiers = StmtModifier.None, sourceSpan = null, leadingComments) { 6271 this.modifiers = modifiers; 6272 this.sourceSpan = sourceSpan; 6273 this.leadingComments = leadingComments; 6274 } 6275 6276 hasModifier(modifier) { 6277 return (this.modifiers & modifier) !== 0; 6278 } 6279 6280 addLeadingComment(leadingComment) { 6281 this.leadingComments = this.leadingComments ?? []; 6282 this.leadingComments.push(leadingComment); 6283 } 6284 6285} 6286 6287class DeclareVarStmt extends Statement { 6288 constructor(name, value, type, modifiers, sourceSpan, leadingComments) { 6289 super(modifiers, sourceSpan, leadingComments); 6290 this.name = name; 6291 this.value = value; 6292 this.type = type || value && value.type || null; 6293 } 6294 6295 isEquivalent(stmt) { 6296 return stmt instanceof DeclareVarStmt && this.name === stmt.name && (this.value ? !!stmt.value && this.value.isEquivalent(stmt.value) : !stmt.value); 6297 } 6298 6299 visitStatement(visitor, context) { 6300 return visitor.visitDeclareVarStmt(this, context); 6301 } 6302 6303} 6304 6305class DeclareFunctionStmt extends Statement { 6306 constructor(name, params, statements, type, modifiers, sourceSpan, leadingComments) { 6307 super(modifiers, sourceSpan, leadingComments); 6308 this.name = name; 6309 this.params = params; 6310 this.statements = statements; 6311 this.type = type || null; 6312 } 6313 6314 isEquivalent(stmt) { 6315 return stmt instanceof DeclareFunctionStmt && areAllEquivalent(this.params, stmt.params) && areAllEquivalent(this.statements, stmt.statements); 6316 } 6317
6318 visitStatement(visitor, context) { 6319 return visitor.visitDeclareFunctionStmt(this, context); 6320 } 6321 6322} 6323 6324class ExpressionStatement extends Statement { 6325 constructor(expr, sourceSpan, leadingComments) { 6326 super(StmtModifier.None, sourceSpan, leadingComments); 6327 this.expr = expr; 6328 } 6329 6330 isEquivalent(stmt) { 6331 return stmt instanceof ExpressionStatement && this.expr.isEquivalent(stmt.expr); 6332 } 6333 6334 visitStatement(visitor, context) { 6335 return visitor.visitExpressionStmt(this, context); 6336 } 6337 6338} 6339 6340class ReturnStatement extends Statement { 6341 constructor(value, sourceSpan = null, leadingComments) { 6342 super(StmtModifier.None, sourceSpan, leadingComments); 6343 this.value = value; 6344 } 6345 6346 isEquivalent(stmt) { 6347 return stmt instanceof ReturnStatement && this.value.isEquivalent(stmt.value); 6348 } 6349 6350 visitStatement(visitor, context) { 6351 return visitor.visitReturnStmt(this, context); 6352 } 6353 6354} 6355 6356class IfStmt extends Statement { 6357 constructor(condition, trueCase, falseCase = [], sourceSpan, leadingComments) { 6358 super(StmtModifier.None, sourceSpan, leadingComments); 6359 this.condition = condition; 6360 this.trueCase = trueCase; 6361 this.falseCase = falseCase; 6362 } 6363 6364 isEquivalent(stmt) { 6365 return stmt instanceof IfStmt && this.condition.isEquivalent(stmt.condition) && areAllEquivalent(this.trueCase, stmt.trueCase) && areAllEquivalent(this.falseCase, stmt.falseCase); 6366 } 6367 6368 visitStatement(visitor, context) { 6369 return visitor.visitIfStmt(this, context); 6370 } 6371 6372} 6373 6374class RecursiveAstVisitor$1 { 6375 visitType(ast, context) { 6376 return ast; 6377 } 6378 6379 visitExpression(ast, context) { 6380 if (ast.type) { 6381 ast.type.visitType(this, context); 6382 } 6383 6384 return ast; 6385 } 6386 6387 visitBuiltinType(type, context) { 6388 return this.visitType(type, context); 6389 } 6390 6391 visitExpressionType(type, context) { 6392 type.value.visitExpression(this, context); 6393 6394 if (type.typeParams !== null) { 6395 type.typeParams.forEach(param => this.visitType(param, context)); 6396 } 6397 6398 return this.visitType(type, context); 6399 } 6400 6401 visitArrayType(type, context) { 6402 return this.visitType(type, context); 6403 } 6404 6405 visitMapType(type, context) { 6406 return this.visitType(type, context); 6407 } 6408 6409 visitWrappedNodeExpr(ast, context) { 6410 return ast; 6411 } 6412 6413 visitTypeofExpr(ast, context) { 6414 return this.visitExpression(ast, context); 6415 } 6416 6417 visitReadVarExpr(ast, context) { 6418 return this.visitExpression(ast, context); 6419 } 6420 6421 visitWriteVarExpr(ast, context) { 6422 ast.value.visitExpression(this, context); 6423 return this.visitExpression(ast, context); 6424 } 6425 6426 visitWriteKeyExpr(ast, context) { 6427 ast.receiver.visitExpression(this, context); 6428 ast.index.visitExpression(this, context); 6429 ast.value.visitExpression(this, context); 6430 return this.visitExpression(ast, context); 6431 } 6432 6433 visitWritePropExpr(ast, context) { 6434 ast.receiver.visitExpression(this, context); 6435 ast.value.visitExpression(this, context); 6436 return this.visitExpression(ast, context); 6437 } 6438 6439 visitInvokeFunctionExpr(ast, context) { 6440 ast.fn.visitExpression(this, context); 6441 this.visitAllExpressions(ast.args, context); 6442 return this.visitExpression(ast, context); 6443 } 6444 6445 visitTaggedTemplateExpr(ast, context) { 6446 ast.tag.visitExpression(this, context); 6447 this.visitAllExpressions(ast.template.expressions, context); 6448 return this.visitExpression(ast, context); 6449 } 6450 6451 visitInstantiateExpr(ast, context) { 6452 ast.classExpr.visitExpression(this, context); 6453 this.visitAllExpressions(ast.args, context); 6454 return this.visitExpression(ast, context); 6455 } 6456 6457 visitLiteralExpr(ast, context) { 6458 return this.visitExpression(ast, context); 6459 } 6460 6461 visitLocalizedString(ast, context) { 6462 return this.visitExpression(ast, context); 6463 } 6464 6465 visitExternalExpr(ast, context) { 6466 if (ast.typeParams) { 6467 ast.typeParams.forEach(type => type.visitType(this, context)); 6468 } 6469 6470 return this.visitExpression(ast, context); 6471 } 6472 6473 visitConditionalExpr(ast, context) { 6474 ast.condition.visitExpression(this, context); 6475 ast.trueCase.visitExpression(this, context); 6476 ast.falseCase.visitExpression(this, context); 6477 return this.visitExpression(ast, context); 6478 } 6479 6480 visitNotExpr(ast, context) { 6481 ast.condition.visitExpression(this, context); 6482 return this.visitExpression(ast, context); 6483 } 6484 6485 visitFunctionExpr(ast, context) { 6486 this.visitAllStatements(ast.statements, context); 6487 return this.visitExpression(ast, context); 6488 } 6489 6490 visitUnaryOperatorExpr(ast, context) { 6491 ast.expr.visitExpression(this, context); 6492 return this.visitExpression(ast, context); 6493 } 6494 6495 visitBinaryOperatorExpr(ast, context) { 6496 ast.lhs.visitExpression(this, context); 6497 ast.rhs.visitExpression(this, context); 6498 return this.visitExpression(ast, context); 6499 } 6500 6501 visitReadPropExpr(ast, context) { 6502 ast.receiver.visitExpression(this, context); 6503 return this.visitExpression(ast, context); 6504 } 6505 6506 visitReadKeyExpr(ast, context) { 6507 ast.receiver.visitExpression(this, context); 6508 ast.index.visitExpression(this, context); 6509 return this.visitExpression(ast, context); 6510 } 6511 6512 visitLiteralArrayExpr(ast, context) { 6513 this.visitAllExpressions(ast.entries, context); 6514 return this.visitExpression(ast, context); 6515 } 6516 6517 visitLiteralMapExpr(ast, context) {
6518 ast.entries.forEach(entry => entry.value.visitExpression(this, context)); 6519 return this.visitExpression(ast, context); 6520 } 6521 6522 visitCommaExpr(ast, context) { 6523 this.visitAllExpressions(ast.parts, context); 6524 return this.visitExpression(ast, context); 6525 } 6526 6527 visitAllExpressions(exprs, context) { 6528 exprs.forEach(expr => expr.visitExpression(this, context)); 6529 } 6530 6531 visitDeclareVarStmt(stmt, context) { 6532 if (stmt.value) { 6533 stmt.value.visitExpression(this, context); 6534 } 6535 6536 if (stmt.type) { 6537 stmt.type.visitType(this, context); 6538 } 6539 6540 return stmt; 6541 } 6542 6543 visitDeclareFunctionStmt(stmt, context) { 6544 this.visitAllStatements(stmt.statements, context); 6545 6546 if (stmt.type) { 6547 stmt.type.visitType(this, context); 6548 } 6549 6550 return stmt; 6551 } 6552 6553 visitExpressionStmt(stmt, context) { 6554 stmt.expr.visitExpression(this, context); 6555 return stmt; 6556 } 6557 6558 visitReturnStmt(stmt, context) { 6559 stmt.value.visitExpression(this, context); 6560 return stmt; 6561 } 6562 6563 visitIfStmt(stmt, context) { 6564 stmt.condition.visitExpression(this, context); 6565 this.visitAllStatements(stmt.trueCase, context); 6566 this.visitAllStatements(stmt.falseCase, context); 6567 return stmt; 6568 } 6569 6570 visitAllStatements(stmts, context) { 6571 stmts.forEach(stmt => stmt.visitStatement(this, context)); 6572 } 6573 6574} 6575 6576function leadingComment(text, multiline = false, trailingNewline = true) { 6577 return new LeadingComment(text, multiline, trailingNewline); 6578} 6579 6580function jsDocComment(tags = []) { 6581 return new JSDocComment(tags); 6582} 6583 6584function variable(name, type, sourceSpan) { 6585 return new ReadVarExpr(name, type, sourceSpan); 6586} 6587 6588function importExpr(id, typeParams = null, sourceSpan) { 6589 return new ExternalExpr(id, null, typeParams, sourceSpan); 6590} 6591 6592function importType(id, typeParams, typeModifiers) { 6593 return id != null ? expressionType(importExpr(id, typeParams, null), typeModifiers) : null; 6594} 6595 6596function expressionType(expr, typeModifiers, typeParams) { 6597 return new ExpressionType(expr, typeModifiers, typeParams); 6598} 6599 6600function typeofExpr(expr) { 6601 return new TypeofExpr(expr); 6602} 6603 6604function literalArr(values, type, sourceSpan) { 6605 return new LiteralArrayExpr(values, type, sourceSpan); 6606} 6607 6608function literalMap(values, type = null) { 6609 return new LiteralMapExpr(values.map(e => new LiteralMapEntry(e.key, e.value, e.quoted)), type, null); 6610} 6611 6612function unary(operator, expr, type, sourceSpan) { 6613 return new UnaryOperatorExpr(operator, expr, type, sourceSpan); 6614} 6615 6616function not(expr, sourceSpan) { 6617 return new NotExpr(expr, sourceSpan); 6618} 6619 6620function fn(params, body, type, sourceSpan, name) { 6621 return new FunctionExpr(params, body, type, sourceSpan, name); 6622} 6623 6624function ifStmt(condition, thenClause, elseClause, sourceSpan, leadingComments) { 6625 return new IfStmt(condition, thenClause, elseClause, sourceSpan, leadingComments); 6626} 6627 6628function taggedTemplate(tag, template, type, sourceSpan) { 6629 return new TaggedTemplateExpr(tag, template, type, sourceSpan); 6630} 6631 6632function literal(value, type, sourceSpan) { 6633 return new LiteralExpr(value, type, sourceSpan); 6634} 6635 6636function localizedString(metaBlock, messageParts, placeholderNames, expressions, sourceSpan) { 6637 return new LocalizedString(metaBlock, messageParts, placeholderNames, expressions, sourceSpan); 6638} 6639 6640function isNull(exp) { 6641 return exp instanceof LiteralExpr && exp.value === null; 6642} 6643/* 6644 * Serializes a `Tag` into a string. 6645 * Returns a string like " @foo {bar} baz" (note the leading whitespace before `@foo`). 6646 */ 6647 6648 6649function tagToString(tag) { 6650 let out = ''; 6651 6652 if (tag.tagName) { 6653 out += ` @${tag.tagName}`; 6654 } 6655 6656 if (tag.text) { 6657 if (tag.text.match(/\/\*|\*\//)) { 6658 throw new Error('JSDoc text cannot contain "/*" and "*/"'); 6659 } 6660 6661 out += ' ' + tag.text.replace(/@/g, '\\@'); 6662 } 6663 6664 return out; 6665} 6666 6667function serializeTags(tags) { 6668 if (tags.length === 0) return ''; 6669 6670 if (tags.length === 1 && tags[0].tagName && !tags[0].text) { 6671 // The JSDOC comment is a single simple tag: e.g `/** @tagname */`. 6672 return `*${tagToString(tags[0])} `; 6673 } 6674 6675 let out = '*\n'; 6676 6677 for (const tag of tags) { 6678 out += ' *'; // If the tagToString is multi-line, insert " * " prefixes on lines. 6679 6680 out += tagToString(tag).replace(/\n/g, '\n * '); 6681 out += '\n'; 6682 } 6683 6684 out += ' '; 6685 return out; 6686} 6687 6688var output_ast = /*#__PURE__*/Object.freeze({ 6689 __proto__: null, 6690 6691 get TypeModifier() { 6692 return TypeModifier; 6693 }, 6694 6695 Type: Type, 6696 6697 get BuiltinTypeName() { 6698 return BuiltinTypeName; 6699 }, 6700 6701 BuiltinType: BuiltinType, 6702 ExpressionType: ExpressionType, 6703 ArrayType: ArrayType, 6704 MapType: MapType, 6705 DYNAMIC_TYPE: DYNAMIC_TYPE, 6706 INFERRED_TYPE: INFERRED_TYPE, 6707 BOOL_TYPE: BOOL_TYPE, 6708 INT_TYPE: INT_TYPE, 6709 NUMBER_TYPE: NUMBER_TYPE, 6710 STRING_TYPE: STRING_TYPE, 6711 FUNCTION_TYPE: FUNCTION_TYPE, 6712 NONE_TYPE: NONE_TYPE, 6713 6714 get UnaryOperator() { 6715 return UnaryOperator; 6716 }, 6717 6718 get BinaryOperator() { 6719 return BinaryOperator; 6720 }, 6721 6722 nullSafeIsEquivalent: nullSafeIsEquivalent, 6723 areAllEquivalent: areAllEquivalent, 6724 Expression: Expression, 6725 ReadVarExpr: ReadVarExpr, 6726 TypeofExpr: TypeofExpr, 6727 WrappedNodeExpr: WrappedNodeExpr, 6728 WriteVarExpr: WriteVarExpr, 6729 WriteKeyExpr: WriteKeyExpr, 6730 WritePropExpr: WritePropExpr, 6731 InvokeFunctionExpr: InvokeFunctionExpr, 6732 TaggedTemplateExpr: TaggedTemplateExpr, 6733 InstantiateExpr: InstantiateExpr, 6734 LiteralExpr: LiteralExpr,
6735 TemplateLiteral: TemplateLiteral, 6736 TemplateLiteralElement: TemplateLiteralElement, 6737 LiteralPiece: LiteralPiece, 6738 PlaceholderPiece: PlaceholderPiece, 6739 LocalizedString: LocalizedString, 6740 ExternalExpr: ExternalExpr, 6741 ExternalReference: ExternalReference, 6742 ConditionalExpr: ConditionalExpr, 6743 NotExpr: NotExpr, 6744 FnParam: FnParam, 6745 FunctionExpr: FunctionExpr, 6746 UnaryOperatorExpr: UnaryOperatorExpr, 6747 BinaryOperatorExpr: BinaryOperatorExpr, 6748 ReadPropExpr: ReadPropExpr, 6749 ReadKeyExpr: ReadKeyExpr, 6750 LiteralArrayExpr: LiteralArrayExpr, 6751 LiteralMapEntry: LiteralMapEntry, 6752 LiteralMapExpr: LiteralMapExpr, 6753 CommaExpr: CommaExpr, 6754 NULL_EXPR: NULL_EXPR, 6755 TYPED_NULL_EXPR: TYPED_NULL_EXPR, 6756 6757 get StmtModifier() { 6758 return StmtModifier; 6759 }, 6760 6761 LeadingComment: LeadingComment, 6762 JSDocComment: JSDocComment, 6763 Statement: Statement, 6764 DeclareVarStmt: DeclareVarStmt, 6765 DeclareFunctionStmt: DeclareFunctionStmt, 6766 ExpressionStatement: ExpressionStatement, 6767 ReturnStatement: ReturnStatement, 6768 IfStmt: IfStmt, 6769 RecursiveAstVisitor: RecursiveAstVisitor$1, 6770 leadingComment: leadingComment, 6771 jsDocComment: jsDocComment, 6772 variable: variable, 6773 importExpr: importExpr, 6774 importType: importType, 6775 expressionType: expressionType, 6776 typeofExpr: typeofExpr, 6777 literalArr: literalArr, 6778 literalMap: literalMap, 6779 unary: unary, 6780 not: not, 6781 fn: fn, 6782 ifStmt: ifStmt, 6783 taggedTemplate: taggedTemplate, 6784 literal: literal, 6785 localizedString: localizedString, 6786 isNull: isNull 6787}); 6788/** 6789 * @license 6790 * Copyright Google LLC All Rights Reserved. 6791 * 6792 * Use of this source code is governed by an MIT-style license that can be 6793 * found in the LICENSE file at https://angular.io/license 6794 */ 6795 6796const CONSTANT_PREFIX = '_c'; 6797/** 6798 * `ConstantPool` tries to reuse literal factories when two or more literals are identical. 6799 * We determine whether literals are identical by creating a key out of their AST using the 6800 * `KeyVisitor`. This constant is used to replace dynamic expressions which can't be safely 6801 * converted into a key. E.g. given an expression `{foo: bar()}`, since we don't know what 6802 * the result of `bar` will be, we create a key that looks like `{foo: <unknown>}`. Note 6803 * that we use a variable, rather than something like `null` in order to avoid collisions. 6804 */ 6805 6806const UNKNOWN_VALUE_KEY = variable('<unknown>'); 6807/** 6808 * Context to use when producing a key. 6809 * 6810 * This ensures we see the constant not the reference variable when producing 6811 * a key. 6812 */ 6813 6814const KEY_CONTEXT = {}; 6815/** 6816 * Generally all primitive values are excluded from the `ConstantPool`, but there is an exclusion 6817 * for strings that reach a certain length threshold. This constant defines the length threshold for 6818 * strings. 6819 */ 6820 6821const POOL_INCLUSION_LENGTH_THRESHOLD_FOR_STRINGS = 50; 6822/** 6823 * A node that is a place-holder that allows the node to be replaced when the actual 6824 * node is known. 6825 * 6826 * This allows the constant pool to change an expression from a direct reference to 6827 * a constant to a shared constant. It returns a fix-up node that is later allowed to 6828 * change the referenced expression. 6829 */ 6830 6831class FixupExpression extends Expression { 6832 constructor(resolved) { 6833 super(resolved.type); 6834 this.resolved = resolved; 6835 this.original = resolved; 6836 } 6837 6838 visitExpression(visitor, context) { 6839 if (context === KEY_CONTEXT) { 6840 // When producing a key we want to traverse the constant not the 6841 // variable used to refer to it. 6842 return this.original.visitExpression(visitor, context); 6843 } else { 6844 return this.resolved.visitExpression(visitor, context); 6845 } 6846 } 6847 6848 isEquivalent(e) { 6849 return e instanceof FixupExpression && this.resolved.isEquivalent(e.resolved); 6850 } 6851 6852 isConstant() { 6853 return true; 6854 } 6855 6856 fixup(expression) { 6857 this.resolved = expression; 6858 this.shared = true; 6859 } 6860 6861} 6862/** 6863 * A constant pool allows a code emitter to share constant in an output context. 6864 * 6865 * The constant pool also supports sharing access to ivy definitions references. 6866 */ 6867 6868 6869class ConstantPool { 6870 constructor(isClosureCompilerEnabled = false) { 6871 this.isClosureCompilerEnabled = isClosureCompilerEnabled; 6872 this.statements = []; 6873 this.literals = new Map(); 6874 this.literalFactories = new Map(); 6875 this.nextNameIndex = 0; 6876 } 6877 6878 getConstLiteral(literal, forceShared) { 6879 if (literal instanceof LiteralExpr && !isLongStringLiteral(literal) || literal instanceof FixupExpression) {
6880 // Do no put simple literals into the constant pool or try to produce a constant for a 6881 // reference to a constant. 6882 return literal; 6883 } 6884 6885 const key = this.keyOf(literal); 6886 let fixup = this.literals.get(key); 6887 let newValue = false; 6888 6889 if (!fixup) { 6890 fixup = new FixupExpression(literal); 6891 this.literals.set(key, fixup); 6892 newValue = true; 6893 } 6894 6895 if (!newValue && !fixup.shared || newValue && forceShared) { 6896 // Replace the expression with a variable 6897 const name = this.freshName(); 6898 let definition; 6899 let usage; 6900 6901 if (this.isClosureCompilerEnabled && isLongStringLiteral(literal)) { 6902 // For string literals, Closure will **always** inline the string at 6903 // **all** usages, duplicating it each time. For large strings, this 6904 // unnecessarily bloats bundle size. To work around this restriction, we 6905 // wrap the string in a function, and call that function for each usage. 6906 // This tricks Closure into using inline logic for functions instead of 6907 // string literals. Function calls are only inlined if the body is small 6908 // enough to be worth it. By doing this, very large strings will be 6909 // shared across multiple usages, rather than duplicating the string at 6910 // each usage site. 6911 // 6912 // const myStr = function() { return "very very very long string"; }; 6913 // const usage1 = myStr(); 6914 // const usage2 = myStr(); 6915 definition = variable(name).set(new FunctionExpr([], // Params. 6916 [// Statements.
6917 new ReturnStatement(literal)])); 6918 usage = variable(name).callFn([]); 6919 } else { 6920 // Just declare and use the variable directly, without a function call 6921 // indirection. This saves a few bytes and avoids an unnecessary call. 6922 definition = variable(name).set(literal); 6923 usage = variable(name); 6924 } 6925 6926 this.statements.push(definition.toDeclStmt(INFERRED_TYPE, StmtModifier.Final)); 6927 fixup.fixup(usage); 6928 } 6929 6930 return fixup; 6931 } 6932 6933 getLiteralFactory(literal) { 6934 // Create a pure function that builds an array of a mix of constant and variable expressions 6935 if (literal instanceof LiteralArrayExpr) { 6936 const argumentsForKey = literal.entries.map(e => e.isConstant() ? e : UNKNOWN_VALUE_KEY); 6937 const key = this.keyOf(literalArr(argumentsForKey)); 6938 return this._getLiteralFactory(key, literal.entries, entries => literalArr(entries)); 6939 } else { 6940 const expressionForKey = literalMap(literal.entries.map(e => ({ 6941 key: e.key, 6942 value: e.value.isConstant() ? e.value : UNKNOWN_VALUE_KEY, 6943 quoted: e.quoted 6944 }))); 6945 const key = this.keyOf(expressionForKey); 6946 return this._getLiteralFactory(key, literal.entries.map(e => e.value), entries => literalMap(entries.map((value, index) => ({ 6947 key: literal.entries[index].key, 6948 value, 6949 quoted: literal.entries[index].quoted 6950 })))); 6951 } 6952 } 6953 6954 _getLiteralFactory(key, values, resultMap) { 6955 let literalFactory = this.literalFactories.get(key); 6956 const literalFactoryArguments = values.filter(e => !e.isConstant()); 6957 6958 if (!literalFactory) { 6959 const resultExpressions = values.map((e, index) => e.isConstant() ? this.getConstLiteral(e, true) : variable(`a${index}`)); 6960 const parameters = resultExpressions.filter(isVariable).map(e => new FnParam(e.name, DYNAMIC_TYPE)); 6961 const pureFunctionDeclaration = fn(parameters, [new ReturnStatement
6961(resultMap(resultExpressions))], INFERRED_TYPE); 6962 const name = this.freshName(); 6963 this.statements.push(variable(name).set(pureFunctionDeclaration).toDeclStmt(INFERRED_TYPE, StmtModifier.Final)); 6964 literalFactory = variable(name); 6965 this.literalFactories.set(key, literalFactory); 6966 } 6967 6968 return { 6969 literalFactory, 6970 literalFactoryArguments 6971 }; 6972 } 6973 /** 6974 * Produce a unique name. 6975 * 6976 * The name might be unique among different prefixes if any of the prefixes end in 6977 * a digit so the prefix should be a constant string (not based on user input) and 6978 * must not end in a digit. 6979 */ 6980 6981 6982 uniqueName(prefix) { 6983 return `${prefix}${this.nextNameIndex++}`; 6984 } 6985 6986 freshName() { 6987 return this.uniqueName(CONSTANT_PREFIX); 6988 } 6989 6990 keyOf(expression) { 6991 return expression.visitExpression(new KeyVisitor(), KEY_CONTEXT); 6992 } 6993 6994} 6995/** 6996 * Visitor used to determine if 2 expressions are equivalent and can be shared in the 6997 * `ConstantPool`. 6998 * 6999 * When the id (string) generated by the visitor is equal, expressions are considered equivalent. 7000 */ 7001 7002 7003class KeyVisitor { 7004 constructor() { 7005 this.visitWrappedNodeExpr = invalid$1; 7006 this.visitWriteVarExpr = invalid$1; 7007 this.visitWriteKeyExpr = invalid$1; 7008 this.visitWritePropExpr = invalid$1; 7009 this.visitInvokeFunctionExpr = invalid$1; 7010 this.visitTaggedTemplateExpr = invalid$1; 7011 this.visitInstantiateExpr = invalid$1; 7012 this.visitConditionalExpr = invalid$1; 7013 this.visitNotExpr = invalid$1; 7014 this.visitAssertNotNullExpr = invalid$1; 7015 this.visitCastExpr = invalid$1; 7016 this.visitFunctionExpr = invalid$1; 7017 this.visitUnaryOperatorExpr = invalid$1; 7018 this.visitBinaryOperatorExpr = invalid$1; 7019 this.visitReadPropExpr = invalid$1; 7020 this.visitReadKeyExpr = invalid$1; 7021 this.visitCommaExpr = invalid$1; 7022 this.visitLocalizedString = invalid$1; 7023 } 7024 7025 visitLiteralExpr(ast) { 7026 return `${typeof ast.value === 'string' ? '"' + ast.value + '"' : ast.value}`; 7027 } 7028 7029 visitLiteralArrayExpr(ast, context) { 7030 return `[${ast.entries.map(entry => entry.visitExpression(this, context)).join(',')}]`; 7031 } 7032 7033 visitLiteralMapExpr(ast, context) { 7034 const mapKey = entry => { 7035 const quote = entry.quoted ? '"' : ''; 7036 return `${quote}${entry.key}${quote}`; 7037 }; 7038 7039 const mapEntry = entry => `${mapKey(entry)}:${entry.value.visitExpression(this, context)}`; 7040 7041 return `{${ast.entries.map(mapEntry).join(',')}`; 7042 } 7043 7044 visitExternalExpr(ast) { 7045 return ast.value.moduleName ? `EX:${ast.value.moduleName}:${ast.value.name}` : `EX:${ast.value.runtime.name}`; 7046 } 7047 7048 visitReadVarExpr(node) { 7049 return `VAR:${node.name}`; 7050 } 7051 7052 visitTypeofExpr(node, context) { 7053 return `TYPEOF:${node.expr.visitExpression(this, context)}`; 7054 } 7055 7056} 7057
7058function invalid$1(arg) { 7059 throw new Error(`Invalid state: Visitor ${this.constructor.name} doesn't handle ${arg.constructor.name}`); 7060} 7061 7062function isVariable(e) { 7063 return e instanceof ReadVarExpr; 7064} 7065 7066function isLongStringLiteral(expr) { 7067 return expr instanceof LiteralExpr && typeof expr.value === 'string' && expr.value.length >= POOL_INCLUSION_LENGTH_THRESHOLD_FOR_STRINGS; 7068} 7069/** 7070 * @license 7071 * Copyright Google LLC All Rights Reserved. 7072 * 7073 * Use of this source code is governed by an MIT-style license that can be 7074 * found in the LICENSE file at https://angular.io/license 7075 */ 7076 7077 7078const CORE = '@angular/core'; 7079 7080class Identifiers {} 7081/* Methods */ 7082 7083 7084Identifiers.NEW_METHOD = 'factory'; 7085Identifiers.TRANSFORM_METHOD = 'transform'; 7086Identifiers.PATCH_DEPS = 'patchedDeps'; 7087Identifiers.core = { 7088 name: null, 7089 moduleName: CORE 7090}; 7091/* Instructions */ 7092 7093Identifiers.namespaceHTML = { 7094 name: 'ɵɵnamespaceHTML', 7095 moduleName: CORE 7096}; 7097Identifiers.namespaceMathML = { 7098 name: 'ɵɵnamespaceMathML', 7099 moduleName: CORE 7100}; 7101Identifiers.namespaceSVG = { 7102 name: 'ɵɵnamespaceSVG', 7103 moduleName: CORE 7104}; 7105Identifiers.element = { 7106 name: 'ɵɵelement', 7107 moduleName: CORE 7108}; 7109Identifiers.elementStart = { 7110 name: 'ɵɵelementStart', 7111 moduleName: CORE 7112}; 7113Identifiers.elementEnd = { 7114 name: 'ɵɵelementEnd', 7115 moduleName: CORE 7116}; 7117Identifiers.advance = { 7118 name: 'ɵɵadvance', 7119 moduleName: CORE 7120}; 7121Identifiers.syntheticHostProperty = { 7122 name: 'ɵɵsyntheticHostProperty', 7123 moduleName: CORE 7124}; 7125Identifiers.syntheticHostListener = { 7126 name: 'ɵɵsyntheticHostListener', 7127 moduleName: CORE 7128}; 7129Identifiers.attribute = { 7130 name: 'ɵɵattribute', 7131 moduleName: CORE 7132}; 7133Identifiers.attributeInterpolate1 = { 7134 name: 'ɵɵattributeInterpolate1', 7135 moduleName: CORE 7136}; 7137Identifiers.attributeInterpolate2 = { 7138 name: 'ɵɵattributeInterpolate2', 7139 moduleName: CORE 7140}; 7141Identifiers.attributeInterpolate3 = { 7142 name: 'ɵɵattributeInterpolate3', 7143 moduleName: CORE 7144}; 7145Identifiers.attributeInterpolate4 = { 7146 name: 'ɵɵattributeInterpolate4', 7147 moduleName: CORE 7148}; 7149Identifiers.attributeInterpolate5 = { 7150 name: 'ɵɵattributeInterpolate5', 7151 moduleName: CORE 7152}; 7153Identifiers.attributeInterpolate6 = { 7154 name: 'ɵɵattributeInterpolate6', 7155 moduleName: CORE 7156}; 7157Identifiers.attributeInterpolate7 = { 7158 name: 'ɵɵattributeInterpolate7', 7159 moduleName: CORE 7160}; 7161Identifiers.attributeInterpolate8 = { 7162 name: 'ɵɵattributeInterpolate8', 7163 moduleName: CORE 7164}; 7165Identifiers.attributeInterpolateV = { 7166 name: 'ɵɵattributeInterpolateV', 7167 moduleName: CORE 7168}; 7169Identifiers.classProp = { 7170 name: 'ɵɵclassProp', 7171 moduleName: CORE 7172}; 7173Identifiers.elementContainerStart = { 7174 name: 'ɵɵelementContainerStart', 7175 moduleName: CORE 7176}; 7177Identifiers.elementContainerEnd = { 7178 name: 'ɵɵelementContainerEnd', 7179 moduleName: CORE 7180}; 7181Identifiers.elementContainer = { 7182 name: 'ɵɵelementContainer', 7183 moduleName: CORE 7184}; 7185Identifiers.styleMap = { 7186 name: 'ɵɵstyleMap', 7187 moduleName: CORE 7188}; 7189Identifiers.styleMapInterpolate1 = { 7190 name: 'ɵɵstyleMapInterpolate1', 7191 moduleName: CORE 7192}; 7193Identifiers.styleMapInterpolate2 = { 7194 name: 'ɵɵstyleMapInterpolate2', 7195 moduleName: CORE 7196}; 7197Identifiers.styleMapInterpolate3 = { 7198 name: 'ɵɵstyleMapInterpolate3', 7199 moduleName: CORE 7200}; 7201Identifiers.styleMapInterpolate4 = { 7202 name: 'ɵɵstyleMapInterpolate4', 7203 moduleName: CORE 7204}; 7205Identifiers.styleMapInterpolate5 = { 7206 name: 'ɵɵstyleMapInterpolate5', 7207 moduleName: CORE 7208}; 7209Identifiers.styleMapInterpolate6 = { 7210 name: 'ɵɵstyleMapInterpolate6', 7211 moduleName: CORE 7212}; 7213Identifiers.styleMapInterpolate7 = { 7214 name: 'ɵɵstyleMapInterpolate7', 7215 moduleName: CORE 7216}; 7217Identifiers.styleMapInterpolate8 = { 7218 name: 'ɵɵstyleMapInterpolate8', 7219 moduleName: CORE 7220}; 7221Identifiers.styleMapInterpolateV = { 7222 name: 'ɵɵstyleMapInterpolateV', 7223 moduleName: CORE 7224}; 7225Identifiers.classMap = { 7226 name: 'ɵɵclassMap', 7227 moduleName: CORE 7228}; 7229Identifiers.classMapInterpolate1 = { 7230 name: 'ɵɵclassMapInterpolate1', 7231 moduleName: CORE 7232}; 7233Identifiers.classMapInterpolate2 = { 7234 name: 'ɵɵclassMapInterpolate2', 7235 moduleName: CORE 7236}; 7237Identifiers.classMapInterpolate3 = { 7238 name: 'ɵɵclassMapInterpolate3', 7239 moduleName: CORE 7240}; 7241Identifiers.classMapInterpolate4 = { 7242 name: 'ɵɵclassMapInterpolate4', 7243 moduleName: CORE 7244}; 7245Identifiers.classMapInterpolate5 = { 7246 name: 'ɵɵclassMapInterpolate5', 7247 moduleName: CORE 7248}; 7249Identifiers.classMapInterpolate6 = { 7250 name: 'ɵɵclassMapInterpolate6', 7251 moduleName: CORE 7252}; 7253Identifiers.classMapInterpolate7 = { 7254 name: 'ɵɵclassMapInterpolate7', 7255 moduleName: CORE 7256}; 7257Identifiers.classMapInterpolate8 = { 7258 name: 'ɵɵclassMapInterpolate8', 7259 moduleName: CORE 7260}; 7261Identifiers.classMapInterpolateV = { 7262 name: 'ɵɵclassMapInterpolateV', 7263 moduleName: CORE 7264}; 7265Identifiers.styleProp = { 7266 name: 'ɵɵstyleProp', 7267 moduleName: CORE 7268}; 7269Identifiers.stylePropInterpolate1 = { 7270 name: 'ɵɵstylePropInterpolate1', 7271 moduleName: CORE 7272}; 7273Identifiers.stylePropInterpolate2 = { 7274 name: 'ɵɵstylePropInterpolate2', 7275 moduleName: CORE 7276}; 7277Identifiers.stylePropInterpolate3 = { 7278 name: 'ɵɵstylePropInterpolate3', 7279 moduleName: CORE 7280}; 7281Identifiers.stylePropInterpolate4 = { 7282 name: 'ɵɵstylePropInterpolate4', 7283 moduleName: CORE 7284}; 7285Identifiers.stylePropInterpolate5 = { 7286 name: 'ɵɵstylePropInterpolate5', 7287 moduleName: CORE 7288}; 7289Identifiers.stylePropInterpolate6 = { 7290 name: 'ɵɵstylePropInterpolate6', 7291 moduleName: CORE 7292}; 7293Identifiers.stylePropInterpolate7 = { 7294 name: 'ɵɵstylePropInterpolate7', 7295 moduleName: CORE 7296}; 7297Identifiers.stylePropInterpolate8 = { 7298 name: 'ɵɵstylePropInterpolate8', 7299 moduleName: CORE 7300}; 7301Identifiers.stylePropInterpolateV = { 7302 name: 'ɵɵstylePropInterpolateV', 7303 moduleName: CORE 7304}; 7305Identifiers.nextContext = { 7306 name: 'ɵɵnextContext', 7307 moduleName: CORE 7308}; 7309Identifiers.resetView = {
7310 name: 'ɵɵresetView', 7311 moduleName: CORE 7312}; 7313Identifiers.templateCreate = { 7314 name: 'ɵɵtemplate', 7315 moduleName: CORE 7316}; 7317Identifiers.text = { 7318 name: 'ɵɵtext', 7319 moduleName: CORE 7320}; 7321Identifiers.enableBindings = { 7322 name: 'ɵɵenableBindings', 7323 moduleName: CORE 7324}; 7325Identifiers.disableBindings = { 7326 name: 'ɵɵdisableBindings', 7327 moduleName: CORE 7328}; 7329Identifiers.getCurrentView = { 7330 name: 'ɵɵgetCurrentView', 7331 moduleName: CORE 7332}; 7333Identifiers.textInterpolate = { 7334 name: 'ɵɵtextInterpolate', 7335 moduleName: CORE 7336}; 7337Identifiers.textInterpolate1 = { 7338 name: 'ɵɵtextInterpolate1', 7339 moduleName: CORE 7340}; 7341Identifiers.textInterpolate2 = { 7342 name: 'ɵɵtextInterpolate2', 7343 moduleName: CORE 7344}; 7345Identifiers.textInterpolate3 = { 7346 name: 'ɵɵtextInterpolate3', 7347 moduleName: CORE 7348}; 7349Identifiers.textInterpolate4 = { 7350 name: 'ɵɵtextInterpolate4', 7351 moduleName: CORE 7352}; 7353Identifiers.textInterpolate5 = { 7354 name: 'ɵɵtextInterpolate5', 7355 moduleName: CORE 7356}; 7357Identifiers.textInterpolate6 = { 7358 name: 'ɵɵtextInterpolate6', 7359 moduleName: CORE 7360}; 7361Identifiers.textInterpolate7 = { 7362 name: 'ɵɵtextInterpolate7', 7363 moduleName: CORE 7364}; 7365Identifiers.textInterpolate8 = { 7366 name: 'ɵɵtextInterpolate8', 7367 moduleName: CORE 7368}; 7369Identifiers.textInterpolateV = { 7370 name: 'ɵɵtextInterpolateV', 7371 moduleName: CORE 7372}; 7373Identifiers.restoreView = { 7374 name: 'ɵɵrestoreView', 7375 moduleName: CORE 7376}; 7377Identifiers.pureFunction0 = { 7378 name: 'ɵɵpureFunction0', 7379 moduleName: CORE 7380}; 7381Identifiers.pureFunction1 = { 7382 name: 'ɵɵpureFunction1', 7383 moduleName: CORE 7384}; 7385Identifiers.pureFunction2 = { 7386 name: 'ɵɵpureFunction2', 7387 moduleName: CORE 7388}; 7389Identifiers.pureFunction3 = { 7390 name: 'ɵɵpureFunction3', 7391 moduleName: CORE 7392}; 7393Identifiers.pureFunction4 = { 7394 name: 'ɵɵpureFunction4', 7395 moduleName: CORE 7396}; 7397Identifiers.pureFunction5 = { 7398 name: 'ɵɵpureFunction5', 7399 moduleName: CORE 7400}; 7401Identifiers.pureFunction6 = { 7402 name: 'ɵɵpureFunction6', 7403 moduleName: CORE 7404}; 7405Identifiers.pureFunction7 = { 7406 name: 'ɵɵpureFunction7', 7407 moduleName: CORE 7408}; 7409Identifiers.pureFunction8 = { 7410 name: 'ɵɵpureFunction8', 7411 moduleName: CORE 7412}; 7413Identifiers.pureFunctionV = { 7414 name: 'ɵɵpureFunctionV', 7415 moduleName: CORE 7416}; 7417Identifiers.pipeBind1 = { 7418 name: 'ɵɵpipeBind1', 7419 moduleName: CORE 7420}; 7421Identifiers.pipeBind2 = { 7422 name: 'ɵɵpipeBind2', 7423 moduleName: CORE 7424}; 7425Identifiers.pipeBind3 = { 7426 name: 'ɵɵpipeBind3', 7427 moduleName: CORE 7428}; 7429Identifiers.pipeBind4 = { 7430 name: 'ɵɵpipeBind4', 7431 moduleName: CORE 7432}; 7433Identifiers.pipeBindV = { 7434 name: 'ɵɵpipeBindV', 7435 moduleName: CORE 7436}; 7437Identifiers.hostProperty = { 7438 name: 'ɵɵhostProperty', 7439 moduleName: CORE 7440}; 7441Identifiers.property = { 7442 name: 'ɵɵproperty', 7443 moduleName: CORE 7444}; 7445Identifiers.propertyInterpolate = { 7446 name: 'ɵɵpropertyInterpolate', 7447 moduleName: CORE 7448}; 7449Identifiers.propertyInterpolate1 = { 7450 name: 'ɵɵpropertyInterpolate1', 7451 moduleName: CORE 7452}; 7453Identifiers.propertyInterpolate2 = { 7454 name: 'ɵɵpropertyInterpolate2', 7455 moduleName: CORE 7456}; 7457Identifiers.propertyInterpolate3 = { 7458 name: 'ɵɵpropertyInterpolate3', 7459 moduleName: CORE 7460}; 7461Identifiers.propertyInterpolate4 = { 7462 name: 'ɵɵpropertyInterpolate4', 7463 moduleName: CORE 7464}; 7465Identifiers.propertyInterpolate5 = { 7466 name: 'ɵɵpropertyInterpolate5', 7467 moduleName: CORE 7468}; 7469Identifiers.propertyInterpolate6 = { 7470 name: 'ɵɵpropertyInterpolate6', 7471 moduleName: CORE 7472}; 7473Identifiers.propertyInterpolate7 = { 7474 name: 'ɵɵpropertyInterpolate7', 7475 moduleName: CORE 7476}; 7477Identifiers.propertyInterpolate8 = { 7478 name: 'ɵɵpropertyInterpolate8', 7479 moduleName: CORE 7480}; 7481Identifiers.propertyInterpolateV = { 7482 name: 'ɵɵpropertyInterpolateV', 7483 moduleName: CORE 7484}; 7485Identifiers.i18n = { 7486 name: 'ɵɵi18n', 7487 moduleName: CORE 7488}; 7489Identifiers.i18nAttributes = { 7490 name: 'ɵɵi18nAttributes', 7491 moduleName: CORE 7492}; 7493Identifiers.i18nExp = { 7494 name: 'ɵɵi18nExp', 7495 moduleName: CORE 7496}; 7497Identifiers.i18nStart = { 7498 name: 'ɵɵi18nStart', 7499 moduleName: CORE 7500}; 7501Identifiers.i18nEnd = { 7502 name: 'ɵɵi18nEnd', 7503 moduleName: CORE 7504}; 7505Identifiers.i18nApply = { 7506 name: 'ɵɵi18nApply', 7507 moduleName: CORE 7508}; 7509Identifiers.i18nPostprocess = { 7510 name: 'ɵɵi18nPostprocess', 7511 moduleName: CORE 7512}; 7513Identifiers.pipe = { 7514 name: 'ɵɵpipe', 7515 moduleName: CORE 7516}; 7517Identifiers.projection = { 7518 name: 'ɵɵprojection', 7519 moduleName: CORE 7520}; 7521Identifiers.projectionDef = { 7522 name: 'ɵɵprojectionDef', 7523 moduleName: CORE 7524}; 7525Identifiers.reference = { 7526 name: 'ɵɵreference', 7527 moduleName: CORE 7528}; 7529Identifiers.inject = { 7530 name: 'ɵɵinject', 7531 moduleName: CORE 7532}; 7533Identifiers.injectAttribute = { 7534 name: 'ɵɵinjectAttribute', 7535 moduleName: CORE 7536}; 7537Identifiers.directiveInject = { 7538 name: 'ɵɵdirectiveInject', 7539 moduleName: CORE 7540}; 7541Identifiers.invalidFactory = { 7542 name: 'ɵɵinvalidFactory', 7543 moduleName: CORE 7544}; 7545Identifiers.invalidFactoryDep = { 7546 name: 'ɵɵinvalidFactoryDep', 7547 moduleName: CORE 7548}; 7549Identifiers.templateRefExtractor = { 7550 name: 'ɵɵtemplateRefExtractor', 7551 moduleName: CORE 7552}; 7553Identifiers.forwardRef = { 7554 name: 'forwardRef', 7555 moduleName: CORE 7556}; 7557Identifiers.resolveForwardRef = { 7558 name: 'resolveForwardRef', 7559 moduleName: CORE 7560}; 7561Identifiers.ɵɵdefineInjectable = { 7562 name: 'ɵɵdefineInjectable', 7563 moduleName: CORE 7564}; 7565Identifiers.declareInjectable = { 7566 name: 'ɵɵngDeclareInjectable', 7567 moduleName: CORE 7568}; 7569Identifiers.InjectableDeclaration = { 7570 name: 'ɵɵInjectableDeclaration', 7571 moduleName: CORE 7572}; 7573Identifiers.resolveWindow = { 7574 name: 'ɵɵresolveWindow', 7575 moduleName: CORE 7576}; 7577Identifiers.resolveDocument = { 7578 name: 'ɵɵresolveDocument', 7579 moduleName: CORE 7580}; 7581Identifiers.resolveBody = { 7582 name: 'ɵɵresolveBody', 7583 moduleName: CORE 7584}; 7585Identifiers.defineComponent = { 7586 name: 'ɵɵdefineComponent', 7587 moduleName: CORE 7588}; 7589Identifiers.declareComponent = { 7590 name: 'ɵɵngDeclareComponent', 7591 moduleName: CORE 7592}; 7593Identifiers.setComponentScope = { 7594 name: 'ɵɵsetComponentScope', 7595 moduleName: CORE 7596}; 7597Identifiers.ChangeDetectionStrategy = { 7598 name: 'ChangeDetectionStrategy', 7599 moduleName: CORE 7600}; 7601Identifiers.ViewEncapsulation = { 7602 name: 'ViewEncapsulation', 7603 moduleName: CORE 7604}; 7605Identifiers.ComponentDeclaration = { 7606 name: 'ɵɵComponentDeclaration', 7607 moduleName: CORE 7608}; 7609Identifiers.FactoryDeclaration = { 7610 name: 'ɵɵFactoryDeclaration', 7611 moduleName: CORE 7612}; 7613Identifiers.declareFactory = { 7614 name: 'ɵɵngDeclareFactory', 7615 moduleName: CORE 7616}; 7617Identifiers.FactoryTarget = { 7618 name: 'ɵɵFactoryTarget', 7619 moduleName: CORE 7620}; 7621Identifiers.defineDirective = { 7622 name: 'ɵɵdefineDirective', 7623 moduleName: CORE 7624}; 7625Identifiers.declareDirective = { 7626 name: 'ɵɵngDeclareDirective', 7627 moduleName: CORE 7628}; 7629Identifiers.DirectiveDeclaration = { 7630 name: 'ɵɵDirectiveDeclaration', 7631 moduleName: CORE 7632}; 7633Identifiers.InjectorDef = { 7634 name: 'ɵɵInjectorDef', 7635 moduleName: CORE 7636}; 7637Identifiers.InjectorDeclaration = { 7638 name: 'ɵɵInjectorDeclaration', 7639 moduleName: CORE 7640}; 7641Identifiers.defineInjector = { 7642 name: 'ɵɵdefineInjector', 7643 moduleName: CORE 7644}; 7645Identifiers.declareInjector = { 7646 name: 'ɵɵngDeclareInjector', 7647 moduleName: CORE 7648}; 7649Identifiers.NgModuleDeclaration = { 7650 name: 'ɵɵNgModuleDeclaration', 7651 moduleName: CORE 7652}; 7653Identifiers.ModuleWithProviders = { 7654 name: 'ModuleWithProviders', 7655 moduleName: CORE 7656}; 7657Identifiers.defineNgModule = { 7658 name: 'ɵɵdefineNgModule', 7659 moduleName: CORE 7660}; 7661Identifiers.declareNgModule = { 7662 name: 'ɵɵngDeclareNgModule', 7663 moduleName: CORE 7664}; 7665Identifiers.setNgModuleScope = { 7666 name: 'ɵɵsetNgModuleScope', 7667 moduleName: CORE 7668}; 7669Identifiers.registerNgModuleType = { 7670 name: 'ɵɵregisterNgModuleType', 7671 moduleName: CORE 7672}; 7673Identifiers.PipeDeclaration = { 7674 name: 'ɵɵPipeDeclaration', 7675 moduleName: CORE 7676}; 7677Identifiers.definePipe = { 7678 name: 'ɵɵdefinePipe', 7679 moduleName: CORE 7680}; 7681Identifiers.declarePipe = { 7682 name: 'ɵɵngDeclarePipe', 7683 moduleName: CORE 7684}; 7685Identifiers.declareClassMetadata = { 7686 name: 'ɵɵngDeclareClassMetadata', 7687 moduleName: CORE 7688}; 7689Identifiers.setClassMetadata = { 7690 name: 'ɵsetClassMetadata', 7691 moduleName: CORE 7692}; 7693Identifiers.queryRefresh = { 7694 name: 'ɵɵqueryRefresh', 7695 moduleName: CORE 7696}; 7697Identifiers.viewQuery = { 7698 name: 'ɵɵviewQuery', 7699 moduleName: CORE 7700}; 7701Identifiers.loadQuery = { 7702 name: 'ɵɵloadQuery', 7703 moduleName: CORE 7704}; 7705Identifiers.contentQuery = { 7706 name: 'ɵɵcontentQuery', 7707 moduleName: CORE 7708}; 7709Identifiers.NgOnChangesFeature = { 7710 name: 'ɵɵNgOnChangesFeature', 7711 moduleName: CORE 7712}; 7713Identifiers.InheritDefinitionFeature = { 7714 name: 'ɵɵInheritDefinitionFeature', 7715 moduleName: CORE 7716}; 7717Identifiers.CopyDefinitionFeature = { 7718 name: 'ɵɵCopyDefinitionFeature', 7719 moduleName: CORE 7720}; 7721Identifiers.StandaloneFeature = { 7722 name: 'ɵɵStandaloneFeature', 7723 moduleName: CORE 7724}; 7725Identifiers.ProvidersFeature = { 7726 name: 'ɵɵProvidersFeature', 7727 moduleName: CORE 7728}; 7729Identifiers.listener = { 7730 name: 'ɵɵlistener', 7731 moduleName: CORE 7732}; 7733Identifiers.getInheritedFactory = { 7734 name: 'ɵɵgetInheritedFactory', 7735 moduleName: CORE 7736}; // sanitization-related functions 7737 7738Identifiers.sanitizeHtml = { 7739 name: 'ɵɵsanitizeHtml', 7740 moduleName: CORE 7741}; 7742Identifiers.sanitizeStyle = { 7743 name: 'ɵɵsanitizeStyle', 7744 moduleName: CORE 7745}; 7746Identifiers.sanitizeResourceUrl = { 7747 name: 'ɵɵsanitizeResourceUrl', 7748 moduleName: CORE 7749}; 7750Identifiers.sanitizeScript = { 7751 name: 'ɵɵsanitizeScript', 7752 moduleName: CORE 7753}; 7754Identifiers.sanitizeUrl = { 7755 name: 'ɵɵsanitizeUrl', 7756 moduleName: CORE 7757}; 7758Identifiers.sanitizeUrlOrResourceUrl = { 7759 name: 'ɵɵsanitizeUrlOrResourceUrl', 7760 moduleName: CORE 7761}; 7762Identifiers.trustConstantHtml = {
7763 name: 'ɵɵtrustConstantHtml', 7764 moduleName: CORE 7765}; 7766Identifiers.trustConstantResourceUrl = { 7767 name: 'ɵɵtrustConstantResourceUrl', 7768 moduleName: CORE 7769}; 7770Identifiers.validateIframeAttribute = { 7771 name: 'ɵɵvalidateIframeAttribute', 7772 moduleName: CORE 7773}; 7774/** 7775 * @license 7776 * Copyright Google LLC All Rights Reserved. 7777 * 7778 * Use of this source code is governed by an MIT-style license that can be 7779 * found in the LICENSE file at https://angular.io/license 7780 */ 7781// https://docs.google.com/document/d/1U1RGAehQwRypUTovF1KRlpiOFze0b-_2gc6fAH0KY0k/edit 7782 7783const VERSION$1 = 3; 7784const JS_B64_PREFIX = '# sourceMappingURL=data:application/json;base64,'; 7785 7786class SourceMapGenerator { 7787 constructor(file = null) { 7788 this.file = file; 7789 this.sourcesContent = new Map(); 7790 this.lines = []; 7791 this.lastCol0 = 0; 7792 this.hasMappings = false; 7793 } // The content is `null` when the content is expected to be loaded using the URL 7794 7795 7796 addSource(url, content = null) { 7797 if (!this.sourcesContent.has(url)) { 7798 this.sourcesContent.set(url, content); 7799 } 7800 7801 return this; 7802 } 7803 7804 addLine() { 7805 this.lines.push([]); 7806 this.lastCol0 = 0; 7807 return this; 7808 } 7809 7810 addMapping(col0, sourceUrl, sourceLine0, sourceCol0) { 7811 if (!this.currentLine) { 7812 throw new Error(`A line must be added before mappings can be added`); 7813 } 7814 7815 if (sourceUrl != null && !this.sourcesContent.has(sourceUrl)) { 7816 throw new Error(`Unknown source file "${sourceUrl}"`); 7817 } 7818 7819 if (col0 == null) { 7820 throw new Error(`The column in the generated code must be provided`); 7821 } 7822 7823 if (col0 < this.lastCol0) { 7824 throw new Error(`Mapping should be added in output order`); 7825 } 7826 7827 if (sourceUrl && (sourceLine0 == null || sourceCol0 == null)) { 7828 throw new Error(`The source location must be provided when a source url is provided`); 7829 } 7830 7831 this.hasMappings = true; 7832 this.lastCol0 = col0; 7833 this.currentLine.push({ 7834 col0, 7835 sourceUrl, 7836 sourceLine0, 7837 sourceCol0 7838 }); 7839 return this; 7840 } 7841 /** 7842 * @internal strip this from published d.ts files due to 7843 * https://github.com/microsoft/TypeScript/issues/36216 7844 */ 7845 7846 7847 get currentLine() { 7848 return this.lines.slice(-1)[0]; 7849 } 7850 7851 toJSON() { 7852 if (!this.hasMappings) { 7853 return null; 7854 } 7855 7856 const sourcesIndex = new Map(); 7857 const sources = []; 7858 const sourcesContent = []; 7859 Array.from(this.sourcesContent.keys()).forEach((url, i) => { 7860 sourcesIndex.set(url, i); 7861 sources.push(url); 7862 sourcesContent.push(this.sourcesContent.get(url) || null); 7863 }); 7864 let mappings = ''; 7865 let lastCol0 = 0; 7866 let lastSourceIndex = 0; 7867 let lastSourceLine0 = 0; 7868 let lastSourceCol0 = 0; 7869 this.lines.forEach(segments => { 7870 lastCol0 = 0; 7871 mappings += segments.map(segment => { 7872 // zero-based starting column of the line in the generated code 7873 let segAsStr = toBase64VLQ(segment.col0 - lastCol0); 7874 lastCol0 = segment.col0; 7875 7876 if (segment.sourceUrl != null) { 7877 // zero-based index into the âsourcesâ list 7878 segAsStr += toBase64VLQ(sourcesIndex.get(segment.sourceUrl) - lastSourceIndex); 7879 lastSourceIndex = sourcesIndex.get(segment.sourceUrl); // the zero-based starting line in the original source 7880 7881 segAsStr += toBase64VLQ(segment.sourceLine0 - lastSourceLine0); 7882 lastSourceLine0 = segment.sourceLine0; // the zero-based starting column in the original source 7883 7884 segAsStr += toBase64VLQ(segment.sourceCol0 - lastSourceCol0); 7885 lastSourceCol0 = segment.sourceCol0; 7886 } 7887 7888 return segAsStr; 7889 }).join(','); 7890 mappings += ';'; 7891 }); 7892 mappings = mappings.slice(0, -1); 7893 return { 7894 'file': this.file || '', 7895 'version': VERSION$1, 7896 'sourceRoot': '', 7897 'sources': sources, 7898 'sourcesContent': sourcesContent, 7899 'mappings': mappings 7900 }; 7901 } 7902 7903 toJsComment() { 7904 return this.hasMappings ? '//' + JS_B64_PREFIX + toBase64String(JSON.stringify(this, null, 0)) : ''; 7905 } 7906 7907} 7908 7909function toBase64String(value) { 7910 let b64 = ''; 7911 const encoded = utf8Encode(value); 7912 7913 for (let i = 0; i < encoded.length;) { 7914 const i1 = encoded[i++]; 7915 const i2 = i < encoded.length ? encoded[i++] : null; 7916 const i3 = i < encoded.length ? encoded[i++] : null; 7917 b64 += toBase64Digit(i1 >> 2); 7918 b64 += toBase64Digit((i1 & 3) << 4 | (i2 === null ? 0 : i2 >> 4)); 7919 b64 += i2 === null ? '=' : toBase64Digit((i2 & 15) << 2 | (i3 === null ? 0 : i3 >> 6)); 7920 b64 += i2 === null || i3 === null ? '=' : toBase64Digit(i3 & 63); 7921 } 7922 7923 return b64; 7924} 7925 7926function toBase64VLQ(value) { 7927 value = value < 0 ? (-value << 1) + 1 : value << 1; 7928 let out = ''; 7929 7930 do { 7931 let digit = value & 31; 7932 value = value >> 5; 7933 7934 if (value > 0) { 7935 digit = digit | 32; 7936 } 7937 7938 out += toBase64Digit(digit); 7939 } while (value > 0); 7940 7941 return out; 7942} 7943 7944const B64_DIGITS = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789
7944+/'; 7945 7946function toBase64Digit(value) { 7947 if (value < 0 || value >= 64) { 7948 throw new Error(`Can only encode value in the range [0, 63]`); 7949 } 7950 7951 return B64_DIGITS[value]; 7952} 7953/** 7954 * @license 7955 * Copyright Google LLC All Rights Reserved. 7956 * 7957 * Use of this source code is governed by an MIT-style license that can be 7958 * found in the LICENSE file at https://angular.io/license 7959 */ 7960 7961 7962const _SINGLE_QUOTE_ESCAPE_STRING_RE = /'|\\|\n|\r|\$/g; 7963const _LEGAL_IDENTIFIER_RE = /^[$A-Z_][0-9A-Z_$]*$/i; 7964const _INDENT_WITH = ' '; 7965 7966class _EmittedLine { 7967 constructor(indent) { 7968 this.indent = indent; 7969 this.partsLength = 0; 7970 this.parts = []; 7971 this.srcSpans = []; 7972 } 7973 7974} 7975 7976class EmitterVisitorContext { 7977 constructor(_indent) { 7978 this._indent = _indent; 7979 this._lines = [new _EmittedLine(_indent)]; 7980 } 7981 7982 static createRoot() { 7983 return new EmitterVisitorContext(0); 7984 } 7985 /** 7986 * @internal strip this from published d.ts files due to 7987 * https://github.com/microsoft/TypeScript/issues/36216 7988 */ 7989 7990 7991 get _currentLine() { 7992 return this._lines[this._lines.length - 1]; 7993 } 7994 7995 println(from, lastPart = '') { 7996 this.print(from || null, lastPart, true); 7997 } 7998 7999 lineIsEmpty() { 8000 return this._currentLine.parts.length === 0; 8001 } 8002 8003 lineLength() { 8004 return this._currentLine.indent * _INDENT_WITH.length + this._currentLine.partsLength; 8005 } 8006 8007 print(from, part, newLine = false) { 8008 if (part.length > 0) { 8009 this._currentLine.parts.push(part); 8010 8011 this._currentLine.partsLength += part.length; 8012 8013 this._currentLine.srcSpans.push(from && from.sourceSpan || null); 8014 } 8015 8016 if (newLine) { 8017 this._lines.push(new _EmittedLine(this._indent)); 8018 } 8019 } 8020 8021 removeEmptyLastLine() { 8022 if (this.lineIsEmpty()) { 8023 this._lines.pop(); 8024 } 8025 } 8026 8027 incIndent() { 8028 this._indent++; 8029 8030 if (this.lineIsEmpty()) { 8031 this._currentLine.indent = this._indent; 8032 } 8033 } 8034 8035 decIndent() { 8036 this._indent--; 8037 8038 if (this.lineIsEmpty()) { 8039 this._currentLine.indent = this._indent; 8040 } 8041 } 8042 8043 toSource() { 8044 return this.sourceLines.map(l => l.parts.length > 0 ? _createIndent(l.indent) + l.parts.join('') : '').join('\n'); 8045 } 8046 8047 toSourceMapGenerator(genFilePath, startsAtLine = 0) { 8048 const map = new SourceMapGenerator(genFilePath); 8049 let firstOffsetMapped = false; 8050 8051 const mapFirstOffsetIfNeeded = () => { 8052 if (!firstOffsetMapped) { 8053 // Add a single space so that tools won't try to load the file from disk. 8054 // Note: We are using virtual urls like `ng:///`, so we have to 8055 // provide a content here. 8056 map.addSource(genFilePath, ' ').addMapping(0, genFilePath, 0, 0); 8057 firstOffsetMapped = true; 8058 } 8059 }; 8060 8061 for (let i = 0; i < startsAtLine; i++) { 8062 map.addLine(); 8063 mapFirstOffsetIfNeeded(); 8064 } 8065 8066 this.sourceLines.forEach((line, lineIdx) => { 8067 map.addLine(); 8068 const spans = line.srcSpans; 8069 const parts = line.parts; 8070 let col0 = line.indent * _INDENT_WITH.length; 8071 let spanIdx = 0; // skip leading parts without source spans 8072 8073 while (spanIdx < spans.length && !spans[spanIdx]) { 8074 col0 += parts[spanIdx].length; 8075 spanIdx++; 8076 } 8077 8078 if (spanIdx < spans.length && lineIdx === 0 && col0 === 0) { 8079 firstOffsetMapped = true; 8080 } else { 8081 mapFirstOffsetIfNeeded(); 8082 } 8083 8084 while (spanIdx < spans.length) { 8085 const span = spans[spanIdx]; 8086 const source = span.start.file; 8087 const sourceLine = span.start.line; 8088 const sourceCol = span.start.col; 8089 map.addSource(source.url, source.content).addMapping(col0, source.url, sourceLine, sourceCol); 8090 col0 += parts[spanIdx].length; 8091 spanIdx++; // assign parts without span or the same span to the previous segment 8092 8093 while (spanIdx < spans.length && (span === spans[spanIdx] || !spans[spanIdx])) { 8094 col0 += parts[spanIdx].length; 8095 spanIdx++; 8096 } 8097 } 8098 }); 8099 return map; 8100 } 8101 8102 spanOf(line, column) { 8103 const emittedLine = this._lines[line]; 8104 8105 if (emittedLine) { 8106 let columnsLeft = column - _createIndent(emittedLine.indent).length; 8107 8108 for (let partIndex = 0; partIndex < emittedLine.parts.length; partIndex++) { 8109 const part = emittedLine.parts[partIndex]; 8110 8111 if (part.length > columnsLeft) { 8112 return emittedLine.srcSpans[partIndex]; 8113 } 8114 8115 columnsLeft -= part.length; 8116 } 8117 } 8118 8119 return null; 8120 } 8121 /** 8122 * @internal strip this from published d.ts files due to 8123 * https://github.com/microsoft/TypeScript/issues/36216 8124 */ 8125 8126 8127 get sourceLines() { 8128 if (this._lines.length && this._lines[this._lines.length - 1].parts.length === 0) { 8129 return this._lines.slice(0, -1); 8130 } 8131 8132 return this._lines; 8133 } 8134 8135} 8136 8137class AbstractEmitterVisitor { 8138 constructor(_escapeDollarInStrings) { 8139 this._escapeDollarInStrings = _escapeDollarInStrings; 8140 } 8141 8142 printLeadingComments(stmt, ctx) { 8143 if (stmt.leadingComments === undefined) { 8144 return; 8145 } 8146 8147 for (const comment of stmt.leadingComments) { 8148 if (comment instanceof JSDocComment) { 8149 ctx.print(stmt, `/*${comment.toString()}*/`, comment.trailingNewline); 8150 } else { 8151 if (comment.multiline) { 8152 ctx.print(stmt, `/* ${comment.text} */`, comment.trailingNewline); 8153 } else { 8154 comment.text.split('\n').forEach(line => { 8155 ctx.println(stmt, `// ${line}`); 8156 }); 8157 } 8158 } 8159 } 8160 } 8161 8162 visitExpressionStmt(stmt, ctx) { 8163 this.printLeadingComments(stmt, ctx); 8164 stmt.expr.visitExpression(this, ctx); 8165 ctx.println(stmt, ';'); 8166 return null; 8167 } 8168 8169 visitReturnStmt(stmt, ctx) { 8170 this.printLeadingComments(stmt, ctx); 8171 ctx.print(stmt, `return `); 8172 stmt.value.visitExpression(this, ctx); 8173 ctx.println(stmt, ';'); 8174 return null; 8175 } 8176 8177 visitIfStmt(stmt, ctx) { 8178 this.printLeadingComments(stmt, ctx); 8179 ctx.print(stmt, `if (`); 8180 stmt.condition.visitExpression(this, ctx); 8181 ctx.print(stmt, `) {`); 8182 const hasElseCase = stmt.falseCase != null && stmt.falseCase.length > 0; 8183 8184 if (stmt.trueCase.length <= 1 && !hasElseCase) { 8185 ctx.print(stmt, ` `);
8186 this.visitAllStatements(stmt.trueCase, ctx); 8187 ctx.removeEmptyLastLine(); 8188 ctx.print(stmt, ` `); 8189 } else { 8190 ctx.println(); 8191 ctx.incIndent(); 8192 this.visitAllStatements(stmt.trueCase, ctx); 8193 ctx.decIndent(); 8194 8195 if (hasElseCase) { 8196 ctx.println(stmt, `} else {`); 8197 ctx.incIndent(); 8198 this.visitAllStatements(stmt.falseCase, ctx); 8199 ctx.decIndent(); 8200 } 8201 } 8202 8203 ctx.println(stmt, `}`); 8204 return null; 8205 } 8206 8207 visitWriteVarExpr(expr, ctx) { 8208 const lineWasEmpty = ctx.lineIsEmpty(); 8209 8210 if (!lineWasEmpty) { 8211 ctx.print(expr, '('); 8212 } 8213 8214 ctx.print(expr, `${expr.name} = `); 8215 expr.value.visitExpression(this, ctx); 8216 8217 if (!lineWasEmpty) { 8218 ctx.print(expr, ')'); 8219 } 8220 8221 return null; 8222 } 8223 8224 visitWriteKeyExpr(expr, ctx) { 8225 const lineWasEmpty = ctx.lineIsEmpty(); 8226 8227 if (!lineWasEmpty) { 8228 ctx.print(expr, '('); 8229 } 8230 8231 expr.receiver.visitExpression(this, ctx); 8232 ctx.print(expr, `[`); 8233 expr.index.visitExpression(this, ctx); 8234 ctx.print(expr, `] = `); 8235 expr.value.visitExpression(this, ctx); 8236 8237 if (!lineWasEmpty) { 8238 ctx.print(expr, ')'); 8239 } 8240 8241 return null; 8242 } 8243 8244 visitWritePropExpr(expr, ctx) { 8245 const lineWasEmpty = ctx.lineIsEmpty(); 8246 8247 if (!lineWasEmpty) { 8248 ctx.print(expr, '('); 8249 } 8250 8251 expr.receiver.visitExpression(this, ctx); 8252 ctx.print(expr, `.${expr.name} = `); 8253 expr.value.visitExpression(this, ctx); 8254 8255 if (!lineWasEmpty) { 8256 ctx.print(expr, ')'); 8257 } 8258 8259 return null; 8260 } 8261 8262 visitInvokeFunctionExpr(expr, ctx) { 8263 expr.fn.visitExpression(this, ctx); 8264 ctx.print(expr, `(`); 8265 this.visitAllExpressions(expr.args, ctx, ','); 8266 ctx.print(expr, `)`); 8267 return null; 8268 } 8269 8270 visitTaggedTemplateExpr(expr, ctx) { 8271 expr.tag.visitExpression(this, ctx); 8272 ctx.print(expr, '`' + expr.template.elements[0].rawText); 8273 8274 for (let i = 1; i < expr.template.elements.length; i++) { 8275 ctx.print(expr, '${'); 8276 expr.template.expressions[i - 1].visitExpression(this, ctx); 8277 ctx.print(expr, `}${expr.template.elements[i].rawText}`); 8278 } 8279 8280 ctx.print(expr, '`'); 8281 return null; 8282 } 8283 8284 visitWrappedNodeExpr(ast, ctx) { 8285 throw new Error('Abstract emitter cannot visit WrappedNodeExpr.'); 8286 } 8287 8288 visitTypeofExpr(expr, ctx) { 8289 ctx.print(expr, 'typeof '); 8290 expr.expr.visitExpression(this, ctx); 8291 } 8292 8293 visitReadVarExpr(ast, ctx) { 8294 ctx.print(ast, ast.name); 8295 return null; 8296 } 8297 8298 visitInstantiateExpr(ast, ctx) { 8299 ctx.print(ast, `new `); 8300 ast.classExpr.visitExpression(this, ctx); 8301 ctx.print(ast, `(`); 8302 this.visitAllExpressions(ast.args, ctx, ','); 8303 ctx.print(ast, `)`); 8304 return null; 8305 } 8306 8307 visitLiteralExpr(ast, ctx) { 8308 const value = ast.value; 8309 8310 if (typeof value === 'string') { 8311 ctx.print(ast, escapeIdentifier(value, this._escapeDollarInStrings)); 8312 } else { 8313 ctx.print(ast, `${value}`); 8314 } 8315 8316 return null; 8317 } 8318 8319 visitLocalizedString(ast, ctx) { 8320 const head = ast.serializeI18nHead(); 8321 ctx.print(ast, '$localize `' + head.raw); 8322 8323 for (let i = 1; i < ast.messageParts.length; i++) { 8324 ctx.print(ast, '${'); 8325 ast.expressions[i - 1].visitExpression(this, ctx); 8326 ctx.print(ast, `}${ast.serializeI18nTemplatePart(i).raw}`); 8327 } 8328 8329 ctx.print(ast, '`'); 8330 return null; 8331 } 8332 8333 visitConditionalExpr(ast, ctx) { 8334 ctx.print(ast, `(`); 8335 ast.condition.visitExpression(this, ctx); 8336 ctx.print(ast, '? '); 8337 ast.trueCase.visitExpression(this, ctx); 8338 ctx.print(ast, ': '); 8339 ast.falseCase.visitExpression(this, ctx); 8340 ctx.print(ast, `)`); 8341 return null; 8342 } 8343 8344 visitNotExpr(ast, ctx) { 8345 ctx.print(ast, '!'); 8346 ast.condition.visitExpression(this, ctx); 8347 return null; 8348 } 8349 8350 visitUnaryOperatorExpr(ast, ctx) { 8351 let opStr; 8352 8353 switch (ast.operator) { 8354 case UnaryOperator.Plus: 8355 opStr = '+'; 8356 break; 8357 8358 case UnaryOperator.Minus: 8359 opStr = '-'; 8360 break; 8361 8362 default: 8363 throw new Error(`Unknown operator ${ast.operator}`); 8364 } 8365 8366 if (ast.parens) ctx.print(ast, `(`); 8367 ctx.print(ast, opStr); 8368 ast.expr.visitExpression(this, ctx); 8369 if (ast.parens) ctx.print(ast, `)`); 8370 return null; 8371 } 8372 8373 visitBinaryOperatorExpr(ast, ctx) { 8374 let opStr; 8375 8376 switch (ast.operator) { 8377 case BinaryOperator.Equals: 8378 opStr = '=='; 8379 break; 8380 8381 case BinaryOperator.Identical: 8382 opStr = '==='; 8383 break; 8384 8385 case BinaryOperator.NotEquals: 8386 opStr = '!='; 8387 break; 8388 8389 case BinaryOperator.NotIdentical: 8390 opStr = '!=='; 8391 break; 8392 8393 case BinaryOperator.And: 8394 opStr = '&&'; 8395 break; 8396 8397 case BinaryOperator.BitwiseAnd: 8398 opStr = '&'; 8399 break; 8400 8401 case BinaryOperator.Or: 8402 opStr = '||'; 8403 break; 8404 8405 case BinaryOperator.Plus: 8406 opStr = '+'; 8407 break; 8408 8409 case BinaryOperator.Minus: 8410 opStr = '-'; 8411 break; 8412 8413 case BinaryOperator.Divide: 8414 opStr = '/'; 8415 break; 8416 8417 case BinaryOperator.Multiply: 8418 opStr = '*'; 8419 break; 8420 8421 case BinaryOperator.Modulo: 8422 opStr = '%'; 8423 break; 8424 8425 case BinaryOperator.Lower: 8426 opStr = '<'; 8427 break; 8428 8429 case BinaryOperator.LowerEquals: 8430 opStr = '<='; 8431 break; 8432 8433 case BinaryOperator.Bigger: 8434 opStr = '>'; 8435 break; 8436 8437 case BinaryOperator.BiggerEquals: 8438 opStr = '>='; 8439 break; 8440 8441 case BinaryOperator.NullishCoalesce: 8442 opStr = '??'; 8443 break; 8444 8445 default: 8446 throw new Error(`Unknown operator ${ast.operator}`); 8447 } 8448 8449 if (ast.parens) ctx.print(ast, `(`); 8450 ast.lhs.visitExpression(this, ctx); 8451 ctx.print(ast, ` ${opStr} `); 8452 ast.rhs.visitExpression(this, ctx); 8453 if (ast.parens) ctx.print(ast, `)`); 8454 return null; 8455 } 8456 8457 visitReadPropExpr(ast, ctx) { 8458 ast.receiver.visitExpression(this, ctx); 8459 ctx.print(ast, `.`); 8460 ctx.print(ast, ast.name); 8461 return null; 8462 } 8463 8464 visitReadKeyExpr(ast, ctx) { 8465 ast.receiver.visitExpression(this, ctx); 8466 ctx.print(ast, `[`); 8467 ast.index.visitExpression(this, ctx); 8468 ctx.print(ast, `]`); 8469 return null; 8470 } 8471 8472 visitLiteralArrayExpr(ast, ctx) { 8473 ctx.print(ast, `[`); 8474 this.visitAllExpressions(ast.entries, ctx, ','); 8475 ctx.print(ast, `]`); 8476 return null; 8477 } 8478 8479 visitLiteralMapExpr(ast, ctx) { 8480 ctx.print(ast, `{`); 8481 this.visitAllObjects(entry => { 8482 ctx.print(ast, `${escapeIdentifier(entry.key, this._escapeDollarInStrings, entry.quoted)}:`); 8483 entry.value.visitExpression(this, ctx); 8484 }, ast.entries, ctx, ','); 8485 ctx.print(ast, `}`); 8486 return null; 8487 } 8488 8489 visitCommaExpr(ast, ctx) { 8490 ctx.print(ast, '('); 8491 this.visitAllExpressions(ast.parts, ctx, ','); 8492 ctx.print(ast, ')'); 8493 return null; 8494 } 8495 8496 visitAllExpressions(expressions, ctx, separator) { 8497 this.visitAllObjects(expr => expr.visitExpression(this, ctx), expressions, ctx, separator); 8498 } 8499 8500 visitAllObjects(handler, expressions, ctx, separator) { 8501 let incrementedIndent = false;
8502 8503 for (let i = 0; i < expressions.length; i++) { 8504 if (i > 0) { 8505 if (ctx.lineLength() > 80) { 8506 ctx.print(null, separator, true); 8507 8508 if (!incrementedIndent) { 8509 // continuation are marked with double indent. 8510 ctx.incIndent(); 8511 ctx.incIndent(); 8512 incrementedIndent = true; 8513 } 8514 } else { 8515 ctx.print(null, separator, false); 8516 } 8517 } 8518 8519 handler(expressions[i]); 8520 } 8521 8522 if (incrementedIndent) { 8523 // continuation are marked with double indent. 8524 ctx.decIndent(); 8525 ctx.decIndent(); 8526 } 8527 } 8528 8529 visitAllStatements(statements, ctx) { 8530 statements.forEach(stmt => stmt.visitStatement(this, ctx)); 8531 } 8532 8533} 8534 8535function escapeIdentifier(input, escapeDollar, alwaysQuote = true) { 8536 if (input == null) { 8537 return null; 8538 } 8539 8540 const body = input.replace(_SINGLE_QUOTE_ESCAPE_STRING_RE, (...match) => { 8541 if (match[0] == '$') { 8542 return escapeDollar ? '\\$' : '$'; 8543 } else if (match[0] == '\n') { 8544 return '\\n'; 8545 } else if (match[0] == '\r') { 8546 return '\\r'; 8547 } else { 8548 return `\\${match[0]}`; 8549 } 8550 }); 8551 const requiresQuotes = alwaysQuote || !_LEGAL_IDENTIFIER_RE.test(body); 8552 return requiresQuotes ? `'${body}'` : body; 8553} 8554 8555function _createIndent(count) { 8556 let res = ''; 8557 8558 for (let i = 0; i < count; i++) { 8559 res += _INDENT_WITH; 8560 } 8561 8562 return res; 8563} 8564/** 8565 * @license 8566 * Copyright Google LLC All Rights Reserved. 8567 * 8568 * Use of this source code is governed by an MIT-style license that can be 8569 * found in the LICENSE file at https://angular.io/license 8570 */ 8571 8572 8573function typeWithParameters(type, numParams) { 8574 if (numParams === 0) { 8575 return expressionType(type); 8576 } 8577 8578 const params = []; 8579 8580 for (let i = 0; i < numParams; i++) { 8581 params.push(DYNAMIC_TYPE); 8582 } 8583 8584 return expressionType(type, undefined, params); 8585} 8586 8587const ANIMATE_SYMBOL_PREFIX = '@'; 8588 8589function prepareSyntheticPropertyName(name) { 8590 return `${ANIMATE_SYMBOL_PREFIX}${name}`; 8591} 8592 8593function prepareSyntheticListenerName(name, phase) { 8594 return `${ANIMATE_SYMBOL_PREFIX}${name}.${phase}`; 8595} 8596 8597function getSafePropertyAccessString(accessor, name) { 8598 const escapedName = escapeIdentifier(name, false, false); 8599 return escapedName !== name ? `${accessor}[${escapedName}]` : `${accessor}.${name}`; 8600} 8601 8602function prepareSyntheticListenerFunctionName(name, phase) { 8603 return `animation_${name}_${phase}`; 8604} 8605 8606function jitOnlyGuardedExpression(expr) { 8607 return guardedExpression('ngJitMode', expr); 8608} 8609 8610function devOnlyGuardedExpression(expr) { 8611 return guardedExpression('ngDevMode', expr); 8612} 8613 8614function guardedExpression(guard, expr) { 8615 const guardExpr = new ExternalExpr({ 8616 name: guard, 8617 moduleName: null 8618 }); 8619 const guardNotDefined = new BinaryOperatorExpr(BinaryOperator.Identical, new TypeofExpr(guardExpr), literal('undefined')); 8620 const guardUndefinedOrTrue = new BinaryOperatorExpr(BinaryOperator.Or, guardNotDefined, guardExpr, 8621 /* type */ 8622 undefined, 8623 /* sourceSpan */ 8624 undefined, true); 8625 return new BinaryOperatorExpr(BinaryOperator.And, guardUndefinedOrTrue, expr); 8626} 8627 8628function wrapReference(value) { 8629 const wrapped = new WrappedNodeExpr(value); 8630 return { 8631 value: wrapped, 8632 type: wrapped 8633 }; 8634} 8635 8636function refsToArray(refs, shouldForwardDeclare) { 8637 const values = literalArr(refs.map(ref => ref.value));
8638 return shouldForwardDeclare ? fn([], [new ReturnStatement(values)]) : values; 8639} 8640 8641function createMayBeForwardRefExpression(expression, forwardRef) { 8642 return { 8643 expression, 8644 forwardRef 8645 }; 8646} 8647/** 8648 * Convert a `MaybeForwardRefExpression` to an `Expression`, possibly wrapping its expression in a 8649 * `forwardRef()` call. 8650 * 8651 * If `MaybeForwardRefExpression.forwardRef` is `ForwardRefHandling.Unwrapped` then the expression 8652 * was originally wrapped in a `forwardRef()` call to prevent the value from being eagerly evaluated 8653 * in the code. 8654 * 8655 * See `packages/compiler-cli/src/ngtsc/annotations/src/injectable.ts` and 8656 * `packages/compiler/src/jit_compiler_facade.ts` for more information. 8657 */ 8658 8659 8660function convertFromMaybeForwardRefExpression({ 8661 expression, 8662 forwardRef 8663}) { 8664 switch (forwardRef) { 8665 case 0 8666 /* ForwardRefHandling.None */ 8667 : 8668 case 1 8669 /* ForwardRefHandling.Wrapped */ 8670 : 8671 return expression; 8672 8673 case 2 8674 /* ForwardRefHandling.Unwrapped */ 8675 : 8676 return generateForwardRef(expression); 8677 } 8678} 8679/** 8680 * Generate an expression that has the given `expr` wrapped in the following form: 8681 * 8682 * ``` 8683 * forwardRef(() => expr) 8684 * ``` 8685 */ 8686 8687 8688function generateForwardRef(expr) { 8689 return importExpr(Identifiers.forwardRef).callFn([fn([], [new ReturnStatement
8689(expr)])]); 8690} 8691 8692var R3FactoryDelegateType; 8693 8694(function (R3FactoryDelegateType) { 8695 R3FactoryDelegateType[R3FactoryDelegateType["Class"] = 0] = "Class"; 8696 R3FactoryDelegateType[R3FactoryDelegateType["Function"] = 1] = "Function"; 8697})(R3FactoryDelegateType || (R3FactoryDelegateType = {})); 8698 8699var FactoryTarget$1; 8700 8701(function (FactoryTarget) { 8702 FactoryTarget[FactoryTarget["Directive"] = 0] = "Directive"; 8703 FactoryTarget[FactoryTarget["Component"] = 1] = "Component"; 8704 FactoryTarget[FactoryTarget["Injectable"] = 2] = "Injectable"; 8705 FactoryTarget[FactoryTarget["Pipe"] = 3] = "Pipe"; 8706 FactoryTarget[FactoryTarget["NgModule"] = 4] = "NgModule"; 8707})(FactoryTarget$1 || (FactoryTarget$1 = {})); 8708/** 8709 * Construct a factory function expression for the given `R3FactoryMetadata`. 8710 */ 8711 8712 8713function compileFactoryFunction(meta) { 8714 const t = variable('t'); 8715 let baseFactoryVar = null; // The type to instantiate via constructor invocation. If there is no delegated factory, meaning 8716 // this type is always created by constructor invocation, then this is the type-to-create 8717 // parameter provided by the user (t) if specified, or the current type if not. If there is a 8718 // delegated factory (which is used to create the current type) then this is only the type-to- 8719 // create parameter (t). 8720 8721 const typeForCtor = !isDelegatedFactoryMetadata(meta) ? new BinaryOperatorExpr(BinaryOperator.Or, t, meta.internalType) : t; 8722 let ctorExpr = null; 8723 8724 if (meta.deps !== null) { 8725 // There is a constructor (either explicitly or implicitly defined). 8726 if (meta.deps !== 'invalid') { 8727 ctorExpr = new InstantiateExpr(typeForCtor, injectDependencies(meta.deps, meta.target)); 8728 } 8729 } else { 8730 // There is no constructor, use the base class' factory to construct typeForCtor. 8731 baseFactoryVar = variable(`ɵ${meta.name}_BaseFactory`); 8732 ctorExpr = baseFactoryVar.callFn([typeForCtor]); 8733 } 8734 8735 const body = []; 8736 let retExpr = null; 8737 8738 function makeConditionalFactory(nonCtorExpr) { 8739 const r = variable('r'); 8740 body.push(r.set(NULL_EXPR).toDeclStmt()); 8741 const ctorStmt = ctorExpr !== null ? r.set(ctorExpr).toStmt() : importExpr(Identifiers.invalidFactory).callFn([]).toStmt(); 8742 body.push(ifStmt(t, [ctorStmt], [r.set(nonCtorExpr).toStmt()])); 8743 return r; 8744 } 8745 8746 if (isDelegatedFactoryMetadata(meta)) { 8747 // This type is created with a delegated factory. If a type parameter is not specified, call 8748 // the factory instead. 8749 const delegateArgs = injectDependencies(meta.delegateDeps, meta.target); // Either call `new delegate(...)` or `delegate(...)` depending on meta.delegateType. 8750 8751 const factoryExpr = new (meta.delegateType === R3FactoryDelegateType.Class ? InstantiateExpr : InvokeFunctionExpr)(meta.delegate, delegateArgs); 8752 retExpr = makeConditionalFactory(factoryExpr); 8753 } else if (isExpressionFactoryMetadata(meta)) { 8754 // TODO(alxhub): decide whether to lower the value here or in the caller 8755 retExpr = makeConditionalFactory(meta.expression); 8756 } else { 8757 retExpr = ctorExpr; 8758 } 8759 8760 if (retExpr === null) { 8761 // The expression cannot be formed so render an `ɵɵinvalidFactory()` call. 8762 body.push(importExpr(Identifiers.invalidFactory).callFn([]).toStmt()); 8763 } else if (baseFactoryVar !== null) { 8764 // This factory uses a base factory, so call `ɵɵgetInheritedFactory()` to compute it. 8765 const getInheritedFactoryCall = importExpr(Identifiers.getInheritedFactory).callFn([meta.internalType]); // Memoize the base factoryFn: `baseFactory || (baseFactory = ɵɵgetInheritedFactory(...))` 8766 8767 const baseFactory = new BinaryOperatorExpr(BinaryOperator.Or, baseFactoryVar, baseFactoryVar.set(getInheritedFactoryCall));
8768 body.push(new ReturnStatement(baseFactory.callFn([typeForCtor]))); 8769 } else { 8770 // This is straightforward factory, just return it. 8771 body.push(new ReturnStatement(retExpr)); 8772 } 8773 8774 let factoryFn = fn([new FnParam('t', DYNAMIC_TYPE)], body, INFERRED_TYPE, undefined, `${meta.name}_Factory`); 8775 8776 if (baseFactoryVar !== null) { 8777 // There is a base factory variable so wrap its declaration along with the factory function into 8778 // an IIFE. 8779 factoryFn = fn([], [new DeclareVarStmt(baseFactoryVar.name), new ReturnStatement(factoryFn)]).callFn([], 8780 /* sourceSpan */ 8781 undefined, 8782 /* pure */ 8783 true); 8784 } 8785 8786 return { 8787 expression: factoryFn, 8788 statements: [], 8789 type: createFactoryType(meta) 8790 }; 8791} 8792 8793function createFactoryType(meta) { 8794 const ctorDepsType = meta.deps !== null && meta.deps !== 'invalid' ? createCtorDepsType(meta.deps) : NONE_TYPE; 8795 return expressionType(importExpr(Identifiers.FactoryDeclaration, [typeWithParameters(meta.type.type, meta.typeArgumentCount), ctorDepsType])); 8796} 8797 8798function injectDependencies(deps, target) { 8799 return deps.map((dep, index) => compileInjectDependency(dep, target, index)); 8800} 8801 8802function compileInjectDependency(dep, target, index) { 8803 // Interpret the dependency according to its resolved type. 8804 if (dep.token === null) { 8805 return importExpr(Identifiers.invalidFactoryDep).callFn([literal(index)]); 8806 } else if (dep.attributeNameType === null) { 8807 // Build up the injection flags according to the metadata. 8808 const flags = 0 8809 /* InjectFlags.Default */ 8810 | (dep.self ? 2 8811 /* InjectFlags.Self */ 8812 : 0) | (dep.skipSelf ? 4 8813 /* InjectFlags.SkipSelf */ 8814 : 0) | (dep.host ? 1 8815 /* InjectFlags.Host */ 8816 : 0) | (dep.optional ? 8 8817 /* InjectFlags.Optional */ 8818 : 0) | (target === FactoryTarget$1.Pipe ? 16 8819 /* InjectFlags.ForPipe */ 8820 : 0); // If this dependency is optional or otherwise has non-default flags, then additional 8821 // parameters describing how to inject the dependency must be passed to the inject function 8822 // that's being used. 8823 8824 let flagsParam = flags !== 0 8825 /* InjectFlags.Default */ 8826 || dep.optional ? literal(flags) : null; // Build up the arguments to the injectFn call. 8827 8828 const injectArgs = [dep.token]; 8829 8830 if (flagsParam) { 8831 injectArgs.push(flagsParam); 8832 } 8833 8834 const injectFn = getInjectFn(target); 8835 return importExpr(injectFn).callFn(injectArgs); 8836 } else { 8837 // The `dep.attributeTypeName` value is defined, which indicates that this is an `@Attribute()` 8838 // type dependency. For the generated JS we still want to use the `dep.token` value in case the 8839 // name given for the attribute is not a string literal. For example given `@Attribute(foo())`, 8840 // we want to generate `ɵɵinjectAttribute(foo())`. 8841 // 8842 // The `dep.attributeTypeName` is only actually used (in `createCtorDepType()`) to generate 8843 // typings. 8844 return importExpr(Identifiers.injectAttribute).callFn([dep.token]); 8845 } 8846} 8847 8848function createCtorDepsType(deps) { 8849 let hasTypes = false; 8850 const attributeTypes = deps.map(dep => { 8851 const type = createCtorDepType(dep); 8852 8853 if (type !== null) { 8854 hasTypes = true; 8855 return type; 8856 } else { 8857 return literal(null); 8858 } 8859 }); 8860 8861 if (hasTypes) { 8862 return expressionType(literalArr(attributeTypes)); 8863 } else { 8864 return NONE_TYPE; 8865 } 8866} 8867 8868function createCtorDepType(dep) { 8869 const entries = []; 8870 8871 if (dep.attributeNameType !== null) { 8872 entries.push({ 8873 key: 'attribute', 8874 value: dep.attributeNameType, 8875 quoted: false 8876 }); 8877 } 8878 8879 if (dep.optional) { 8880 entries.push({ 8881 key: 'optional', 8882 value: literal(true), 8883 quoted: false 8884 }); 8885 } 8886 8887 if (dep.host) { 8888 entries.push({ 8889 key: 'host', 8890 value: literal(true), 8891 quoted: false 8892 }); 8893 } 8894 8895 if (dep.self) { 8896 entries.push({ 8897 key: 'self', 8898 value: literal(true), 8899 quoted: false 8900 }); 8901 } 8902 8903 if (dep.skipSelf) { 8904 entries.push({ 8905 key: 'skipSelf', 8906 value: literal(true), 8907 quoted: false 8908 }); 8909 } 8910 8911 return entries.length > 0 ? literalMap(entries) : null; 8912} 8913 8914function isDelegatedFactoryMetadata(meta) { 8915 return meta.delegateType !== undefined; 8916} 8917 8918function isExpressionFactoryMetadata(meta) { 8919 return meta.expression !== undefined; 8920} 8921 8922function getInjectFn(target) { 8923 switch (target) { 8924 case FactoryTarget$1.Component: 8925 case FactoryTarget$1.Directive: 8926 case FactoryTarget$1.Pipe: 8927 return Identifiers.directiveInject; 8928 8929 case FactoryTarget$1.NgModule: 8930 case FactoryTarget$1.Injectable: 8931 default: 8932 return Identifiers.inject; 8933 } 8934} 8935/** 8936 * @license 8937 * Copyright Google LLC All Rights Reserved. 8938 * 8939 * Use of this source code is governed by an MIT-style license that can be 8940 * found in the LICENSE file at https://angular.io/license 8941 */ 8942 8943/** 8944 * This is an R3 `Node`-like wrapper for a raw `html.Comment` node. We do not currently 8945 * require the implementation of a visitor for Comments as they are only collected at 8946 * the top-level of the R3 AST, and only if `Render3ParseOptions['collectCommentNodes']` 8947 * is true. 8948 */ 8949 8950 8951class Comment$1 { 8952 constructor(value, sourceSpan) { 8953 this.value = value; 8954 this.sourceSpan = sourceSpan; 8955 } 8956 8957 visit(_visitor) { 8958 throw new Error('visit() not implemented for Comment'); 8959 } 8960 8961} 8962 8963class Text$3 { 8964 constructor(value, sourceSpan) { 8965 this.value = value; 8966 this.sourceSpan = sourceSpan; 8967 } 8968 8969 visit(visitor) { 8970 return visitor.visitText(this); 8971 } 8972 8973} 8974 8975class BoundText { 8976 constructor(value, sourceSpan, i18n) { 8977 this.value = value; 8978 this.sourceSpan = sourceSpan; 8979 this.i18n = i18n; 8980 } 8981 8982 visit(visitor) { 8983 return visitor.visitBoundText(this); 8984 } 8985 8986} 8987/** 8988 * Represents a text attribute in the template. 8989 * 8990 * `valueSpan` may not be present in cases where there is no value `<div a></div>`. 8991 * `keySpan` may also not be present for synthetic attributes from ICU expansions. 8992 */ 8993 8994 8995class TextAttribute { 8996 constructor(name, value, sourceSpan, keySpan, valueSpan, i18n) { 8997 this.name = name; 8998 this.value = value; 8999 this.sourceSpan = sourceSpan; 9000 this.keySpan = keySpan; 9001 this.valueSpan = valueSpan; 9002 this.i18n = i18n; 9003 } 9004 9005 visit(visitor) { 9006 return visitor.visitTextAttribute(this); 9007 } 9008 9009} 9010 9011class BoundAttribute { 9012 constructor(name, type, securityContext, value, unit, sourceSpan, keySpan, valueSpan, i18n) { 9013 this.name = name; 9014 this.type = type; 9015 this.securityContext = securityContext; 9016 this.value = value; 9017 this.unit = unit; 9018 this.sourceSpan = sourceSpan; 9019 this.keySpan = keySpan; 9020 this.valueSpan = valueSpan; 9021 this.i18n = i18n; 9022 } 9023 9024 static fromBoundElementProperty(prop, i18n) {
9025 if (prop.keySpan === undefined) { 9026 throw new Error(`Unexpected state: keySpan must be defined for bound attributes but was not for ${prop.name}: ${prop.sourceSpan}`); 9027 } 9028 9029 return new BoundAttribute(prop.name, prop.type, prop.securityContext, prop.value, prop.unit, prop.sourceSpan, prop.keySpan, prop.valueSpan, i18n); 9030 } 9031 9032 visit(visitor) { 9033 return visitor.visitBoundAttribute(this); 9034 } 9035 9036} 9037 9038class BoundEvent { 9039 constructor(name, type, handler, target, phase, sourceSpan, handlerSpan, keySpan) { 9040 this.name = name; 9041 this.type = type; 9042 this.handler = handler; 9043 this.target = target; 9044 this.phase = phase; 9045 this.sourceSpan = sourceSpan; 9046 this.handlerSpan = handlerSpan; 9047 this.keySpan = keySpan; 9048 } 9049 9050 static fromParsedEvent(event) { 9051 const target = event.type === 0 9052 /* ParsedEventType.Regular */ 9053 ? event.targetOrPhase : null; 9054 const phase = event.type === 1 9055 /* ParsedEventType.Animation */ 9056 ? event.targetOrPhase : null; 9057 9058 if (event.keySpan === undefined) { 9059 throw new Error(`Unexpected state: keySpan must be defined for bound event but was not for ${event.name}: ${event.sourceSpan}`); 9060 } 9061 9062 return new BoundEvent(event.name, event.type, event.handler, target, phase, event.sourceSpan, event.handlerSpan, event.keySpan); 9063 } 9064 9065 visit(visitor) { 9066 return visitor.visitBoundEvent(this); 9067 } 9068 9069} 9070 9071class Element$1 { 9072 constructor(name, attributes, inputs, outputs, children, references, sourceSpan, startSourceSpan, endSourceSpan, i18n) { 9073 this.name = name; 9074 this.attributes = attributes; 9075 this.inputs = inputs; 9076 this.outputs = outputs; 9077 this.children = children; 9078 this.references = references; 9079 this.sourceSpan = sourceSpan; 9080 this.startSourceSpan = startSourceSpan; 9081 this.endSourceSpan = endSourceSpan; 9082 this.i18n = i18n; 9083 } 9084 9085 visit(visitor) { 9086 return visitor.visitElement(this); 9087 } 9088 9089} 9090 9091class Template { 9092 constructor( // tagName is the name of the container element, if applicable. 9093 // `null` is a special case for when there is a structural directive on an `ng-template` so 9094 // the renderer can differentiate between the synthetic template and the one written in the 9095 // file. 9096 tagName, attributes, inputs, outputs, templateAttrs, children, references, variables, sourceSpan, startSourceSpan, endSourceSpan, i18n) { 9097 this.tagName = tagName; 9098 this.attributes = attributes; 9099 this.inputs = inputs; 9100 this.outputs = outputs; 9101 this.templateAttrs = templateAttrs; 9102 this.children = children; 9103 this.references = references; 9104 this.variables = variables; 9105 this.sourceSpan = sourceSpan; 9106 this.startSourceSpan = startSourceSpan; 9107 this.endSourceSpan = endSourceSpan; 9108 this.i18n = i18n; 9109 } 9110 9111 visit(visitor) { 9112 return visitor.visitTemplate(this); 9113 } 9114 9115} 9116 9117class Content { 9118 constructor(selector, attributes, sourceSpan, i18n) { 9119 this.selector = selector; 9120 this.attributes = attributes; 9121 this.sourceSpan = sourceSpan; 9122 this.i18n = i18n; 9123 this.name = 'ng-content'; 9124 } 9125 9126 visit(visitor) { 9127 return visitor.visitContent(this); 9128 } 9129 9130} 9131 9132class Variable { 9133 constructor(name, value, sourceSpan, keySpan, valueSpan) { 9134 this.name = name; 9135 this.value = value; 9136 this.sourceSpan = sourceSpan; 9137 this.keySpan = keySpan; 9138 this.valueSpan = valueSpan; 9139 } 9140 9141 visit(visitor) { 9142 return visitor.visitVariable(this); 9143 } 9144 9145} 9146 9147class Reference { 9148 constructor(name, value, sourceSpan, keySpan, valueSpan) { 9149 this.name = name; 9150 this.value = value; 9151 this.sourceSpan = sourceSpan; 9152 this.keySpan = keySpan; 9153 this.valueSpan = valueSpan; 9154 } 9155 9156 visit(visitor) { 9157 return visitor.visitReference(this); 9158 } 9159 9160} 9161 9162class Icu$1 { 9163 constructor(vars, placeholders, sourceSpan, i18n) { 9164 this.vars = vars; 9165 this.placeholders = placeholders; 9166 this.sourceSpan = sourceSpan; 9167 this.i18n = i18n; 9168 } 9169 9170 visit(visitor) { 9171 return visitor.visitIcu(this); 9172 } 9173 9174} 9175 9176class NullVisitor { 9177 visitElement(element) {} 9178 9179 visitTemplate(template) {} 9180 9181 visitContent(content) {} 9182 9183 visitVariable(variable) {} 9184 9185 visitReference(reference) {} 9186 9187 visitTextAttribute(attribute) {} 9188 9189 visitBoundAttribute(attribute) {} 9190 9191 visitBoundEvent(attribute) {} 9192 9193 visitText(text) {} 9194 9195 visitBoundText(text) {} 9196 9197 visitIcu(icu) {} 9198 9199} 9200 9201class RecursiveVisitor$1 { 9202 visitElement(element) { 9203 visitAll$1(this, element.attributes); 9204 visitAll$1(this, element.inputs); 9205 visitAll$1(this, element.outputs); 9206 visitAll$1(this, element.children); 9207 visitAll$1(this, element.references); 9208 } 9209 9210 visitTemplate(template) { 9211 visitAll$1(this, template.attributes); 9212 visitAll$1(this, template.inputs); 9213 visitAll$1(this, template.outputs); 9214 visitAll$1(this, template.children); 9215 visitAll$1(this, template.references); 9216 visitAll$1(this, template.variables); 9217 } 9218 9219 visitContent(content) {} 9220 9221 visitVariable(variable) {} 9222 9223 visitReference(reference) {} 9224 9225 visitTextAttribute(attribute) {} 9226 9227 visitBoundAttribute(attribute) {} 9228 9229 visitBoundEvent(attribute) {} 9230 9231 visitText(text) {} 9232 9233 visitBoundText(text) {} 9234 9235 visitIcu(icu) {} 9236 9237} 9238 9239class TransformVisitor { 9240 visitElement(element) { 9241 const newAttributes = transformAll(this, element.attributes);
9242 const newInputs = transformAll(this, element.inputs); 9243 const newOutputs = transformAll(this, element.outputs); 9244 const newChildren = transformAll(this, element.children); 9245 const newReferences = transformAll(this, element.references); 9246 9247 if (newAttributes != element.attributes || newInputs != element.inputs || newOutputs != element.outputs || newChildren != element.children || newReferences != element.references) { 9248 return new Element$1(element.name, newAttributes, newInputs, newOutputs, newChildren, newReferences, element.sourceSpan, element.startSourceSpan, element.endSourceSpan); 9249 } 9250 9251 return element; 9252 } 9253 9254 visitTemplate(template) { 9255 const newAttributes = transformAll(this, template.attributes); 9256 const newInputs = transformAll(this, template.inputs); 9257 const newOutputs = transformAll(this, template.outputs); 9258 const newTemplateAttrs = transformAll(this, template.templateAttrs); 9259 const newChildren = transformAll(this, template.children); 9260 const newReferences = transformAll(this, template.references); 9261 const newVariables = transformAll(this, template.variables); 9262 9263 if (newAttributes != template.attributes || newInputs != template.inputs || newOutputs != template.outputs || newTemplateAttrs != template.templateAttrs || newChildren != template.children || newReferences != template.references || newVariables != template.variables) { 9264 return new Template(template.tagName, newAttributes, newInputs, newOutputs, newTemplateAttrs, newChildren, newReferences, newVariables, template.sourceSpan, template.startSourceSpan, template.endSourceSpan); 9265 } 9266 9267 return template; 9268 } 9269 9270 visitContent(content) { 9271 return content; 9272 } 9273 9274 visitVariable(variable) { 9275 return variable; 9276 } 9277 9278 visitReference(reference) { 9279 return reference; 9280 } 9281 9282 visitTextAttribute(attribute) { 9283 return attribute; 9284 } 9285 9286 visitBoundAttribute(attribute) { 9287 return attribute; 9288 } 9289 9290 visitBoundEvent(attribute) { 9291 return attribute; 9292 } 9293 9294 visitText(text) { 9295 return text; 9296 } 9297 9298 visitBoundText(text) { 9299 return text; 9300 } 9301 9302 visitIcu(icu) { 9303 return icu; 9304 } 9305 9306} 9307 9308function visitAll$1(visitor, nodes) { 9309 const result = []; 9310 9311 if (visitor.visit) { 9312 for (const node of nodes) { 9313 const newNode = visitor.visit(node) || node.visit(visitor); 9314 } 9315 } else { 9316 for (const node of nodes) { 9317 const newNode = node.visit(visitor); 9318 9319 if (newNode) { 9320 result.push(newNode); 9321 } 9322 } 9323 } 9324 9325 return result; 9326} 9327 9328function transformAll(visitor, nodes) { 9329 const result = []; 9330 let changed = false; 9331 9332 for (const node of nodes) { 9333 const newNode = node.visit(visitor); 9334 9335 if (newNode) { 9336 result.push(newNode); 9337 } 9338 9339 changed = changed || newNode != node; 9340 } 9341 9342 return changed ? result : nodes; 9343} 9344/** 9345 * @license 9346 * Copyright Google LLC All Rights Reserved. 9347 * 9348 * Use of this source code is governed by an MIT-style license that can be 9349 * found in the LICENSE file at https://angular.io/license 9350 */ 9351 9352 9353class Message { 9354 /** 9355 * @param nodes message AST 9356 * @param placeholders maps placeholder names to static content and their source spans 9357 * @param placeholderToMessage maps placeholder names to messages (used for nested ICU messages) 9358 * @param meaning 9359 * @param description 9360 * @param customId 9361 */ 9362 constructor(nodes, placeholders, placeholderToMessage, meaning, description, customId) { 9363 this.nodes = nodes; 9364 this.placeholders = placeholders; 9365 this.placeholderToMessage = placeholderToMessage; 9366 this.meaning = meaning; 9367 this.description = description; 9368 this.customId = customId; 9369 this.id = this.customId; 9370 /** The ids to use if there are no custom id and if `i18nLegacyMessageIdFormat` is not empty */ 9371 9372 this.legacyIds = []; 9373 this.messageString = serializeMessage(this.nodes); 9374 9375 if (nodes.length) { 9376 this.sources = [{ 9377 filePath: nodes[0].sourceSpan.start.file.url, 9378 startLine: nodes[0].sourceSpan.start.line + 1, 9379 startCol: nodes[0].sourceSpan.start.col + 1, 9380 endLine: nodes[nodes.length - 1].sourceSpan.end.line + 1, 9381 endCol: nodes[0].sourceSpan.start.col + 1 9382 }]; 9383 } else { 9384 this.sources = []; 9385 } 9386 } 9387 9388} 9389 9390class Text$2 { 9391 constructor(value, sourceSpan) { 9392 this.value = value; 9393 this.sourceSpan = sourceSpan; 9394 } 9395 9396 visit(visitor, context) { 9397 return visitor.visitText(this, context); 9398 } 9399 9400} // TODO(vicb): do we really need this node (vs an array) ? 9401 9402 9403class Container { 9404 constructor(children, sourceSpan) { 9405 this.children = children; 9406 this.sourceSpan = sourceSpan; 9407 } 9408 9409 visit(visitor, context) { 9410 return visitor.visitContainer(this, context); 9411 } 9412 9413} 9414 9415class Icu { 9416 constructor(expression, type, cases, sourceSpan) { 9417 this.expression = expression; 9418 this.type = type; 9419 this.cases = cases; 9420 this.sourceSpan = sourceSpan; 9421 } 9422 9423 visit(visitor, context) { 9424 return visitor.visitIcu(this, context); 9425 } 9426 9427} 9428 9429class TagPlaceholder { 9430 constructor(tag, attrs, startName, closeName, children, isVoid, // TODO sourceSpan should cover all (we need a startSourceSpan and endSourceSpan) 9431 sourceSpan, startSourceSpan, endSourceSpan) { 9432 this.tag = tag; 9433 this.attrs = attrs; 9434 this.startName = startName; 9435 this.closeName = closeName; 9436 this.children = children; 9437 this.isVoid = isVoid; 9438 this.sourceSpan = sourceSpan; 9439 this.startSourceSpan = startSourceSpan; 9440 this.endSourceSpan = endSourceSpan; 9441 } 9442 9443 visit(visitor, context) { 9444 return visitor.visitTagPlaceholder(this, context); 9445 } 9446 9447} 9448 9449class Placeholder { 9450 constructor(value, name, sourceSpan) { 9451 this.value = value; 9452 this.name = name; 9453 this.sourceSpan = sourceSpan; 9454 } 9455 9456 visit(visitor, context) { 9457 return visitor.visitPlaceholder(this, context); 9458 } 9459 9460} 9461 9462class IcuPlaceholder { 9463 constructor(value, name, sourceSpan) { 9464 this.value = value; 9465 this.name = name; 9466 this.sourceSpan = sourceSpan; 9467 } 9468 9469 visit(visitor, context) { 9470 return visitor.visitIcuPlaceholder(this, context); 9471 } 9472 9473} // Clone the AST 9474 9475 9476class CloneVisitor { 9477 visitText(text, context) { 9478 return new Text$2(text.value, text.sourceSpan); 9479 } 9480 9481 visitContainer(container, context) { 9482 const children = container.children.map(n => n.visit(this, context)); 9483 return new Container(children, container.sourceSpan); 9484 } 9485 9486 visitIcu(icu, context) { 9487 const cases = {};
9488 Object.keys(icu.cases).forEach(key => cases[key] = icu.cases[key].visit(this, context)); 9489 const msg = new Icu(icu.expression, icu.type, cases, icu.sourceSpan); 9490 msg.expressionPlaceholder = icu.expressionPlaceholder; 9491 return msg; 9492 } 9493 9494 visitTagPlaceholder(ph, context) { 9495 const children = ph.children.map(n => n.visit(this, context)); 9496 return new TagPlaceholder(ph.tag, ph.attrs, ph.startName, ph.closeName, children, ph.isVoid, ph.sourceSpan, ph.startSourceSpan, ph.endSourceSpan); 9497 } 9498 9499 visitPlaceholder(ph, context) { 9500 return new Placeholder(ph.value, ph.name, ph.sourceSpan); 9501 } 9502 9503 visitIcuPlaceholder(ph, context) { 9504 return new IcuPlaceholder(ph.value, ph.name, ph.sourceSpan); 9505 } 9506 9507} // Visit all the nodes recursively 9508 9509 9510class RecurseVisitor { 9511 visitText(text, context) {} 9512 9513 visitContainer(container, context) { 9514 container.children.forEach(child => child.visit(this)); 9515 } 9516 9517 visitIcu(icu, context) { 9518 Object.keys(icu.cases).forEach(k => { 9519 icu.cases[k].visit(this); 9520 }); 9521 } 9522 9523 visitTagPlaceholder(ph, context) { 9524 ph.children.forEach(child => child.visit(this)); 9525 } 9526 9527 visitPlaceholder(ph, context) {} 9528 9529 visitIcuPlaceholder(ph, context) {} 9530 9531} 9532/** 9533 * Serialize the message to the Localize backtick string format that would appear in compiled code. 9534 */ 9535 9536 9537function serializeMessage(messageNodes) { 9538 const visitor = new LocalizeMessageStringVisitor(); 9539 const str = messageNodes.map(n => n.visit(visitor)).join(''); 9540 return str; 9541} 9542 9543class LocalizeMessageStringVisitor { 9544 visitText(text) { 9545 return text.value; 9546 } 9547 9548 visitContainer(container) { 9549 return container.children.map(child => child.visit(this)).join(''); 9550 } 9551 9552 visitIcu(icu) { 9553 const strCases = Object.keys(icu.cases).map(k => `${k} {${icu.cases[k].visit(this)}}`); 9554 return `{${icu.expressionPlaceholder}, ${icu.type}, ${strCases.join(' ')}}`; 9555 } 9556 9557 visitTagPlaceholder(ph) { 9558 const children = ph.children.map(child => child.visit(this)).join(''); 9559 return `{$${ph.startName}}${children}{$${ph.closeName}}`; 9560 } 9561 9562 visitPlaceholder(ph) { 9563 return `{$${ph.name}}`; 9564 } 9565 9566 visitIcuPlaceholder(ph) { 9567 return `{$${ph.name}}`; 9568 } 9569 9570} 9571/** 9572 * @license 9573 * Copyright Google LLC All Rights Reserved. 9574 * 9575 * Use of this source code is governed by an MIT-style license that can be 9576 * found in the LICENSE file at https://angular.io/license 9577 */ 9578 9579 9580class Serializer { 9581 // Creates a name mapper, see `PlaceholderMapper` 9582 // Returning `null` means that no name mapping is used. 9583 createNameMapper(message) { 9584 return null; 9585 } 9586 9587} 9588/** 9589 * A simple mapper that take a function to transform an internal name to a public name 9590 */ 9591 9592 9593class SimplePlaceholderMapper extends RecurseVisitor { 9594 // create a mapping from the message 9595 constructor(message, mapName) { 9596 super(); 9597 this.mapName = mapName; 9598 this.internalToPublic = {}; 9599 this.publicToNextId = {}; 9600 this.publicToInternal = {}; 9601 message.nodes.forEach(node => node.visit(this)); 9602 } 9603 9604 toPublicName(internalName) { 9605 return this.internalToPublic.hasOwnProperty(internalName) ? this.internalToPublic[internalName] : null; 9606 } 9607 9608 toInternalName(publicName) { 9609 return this.publicToInternal.hasOwnProperty(publicName) ? this.publicToInternal[publicName] : null; 9610 } 9611 9612 visitText(text, context) { 9613 return null; 9614 } 9615 9616 visitTagPlaceholder(ph, context) { 9617 this.visitPlaceholderName(ph.startName); 9618 super.visitTagPlaceholder(ph, context); 9619 this.visitPlaceholderName(ph.closeName); 9620 } 9621 9622 visitPlaceholder(ph, context) { 9623 this.visitPlaceholderName(ph.name); 9624 } 9625 9626 visitIcuPlaceholder(ph, context) { 9627 this.visitPlaceholderName(ph.name); 9628 } // XMB placeholders could only contains A-Z, 0-9 and _ 9629 9630 9631 visitPlaceholderName(internalName) { 9632 if (!internalName || this.internalToPublic.hasOwnProperty(internalName)) { 9633 return; 9634 } 9635 9636 let publicName = this.mapName(internalName); 9637 9638 if (this.publicToInternal.hasOwnProperty(publicName)) { 9639 // Create a new XMB when it has already been used 9640 const nextId = this.publicToNextId[publicName]; 9641 this.publicToNextId[publicName] = nextId + 1; 9642 publicName = `${publicName}_${nextId}`; 9643 } else { 9644 this.publicToNextId[publicName] = 1; 9645 } 9646 9647 this.internalToPublic[internalName] = publicName; 9648 this.publicToInternal[publicName] = internalName; 9649 } 9650 9651} 9652/** 9653 * @license 9654 * Copyright Google LLC All Rights Reserved. 9655 * 9656 * Use of this source code is governed by an MIT-style license that can be 9657 * found in the LICENSE file at https://angular.io/license 9658 */ 9659 9660 9661class _Visitor$2 { 9662 visitTag(tag) { 9663 const strAttrs = this._serializeAttributes(tag.attrs); 9664 9665 if (tag.children.length == 0) { 9666 return `<${tag.name}${strAttrs}/>`; 9667 } 9668 9669 const strChildren = tag.children.map(node =>
9669 node.visit(this)); 9670 return `<${tag.name}${strAttrs}>${strChildren.join('')}</${tag.name}>`; 9671 } 9672 9673 visitText(text) { 9674 return text.value; 9675 } 9676 9677 visitDeclaration(decl) { 9678 return `<?xml${this._serializeAttributes(decl.attrs)} ?>`; 9679 } 9680 9681 _serializeAttributes(attrs) { 9682 const strAttrs = Object.keys(attrs).map(name => `${name}="${attrs[name]}"`).join(' '); 9683 return strAttrs.length > 0 ? ' ' + strAttrs : ''; 9684 } 9685 9686 visitDoctype(doctype) { 9687 return `<!DOCTYPE ${doctype.rootTag} [\n${doctype.dtd}\n]>`; 9688 } 9689 9690} 9691 9692const _visitor = new _Visitor$2(); 9693 9694function serialize(nodes) { 9695 return nodes.map(node => node.visit(_visitor)).join(''); 9696} 9697 9698class Declaration { 9699 constructor(unescapedAttrs) { 9700 this.attrs = {}; 9701 Object.keys(unescapedAttrs).forEach(k => { 9702 this.attrs[k] = escapeXml(unescapedAttrs[k]); 9703 }); 9704 } 9705 9706 visit(visitor) { 9707 return visitor.visitDeclaration(this); 9708 } 9709 9710} 9711 9712class Doctype { 9713 constructor(rootTag, dtd) { 9714 this.rootTag = rootTag; 9715 this.dtd = dtd; 9716 } 9717 9718 visit(visitor) { 9719 return visitor.visitDoctype(this); 9720 } 9721 9722} 9723 9724class Tag { 9725 constructor(name, unescapedAttrs = {}, children = []) { 9726 this.name = name; 9727 this.children = children; 9728 this.attrs = {}; 9729 Object.keys(unescapedAttrs).forEach(k => { 9730 this.attrs[k] = escapeXml(unescapedAttrs[k]); 9731 }); 9732 } 9733 9734 visit(visitor) { 9735 return visitor.visitTag(this); 9736 } 9737 9738} 9739 9740class Text$1 { 9741 constructor(unescapedValue) { 9742 this.value = escapeXml(unescapedValue); 9743 } 9744 9745 visit(visitor) { 9746 return visitor.visitText(this); 9747 } 9748 9749} 9750 9751class CR extends Text$1 { 9752 constructor(ws = 0) { 9753 super(`\n${new Array(ws + 1).join(' ')}`); 9754 } 9755 9756} 9757 9758const _ESCAPED_CHARS = [[/&/g, '&'], [/"/g, '"'], [/'/g, '''], [/</g, '<'], [/>/g, '>']]; // Escape `_ESCAPED_CHARS` characters in the given text with encoded entities 9759 9760function escapeXml(text) { 9761 return _ESCAPED_CHARS.reduce((text, entry) => text.replace(entry[0], entry[1]), text); 9762} 9763/** 9764 * @license 9765 * Copyright Google LLC All Rights Reserved. 9766 * 9767 * Use of this source code is governed by an MIT-style license that can be 9768 * found in the LICENSE file at https://angular.io/license 9769 */ 9770 9771 9772const _MESSAGES_TAG = 'messagebundle'; 9773const _MESSAGE_TAG = 'msg'; 9774const _PLACEHOLDER_TAG$3 = 'ph'; 9775const _EXAMPLE_TAG = 'ex'; 9776const _SOURCE_TAG$2 = 'source'; 9777const _DOCTYPE = `<!ELEMENT messagebundle (msg)*> 9778<!ATTLIST messagebundle class CDATA #IMPLIED> 9779 9780<!ELEMENT msg (#PCDATA|ph|source)*> 9781<!ATTLIST msg id CDATA #IMPLIED> 9782<!ATTLIST msg seq CDATA #IMPLIED> 9783<!ATTLIST msg name CDATA #IMPLIED> 9784<!ATTLIST msg desc CDATA #IMPLIED> 9785<!ATTLIST msg meaning CDATA #IMPLIED> 9786<!ATTLIST msg obsolete (obsolete) #IMPLIED> 9787<!ATTLIST msg xml:space (default|preserve) "default"> 9788<!ATTLIST msg is_hidden CDATA #IMPLIED> 9789 9790<!ELEMENT source (#PCDATA)> 9791 9792<!ELEMENT ph (#PCDATA|ex)*> 9793<!ATTLIST ph name CDATA #REQUIRED> 9794 9795<!ELEMENT ex (#PCDATA)>`; 9796 9797class Xmb extends Serializer { 9798 write(messages, locale) { 9799 const exampleVisitor = new ExampleVisitor(); 9800 const visitor = new _Visitor$1(); 9801 let rootNode = new Tag(_MESSAGES_TAG); 9802 messages.forEach(message => { 9803 const attrs = { 9804 id: message.id 9805 }; 9806 9807 if (message.description) { 9808 attrs['desc'] = message.description; 9809 } 9810 9811 if (message.meaning) { 9812 attrs['meaning'] = message.meaning; 9813 } 9814 9815 let sourceTags = []; 9816 message.sources.forEach(source => { 9817 sourceTags.push(new Tag(_SOURCE_TAG$2, {}, [new Text$1(`${source.filePath}:${source.startLine}${source.endLine !== source.startLine ? ',' + source.endLine : ''}`)])); 9818 }); 9819 rootNode.children.push(new CR(2), new Tag(_MESSAGE_TAG, attrs, [...sourceTags, ...visitor.serialize(message.nodes)])); 9820 }); 9821 rootNode.children.push(new CR()); 9822 return serialize([new Declaration({ 9823 version: '1.0', 9824 encoding: 'UTF-8' 9825 }), new CR(), new Doctype(_MESSAGES_TAG, _DOCTYPE), new CR(), exampleVisitor.addDefaultExamples(rootNode), new CR()]); 9826 } 9827 9828 load(content, url) { 9829 throw new Error('Unsupported'); 9830 } 9831 9832 digest(message) { 9833 return digest(message); 9834 } 9835 9836 createNameMapper(message) { 9837 return new SimplePlaceholderMapper(message, toPublicName); 9838 } 9839 9840} 9841 9842class _Visitor$1 { 9843 visitText(text, context) { 9844 return [new Text$1(text.value)]; 9845 } 9846 9847 visitContainer(container, context) { 9848 const nodes = [];
9849 container.children.forEach(node => nodes.push(...node.visit(this))); 9850 return nodes; 9851 } 9852 9853 visitIcu(icu, context) { 9854 const nodes = [new Text$1(`{${icu.expressionPlaceholder}, ${icu.type}, `)]; 9855 Object.keys(icu.cases).forEach(c => { 9856 nodes.push(new Text$1(`${c} {`), ...icu.cases[c].visit(this), new Text$1(`} `)); 9857 }); 9858 nodes.push(new Text$1(`}`)); 9859 return nodes; 9860 } 9861 9862 visitTagPlaceholder(ph, context) { 9863 const startTagAsText = new Text$1(`<${ph.tag}>`); 9864 const startEx = new Tag(_EXAMPLE_TAG, {}, [startTagAsText]); // TC requires PH to have a non empty EX, and uses the text node to show the "original" value. 9865 9866 const startTagPh = new Tag(_PLACEHOLDER_TAG$3, { 9867 name: ph.startName 9868 }, [startEx, startTagAsText]); 9869 9870 if (ph.isVoid) { 9871 // void tags have no children nor closing tags 9872 return [startTagPh]; 9873 } 9874 9875 const closeTagAsText = new Text$1(`</${ph.tag}>`); 9876 const closeEx = new Tag(_EXAMPLE_TAG, {}, [closeTagAsText]); // TC requires PH to have a non empty EX, and uses the text node to show the "original" value. 9877 9878 const closeTagPh = new Tag(_PLACEHOLDER_TAG$3, { 9879 name: ph.closeName 9880 }, [closeEx, closeTagAsText]); 9881 return [startTagPh, ...this.serialize(ph.children), closeTagPh]; 9882 } 9883 9884 visitPlaceholder(ph, context) { 9885 const interpolationAsText = new Text$1(`{{${ph.value}}}`); // Example tag needs to be not-empty for TC. 9886 9887 const exTag = new Tag(_EXAMPLE_TAG, {}, [interpolationAsText]); 9888 return [// TC requires PH to have a non empty EX, and uses the text node to show the "original" value. 9889 new Tag(_PLACEHOLDER_TAG$3, { 9890 name: ph.name 9891 }, [exTag, interpolationAsText])]; 9892 } 9893 9894 visitIcuPlaceholder(ph, context) { 9895 const icuExpression = ph.value.expression; 9896 const icuType = ph.value.type; 9897 const icuCases = Object.keys(ph.value.cases).map(value => value + ' {...}').join(' '); 9898 const icuAsText = new Text$1(`{${icuExpression}, ${icuType}, ${icuCases}}`); 9899 const exTag = new Tag(_EXAMPLE_TAG, {}, [icuAsText]); 9900 return [// TC requires PH to have a non empty EX, and uses the text node to show the "original" value. 9901 new Tag(_PLACEHOLDER_TAG$3, { 9902 name: ph.name 9903 }, [exTag, icuAsText])]; 9904 } 9905 9906 serialize(nodes) { 9907 return [].concat(...nodes.map(node => node.visit(this))); 9908 } 9909 9910} 9911 9912function digest(message) { 9913 return decimalDigest(message); 9914} // TC requires at least one non-empty example on placeholders 9915 9916 9917class ExampleVisitor { 9918 addDefaultExamples(node) { 9919 node.visit(this); 9920 return node; 9921 } 9922 9923 visitTag(tag) { 9924 if (tag.name === _PLACEHOLDER_TAG$3) { 9925 if (!tag.children || tag.children.length == 0) { 9926 const exText = new Text$1(tag.attrs['name'] || '...'); 9927 tag.children = [new Tag(_EXAMPLE_TAG, {}, [exText])]; 9928 } 9929 } else if (tag.children) { 9930 tag.children.forEach(node => node.visit(this)); 9931 } 9932 } 9933 9934 visitText(text) {} 9935 9936 visitDeclaration(decl) {} 9937 9938 visitDoctype(doctype) {} 9939 9940} // XMB/XTB placeholders can only contain A-Z, 0-9 and _ 9941 9942 9943function toPublicName(internalName) { 9944 return internalName.toUpperCase().replace(/[^A-Z0-9_]/g, '_'); 9945} 9946/** 9947 * @license 9948 * Copyright Google LLC All Rights Reserved. 9949 * 9950 * Use of this source code is governed by an MIT-style license that can be 9951 * found in the LICENSE file at https://angular.io/license 9952 */ 9953 9954/* Closure variables holding messages must be named `MSG_[A-Z0-9]+` */ 9955 9956 9957const CLOSURE_TRANSLATION_VAR_PREFIX = 'MSG_'; 9958/** 9959 * Prefix for non-`goog.getMsg` i18n-related vars. 9960 * Note: the prefix uses lowercase characters intentionally due to a Closure behavior that 9961 * considers variables like `I18N_0` as constants and throws an error when their value changes. 9962 */ 9963 9964const TRANSLATION_VAR_PREFIX = 'i18n_'; 9965/** Name of the i18n attributes **/ 9966 9967const I18N_ATTR = 'i18n'; 9968const I18N_ATTR_PREFIX = 'i18n-'; 9969/** Prefix of var expressions used in ICUs */ 9970 9971const I18N_ICU_VAR_PREFIX = 'VAR_'; 9972/** Prefix of ICU expressions for post processing */ 9973 9974const I18N_ICU_MAPPING_PREFIX = 'I18N_EXP_'; 9975/** Placeholder wrapper for i18n expressions **/ 9976 9977const I18N_PLACEHOLDER_SYMBOL = '�'; 9978 9979function isI18nAttribute(name) { 9980 return name === I18N_ATTR || name.startsWith(I18N_ATTR_PREFIX); 9981} 9982 9983function isI18nRootNode(meta) { 9984 return meta instanceof Message; 9985} 9986 9987function isSingleI18nIcu(meta) { 9988 return isI18nRootNode(meta) && meta.nodes.length === 1 && meta.nodes[0] instanceof Icu; 9989} 9990 9991function hasI18nMeta(node) { 9992 return !!node.i18n; 9993} 9994 9995function hasI18nAttrs(element) { 9996 return element.attrs.some(attr => isI18nAttribute(attr.name)); 9997} 9998 9999function icuFromI18nMessage(message) { 10000 return message.nodes[0]; 10001} 10002 10003function wrapI18nPlaceholder(content, contextId = 0) { 10004 const blockId = contextId > 0 ? `:${contextId}` : ''; 10005 return `${I18N_PLACEHOLDER_SYMBOL}${content}${blockId}${I18N_PLACEHOLDER_SYMBOL}`; 10006} 10007 10008function assembleI18nBoundString(strings, bindingStartIndex = 0, contextId = 0) { 10009 if (!strings.length) return ''; 10010 let acc = ''; 10011 const lastIdx = strings.length - 1; 10012 10013 for (let i = 0; i < lastIdx; i++) { 10014 acc += `${strings[i]}${wrapI18nPlaceholder(bindingStartIndex + i, contextId)}`; 10015 } 10016 10017 acc += strings[lastIdx]; 10018 return acc; 10019} 10020 10021function getSeqNumberGenerator(startsAt = 0) { 10022 let current = startsAt; 10023 return () => current++; 10024} 10025 10026function placeholdersToParams(placeholders) { 10027 const params = {};
10028 placeholders.forEach((values, key) => { 10029 params[key] = literal(values.length > 1 ? `[${values.join('|')}]` : values[0]); 10030 }); 10031 return params; 10032} 10033 10034function updatePlaceholderMap(map, name, ...values) { 10035 const current = map.get(name) || []; 10036 current.push(...values); 10037 map.set(name, current); 10038} 10039 10040function assembleBoundTextPlaceholders(meta, bindingStartIndex = 0, contextId = 0) { 10041 const startIdx = bindingStartIndex; 10042 const placeholders = new Map(); 10043 const node = meta instanceof Message ? meta.nodes.find(node => node instanceof Container) : meta; 10044 10045 if (node) { 10046 node.children.filter(child => child instanceof Placeholder).forEach((child, idx) => { 10047 const content = wrapI18nPlaceholder(startIdx + idx, contextId); 10048 updatePlaceholderMap(placeholders, child.name, content); 10049 }); 10050 } 10051 10052 return placeholders; 10053} 10054/** 10055 * Format the placeholder names in a map of placeholders to expressions. 10056 * 10057 * The placeholder names are converted from "internal" format (e.g. `START_TAG_DIV_1`) to "external" 10058 * format (e.g. `startTagDiv_1`). 10059 * 10060 * @param params A map of placeholder names to expressions. 10061 * @param useCamelCase whether to camelCase the placeholder name when formatting. 10062 * @returns A new map of formatted placeholder names to expressions. 10063 */ 10064 10065 10066function formatI18nPlaceholderNamesInMap(params = {}, useCamelCase) { 10067 const _params = {}; 10068 10069 if (params && Object.keys(params).length) { 10070 Object.keys(params).forEach(key => _params[formatI18nPlaceholderName(key, useCamelCase)] = params[key]); 10071 } 10072 10073 return _params; 10074} 10075/** 10076 * Converts internal placeholder names to public-facing format 10077 * (for example to use in goog.getMsg call). 10078 * Example: `START_TAG_DIV_1` is converted to `startTagDiv_1`. 10079 * 10080 * @param name The placeholder name that should be formatted 10081 * @returns Formatted placeholder name 10082 */ 10083 10084 10085function formatI18nPlaceholderName(name, useCamelCase = true) { 10086 const publicName = toPublicName(name); 10087 10088 if (!useCamelCase) { 10089 return publicName; 10090 } 10091 10092 const chunks = publicName.split('_'); 10093 10094 if (chunks.length === 1) { 10095 // if no "_" found - just lowercase the value 10096 return name.toLowerCase(); 10097 } 10098 10099 let postfix; // eject last element if it's a number 10100 10101 if (/^\d+$/.test(chunks[chunks.length - 1])) { 10102 postfix = chunks.pop(); 10103 } 10104 10105 let raw = chunks.shift().toLowerCase(); 10106 10107 if (chunks.length) { 10108 raw += chunks.map(c => c.charAt(0).toUpperCase() + c.slice(1).toLowerCase()).join(''); 10109 } 10110 10111 return postfix ? `${raw}_${postfix}` : raw; 10112} 10113/** 10114 * Generates a prefix for translation const name. 10115 * 10116 * @param extra Additional local prefix that should be injected into translation var name 10117 * @returns Complete translation const prefix 10118 */ 10119 10120 10121function getTranslationConstPrefix(extra) { 10122 return `${CLOSURE_TRANSLATION_VAR_PREFIX}${extra}`.toUpperCase(); 10123} 10124/** 10125 * Generate AST to declare a variable. E.g. `var I18N_1;`. 10126 * @param variable the name of the variable to declare. 10127 */ 10128 10129 10130function declareI18nVariable(variable) { 10131 return new DeclareVarStmt(variable.name, undefined, INFERRED_TYPE, undefined, variable.sourceSpan); 10132} 10133/** 10134 * @license 10135 * Copyright Google LLC All Rights Reserved. 10136 * 10137 * Use of this source code is governed by an MIT-style license that can be 10138 * found in the LICENSE file at https://angular.io/license 10139 */ 10140 10141/** 10142 * Checks whether an object key contains potentially unsafe chars, thus the key should be wrapped in 10143 * quotes. Note: we do not wrap all keys into quotes, as it may have impact on minification and may 10144 * bot work in some cases when object keys are mangled by minifier. 10145 * 10146 * TODO(FW-1136): this is a temporary solution, we need to come up with a better way of working with 10147 * inputs that contain potentially unsafe chars. 10148 */ 10149 10150 10151const UNSAFE_OBJECT_KEY_NAME_REGEXP = /[-.]/; 10152/** Name of the temporary to use during data binding */ 10153 10154const TEMPORARY_NAME = '_t'; 10155/** Name of the context parameter passed into a template function */ 10156 10157const CONTEXT_NAME = 'ctx'; 10158/** Name of the RenderFlag passed into a template function */ 10159 10160const RENDER_FLAGS = 'rf'; 10161/** The prefix reference variables */ 10162 10163const REFERENCE_PREFIX = '_r'; 10164/** The name of the implicit context reference */ 10165 10166const IMPLICIT_REFERENCE = '$implicit'; 10167/** Non bindable attribute name **/ 10168 10169const NON_BINDABLE_ATTR = 'ngNonBindable'; 10170/** Name for the variable keeping track of the context returned by `ɵɵrestoreView`. */ 10171 10172const RESTORED_VIEW_CONTEXT_NAME = 'restoredCtx'; 10173/** 10174 * Maximum length of a single instruction chain. Because our output AST uses recursion, we're 10175 * limited in how many expressions we can nest before we reach the call stack limit. This 10176 * length is set very conservatively in order to reduce the chance of problems. 10177 */ 10178 10179const MAX_CHAIN_LENGTH = 500; 10180/** Instructions that support chaining. */ 10181 10182const CHAINABLE_INSTRUCTIONS = new Set([Identifiers.element, Identifiers.elementStart, Identifiers.elementEnd, Identifiers.elementContainer, Identifiers.elementContainerStart, Identifiers.elementContainerEnd, Identifiers.i18nExp, Identifiers.listener, Identifiers.classProp, Identifiers.syntheticHostListener, Identifiers.hostProperty, Identifiers.syntheticHostProperty, Identifiers.property, Identifiers.propertyInterpolate1, Identifiers.propertyInterpolate2, Identifiers.propertyInterpolate3, Identifiers.propertyInterpolate4, Identifiers.propertyInterpolate5, Identifiers.propertyInterpolate6, Identifiers.propertyInterpolate7, Identifiers.propertyInterpolate8, Identifiers.propertyInterpolateV, Identifiers.attribute, Identifiers.attributeInterpolate1, Identifiers.attributeInterpolate2, Identifiers.attributeInterpolate3, Identifiers.attributeInterpolate4, Identifiers.attributeInterpolate5, Identifiers.attributeInterpolate6, Identifiers.attributeInterpolate7, Identifiers.attributeInterpolate8, Identifiers.attributeInterpolateV, Identifiers.styleProp, Identifiers.stylePropInterpolate1, Identifiers.stylePropInterpolate2, Identifiers.stylePropInterpolate3, Identifiers.stylePropInterpolate4, Identifiers.stylePropInterpolate5, Identifiers.stylePropInterpolate6, Identifiers.stylePropInterpolate7, Identifiers.stylePropInterpolate8, Identifiers.stylePropInterpolateV, Identifiers.textInterpolate, Identifiers.textInterpolate1, Identifiers.textInterpolate2, Identifiers.textInterpolate3, Identifiers.textInterpolate4, Identifiers.textInterpolate5, Identifiers.textInterpolate6, Identifiers.textInterpolate7, Identifiers.textInterpolate8, Identifiers.textInterpolateV]); 10183/** Generates a call to a single instruction. */ 10184
10185function invokeInstruction(span, reference, params) { 10186 return importExpr(reference, null, span).callFn(params, span); 10187} 10188/** 10189 * Creates an allocator for a temporary variable. 10190 * 10191 * A variable declaration is added to the statements the first time the allocator is invoked. 10192 */ 10193 10194 10195function temporaryAllocator(statements, name) { 10196 let temp = null; 10197 return () => { 10198 if (!temp) { 10199 statements.push(new DeclareVarStmt(TEMPORARY_NAME, undefined, DYNAMIC_TYPE)); 10200 temp = variable(name); 10201 } 10202 10203 return temp; 10204 }; 10205} 10206 10207function invalid(arg) { 10208 throw new Error(`Invalid state: Visitor ${this.constructor.name} doesn't handle ${arg.constructor.name}`); 10209} 10210 10211function asLiteral(value) { 10212 if (Array.isArray(value)) { 10213 return literalArr(value.map(asLiteral)); 10214 } 10215 10216 return literal(value, INFERRED_TYPE); 10217} 10218 10219function conditionallyCreateMapObjectLiteral(keys, keepDeclared) { 10220 if (Object.getOwnPropertyNames(keys).length > 0) { 10221 return mapToExpression(keys, keepDeclared); 10222 } 10223 10224 return null; 10225} 10226 10227function mapToExpression(map, keepDeclared) { 10228 return literalMap(Object.getOwnPropertyNames(map).map(key => { 10229 // canonical syntax: `dirProp: publicProp` 10230 const value = map[key]; 10231 let declaredName; 10232 let publicName; 10233 let minifiedName; 10234 let needsDeclaredName; 10235 10236 if (Array.isArray(value)) { 10237 [publicName, declaredName] = value; 10238 minifiedName = key; 10239 needsDeclaredName = publicName !== declaredName; 10240 } else { 10241 minifiedName = declaredName = key; 10242 publicName = value; 10243 needsDeclaredName = false; 10244 } 10245 10246 return { 10247 key: minifiedName, 10248 // put quotes around keys that contain potentially unsafe characters 10249 quoted: UNSAFE_OBJECT_KEY_NAME_REGEXP.test(minifiedName), 10250 value: keepDeclared && needsDeclaredName ? literalArr([asLiteral(publicName), asLiteral(declaredName)]) : asLiteral(publicName) 10251 }; 10252 })); 10253} 10254/** 10255 * Remove trailing null nodes as they are implied. 10256 */ 10257 10258 10259function trimTrailingNulls(parameters) { 10260 while (isNull(parameters[parameters.length - 1])) { 10261 parameters.pop(); 10262 } 10263 10264 return parameters; 10265} 10266 10267function getQueryPredicate(query, constantPool) { 10268 if (Array.isArray(query.predicate)) { 10269 let predicate = []; 10270 query.predicate.forEach(selector => { 10271 // Each item in predicates array may contain strings with comma-separated refs 10272 // (for ex. 'ref, ref1, ..., refN'), thus we extract individual refs and store them 10273 // as separate array entities 10274 const selectors = selector.split(',').map(token => literal(token.trim())); 10275 predicate.push(...selectors); 10276 }); 10277 return constantPool.getConstLiteral(literalArr(predicate), true); 10278 } else { 10279 // The original predicate may have been wrapped in a `forwardRef()` call. 10280 switch (query.predicate.forwardRef) { 10281 case 0 10282 /* ForwardRefHandling.None */ 10283 : 10284 case 2 10285 /* ForwardRefHandling.Unwrapped */ 10286 : 10287 return query.predicate.expression; 10288 10289 case 1 10290 /* ForwardRefHandling.Wrapped */ 10291 : 10292 return importExpr(Identifiers.resolveForwardRef).callFn([query.predicate.expression]); 10293 } 10294 } 10295} 10296/** 10297 * A representation for an object literal used during codegen of definition objects. The generic 10298 * type `T` allows to reference a documented type of the generated structure, such that the 10299 * property names that are set can be resolved to their documented declaration. 10300 */ 10301 10302 10303class DefinitionMap { 10304 constructor() { 10305 this.values = []; 10306 } 10307 10308 set(key, value) { 10309 if (value) { 10310 this.values.push({ 10311 key: key, 10312 value, 10313 quoted: false 10314 }); 10315 } 10316 } 10317 10318 toLiteralMap() { 10319 return literalMap(this.values); 10320 } 10321 10322} 10323/** 10324 * Extract a map of properties to values for a given element or template node, which can be used 10325 * by the directive matching machinery. 10326 * 10327 * @param elOrTpl the element or template in question 10328 * @return an object set up for directive matching. For attributes on the element/template, this 10329 * object maps a property name to its (static) value. For any bindings, this map simply maps the 10330 * property name to an empty string. 10331 */ 10332 10333 10334function getAttrsForDirectiveMatching(elOrTpl) { 10335 const attributesMap = {}; 10336 10337 if (elOrTpl instanceof Template && elOrTpl.tagName !== 'ng-template') {
10338 elOrTpl.templateAttrs.forEach(a => attributesMap[a.name] = ''); 10339 } else { 10340 elOrTpl.attributes.forEach(a => { 10341 if (!isI18nAttribute(a.name)) { 10342 attributesMap[a.name] = a.value; 10343 } 10344 }); 10345 elOrTpl.inputs.forEach(i => { 10346 attributesMap[i.name] = ''; 10347 }); 10348 elOrTpl.outputs.forEach(o => { 10349 attributesMap[o.name] = ''; 10350 }); 10351 } 10352 10353 return attributesMap; 10354} 10355/** 10356 * Gets the number of arguments expected to be passed to a generated instruction in the case of 10357 * interpolation instructions. 10358 * @param interpolation An interpolation ast 10359 */ 10360 10361 10362function getInterpolationArgsLength(interpolation) { 10363 const { 10364 expressions, 10365 strings 10366 } = interpolation; 10367 10368 if (expressions.length === 1 && strings.length === 2 && strings[0] === '' && strings[1] === '') { 10369 // If the interpolation has one interpolated value, but the prefix and suffix are both empty 10370 // strings, we only pass one argument, to a special instruction like `propertyInterpolate` or 10371 // `textInterpolate`. 10372 return 1; 10373 } else { 10374 return expressions.length + strings.length; 10375 } 10376} 10377/** 10378 * Generates the final instruction call statements based on the passed in configuration. 10379 * Will try to chain instructions as much as possible, if chaining is supported. 10380 */ 10381 10382 10383function getInstructionStatements(instructions) { 10384 const statements = []; 10385 let pendingExpression = null; 10386 let pendingExpressionType = null; 10387 let chainLength = 0; 10388 10389 for (const current of instructions) { 10390 const resolvedParams = (typeof current.paramsOrFn === 'function' ? current.paramsOrFn() : current.paramsOrFn) ?? []; 10391 const params = Array.isArray(resolvedParams) ? resolvedParams : [resolvedParams]; // If the current instruction is the same as the previous one 10392 // and it can be chained, add another call to the chain. 10393 10394 if (chainLength < MAX_CHAIN_LENGTH && pendingExpressionType === current.reference && CHAINABLE_INSTRUCTIONS.has(pendingExpressionType)) { 10395 // We'll always have a pending expression when there's a pending expression type. 10396 pendingExpression = pendingExpression.callFn(params, pendingExpression.sourceSpan); 10397 chainLength++; 10398 } else { 10399 if (pendingExpression !== null) { 10400 statements.push(pendingExpression.toStmt()); 10401 } 10402 10403 pendingExpression = invokeInstruction(current.span, current.reference, params); 10404 pendingExpressionType = current.reference; 10405 chainLength = 0; 10406 } 10407 } // Since the current instruction adds the previous one to the statements, 10408 // we may be left with the final one at the end that is still pending. 10409 10410 10411 if (pendingExpression !== null) { 10412 statements.push(pendingExpression.toStmt()); 10413 } 10414 10415 return statements; 10416} 10417/** 10418 * @license 10419 * Copyright Google LLC All Rights Reserved. 10420 * 10421 * Use of this source code is governed by an MIT-style license that can be 10422 * found in the LICENSE file at https://angular.io/license 10423 */ 10424 10425 10426function compileInjectable(meta, resolveForwardRefs) { 10427 let result = null; 10428 const factoryMeta = { 10429 name: meta.name, 10430 type: meta.type, 10431 internalType: meta.internalType, 10432 typeArgumentCount: meta.typeArgumentCount, 10433 deps: [], 10434 target: FactoryTarget$1.Injectable 10435 }; 10436 10437 if (meta.useClass !== undefined) { 10438 // meta.useClass has two modes of operation. Either deps are specified, in which case `new` is 10439 // used to instantiate the class with dependencies injected, or deps are not specified and 10440 // the factory of the class is used to instantiate it. 10441 // 10442 // A special case exists for useClass: Type where Type is the injectable type itself and no 10443 // deps are specified, in which case 'useClass' is effectively ignored. 10444 const useClassOnSelf = meta.useClass.expression.isEquivalent(meta.internalType); 10445 let deps = undefined; 10446 10447 if (meta.deps !== undefined) { 10448 deps = meta.deps; 10449 } 10450 10451 if (deps !== undefined) { 10452 // factory: () => new meta.useClass(...deps) 10453 result = compileFactoryFunction({ ...factoryMeta, 10454 delegate: meta.useClass.expression, 10455 delegateDeps: deps, 10456 delegateType: R3FactoryDelegateType.Class 10457 }); 10458 } else if (useClassOnSelf) { 10459 result = compileFactoryFunction(factoryMeta); 10460 } else { 10461 result = { 10462 statements: [], 10463 expression: delegateToFactory(meta.type.value, meta.useClass.expression, resolveForwardRefs) 10464 }; 10465 } 10466 } else if (meta.useFactory !== undefined) { 10467 if (meta.deps !== undefined) { 10468 result = compileFactoryFunction({ ...factoryMeta, 10469 delegate: meta.useFactory, 10470 delegateDeps: meta.deps || [], 10471 delegateType: R3FactoryDelegateType.Function 10472 }); 10473 } else { 10474 result = { 10475 statements: [],
10476 expression: fn([], [new ReturnStatement(meta.useFactory.callFn([]))]) 10477 }; 10478 } 10479 } else if (meta.useValue !== undefined) { 10480 // Note: it's safe to use `meta.useValue` instead of the `USE_VALUE in meta` check used for 10481 // client code because meta.useValue is an Expression which will be defined even if the actual 10482 // value is undefined. 10483 result = compileFactoryFunction({ ...factoryMeta, 10484 expression: meta.useValue.expression 10485 }); 10486 } else if (meta.useExisting !== undefined) { 10487 // useExisting is an `inject` call on the existing token. 10488 result = compileFactoryFunction({ ...factoryMeta, 10489 expression: importExpr(Identifiers.inject).callFn([meta.useExisting.expression]) 10490 }); 10491 } else { 10492 result = { 10493 statements: [], 10494 expression: delegateToFactory(meta.type.value, meta.internalType, resolveForwardRefs) 10495 }; 10496 } 10497 10498 const token = meta.internalType; 10499 const injectableProps = new DefinitionMap(); 10500 injectableProps.set('token', token); 10501 injectableProps.set('factory', result.expression); // Only generate providedIn property if it has a non-null value 10502 10503 if (meta.providedIn.expression.value !== null) { 10504 injectableProps.set('providedIn', convertFromMaybeForwardRefExpression(meta.providedIn)); 10505 } 10506 10507 const expression = importExpr(Identifiers.ɵɵdefineInjectable).callFn([injectableProps.toLiteralMap()], undefined, true); 10508 return { 10509 expression, 10510 type: createInjectableType(meta), 10511 statements: result.statements 10512 }; 10513} 10514 10515function createInjectableType(meta) { 10516 return new ExpressionType(importExpr(Identifiers.InjectableDeclaration, [typeWithParameters(meta.type.type, meta.typeArgumentCount)])); 10517} 10518 10519function delegateToFactory(type, internalType, unwrapForwardRefs) { 10520 if (type.node === internalType.node) { 10521 // The types are the same, so we can simply delegate directly to the type's factory. 10522 // ``` 10523 // factory: type.ɵfac 10524 // ``` 10525 return internalType.prop('ɵfac'); 10526 } 10527 10528 if (!unwrapForwardRefs) { 10529 // The type is not wrapped in a `forwardRef()`, so we create a simple factory function that 10530 // accepts a sub-type as an argument. 10531 // ``` 10532 // factory: function(t) { return internalType.ɵfac(t); } 10533 // ``` 10534 return createFactoryFunction(internalType); 10535 } // The internalType is actually wrapped in a `forwardRef()` so we need to resolve that before 10536 // calling its factory. 10537 // ``` 10538 // factory: function(t) { return core.resolveForwardRef(type).ɵfac(t); } 10539 // ``` 10540 10541 10542 const unwrappedType = importExpr(Identifiers.resolveForwardRef).callFn([internalType]); 10543 return createFactoryFunction(unwrappedType); 10544} 10545 10546function createFactoryFunction(type) { 10547 return fn([new FnParam('t', DYNAMIC_TYPE)], [new ReturnStatement
10547(type.prop('ɵfac').callFn([variable('t')]))]); 10548} 10549/** 10550 * @license 10551 * Copyright Google LLC All Rights Reserved. 10552 * 10553 * Use of this source code is governed by an MIT-style license that can be 10554 * found in the LICENSE file at https://angular.io/license 10555 */ 10556 10557 10558const UNUSABLE_INTERPOLATION_REGEXPS = [/^\s*$/, /[<>]/, /^[{}]$/, /&(#|[a-z])/i, /^\/\// // comment 10559]; 10560 10561function assertInterpolationSymbols(identifier, value) { 10562 if (value != null && !(Array.isArray(value) && value.length == 2)) { 10563 throw new Error(`Expected '${identifier}' to be an array, [start, end].`); 10564 } else if (value != null) { 10565 const start = value[0]; 10566 const end = value[1]; // Check for unusable interpolation symbols 10567 10568 UNUSABLE_INTERPOLATION_REGEXPS.forEach(regexp => { 10569 if (regexp.test(start) || regexp.test(end)) { 10570 throw new Error(`['${start}', '${end}'] contains unusable interpolation symbol.`); 10571 } 10572 }); 10573 } 10574} 10575/** 10576 * @license 10577 * Copyright Google LLC All Rights Reserved. 10578 * 10579 * Use of this source code is governed by an MIT-style license that can be 10580 * found in the LICENSE file at https://angular.io/license 10581 */ 10582 10583 10584class InterpolationConfig { 10585 constructor(start, end) { 10586 this.start = start; 10587 this.end = end; 10588 } 10589 10590 static fromArray(markers) { 10591 if (!markers) { 10592 return DEFAULT_INTERPOLATION_CONFIG; 10593 } 10594 10595 assertInterpolationSymbols('interpolation', markers); 10596 return new InterpolationConfig(markers[0], markers[1]); 10597 } 10598 10599} 10600 10601const DEFAULT_INTERPOLATION_CONFIG = new InterpolationConfig('{{', '}}'); 10602/** 10603 * @license 10604 * Copyright Google LLC All Rights Reserved. 10605 * 10606 * Use of this source code is governed by an MIT-style license that can be 10607 * found in the LICENSE file at https://angular.io/license 10608 */ 10609 10610const $EOF = 0; 10611const $BSPACE = 8; 10612const $TAB = 9; 10613const $LF = 10; 10614const $VTAB = 11; 10615const $FF = 12; 10616const $CR = 13; 10617const $SPACE = 32; 10618const $BANG = 33; 10619const $DQ = 34; 10620const $HASH = 35; 10621const $$ = 36; 10622const $PERCENT = 37; 10623const $AMPERSAND = 38; 10624const $SQ = 39; 10625const $LPAREN = 40; 10626const $RPAREN = 41; 10627const $STAR = 42; 10628const $PLUS = 43; 10629const $COMMA = 44; 10630const $MINUS = 45; 10631const $PERIOD = 46; 10632const $SLASH = 47; 10633const $COLON = 58; 10634const $SEMICOLON = 59; 10635const $LT = 60; 10636const $EQ = 61; 10637const $GT = 62; 10638const $QUESTION = 63; 10639const $0 = 48; 10640const $7 = 55; 10641const $9 = 57; 10642const $A = 65; 10643const $E = 69; 10644const $F = 70; 10645const $X = 88; 10646const $Z = 90; 10647const $LBRACKET = 91; 10648const $BACKSLASH = 92; 10649const $RBRACKET = 93; 10650const $CARET = 94; 10651const $_ = 95; 10652const $a = 97; 10653const $b = 98; 10654const $e = 101; 10655const $f = 102; 10656const $n = 110; 10657const $r = 114; 10658const $t = 116; 10659const $u = 117; 10660const $v = 118; 10661const $x = 120; 10662const $z = 122; 10663const $LBRACE = 123; 10664const $BAR = 124; 10665const $RBRACE = 125; 10666const $NBSP = 160; 10667const $PIPE = 124; 10668const $TILDA = 126; 10669const $AT = 64; 10670const $BT = 96; 10671 10672function isWhitespace(code) { 10673 return code >= $TAB && code <= $SPACE || code == $NBSP; 10674} 10675 10676function isDigit(code) { 10677 return $0 <= code && code <= $9; 10678} 10679 10680function isAsciiLetter(code) { 10681 return code >= $a && code <= $z || code >= $A && code <= $Z; 10682} 10683 10684function isAsciiHexDigit(code) { 10685 return code >= $a && code <= $f || code >= $A && code <= $F || isDigit(code); 10686} 10687 10688function isNewLine(code) { 10689 return code === $LF || code === $CR; 10690} 10691 10692function isOctalDigit(code) { 10693 return $0 <= code && code <= $7; 10694} 10695 10696function isQuote(code) { 10697 return code === $SQ || code === $DQ || code === $BT; 10698} 10699/** 10700 * @license 10701 * Copyright Google LLC All Rights Reserved. 10702 * 10703 * Use of this source code is governed by an MIT-style license that can be 10704 * found in the LICENSE file at https://angular.io/license 10705 */ 10706 10707 10708class ParseLocation { 10709 constructor(file, offset, line, col) { 10710 this.file = file; 10711 this.offset = offset; 10712 this.line = line; 10713 this.col = col; 10714 } 10715 10716 toString() { 10717 return this.offset != null ? `${this.file.url}@${this.line}:${this.col}` : this.file.url; 10718 } 10719 10720 moveBy(delta) { 10721 const source = this.file.content; 10722 const len = source.length; 10723 let offset = this.offset; 10724 let line = this.line; 10725 let col = this.col; 10726 10727 while (offset > 0 && delta < 0) { 10728 offset--; 10729 delta++; 10730 const ch = source.charCodeAt(offset); 10731 10732 if (ch == $LF) { 10733 line--; 10734 const priorLine = source.substring(0, offset - 1).lastIndexOf(String.fromCharCode($LF)); 10735 col = priorLine > 0 ? offset - priorLine : offset; 10736 } else { 10737 col--; 10738 } 10739 } 10740 10741 while (offset < len && delta > 0) { 10742 const ch = source.charCodeAt(offset); 10743 offset++; 10744 delta--; 10745 10746 if (ch == $LF) { 10747 line++; 10748 col = 0; 10749 } else { 10750 col++; 10751 } 10752 } 10753 10754 return new ParseLocation(this.file, offset, line, col); 10755 } // Return the source around the location 10756 // Up to `maxChars` or `maxLines` on each side of the location 10757 10758 10759 getContext(maxChars, maxLines) { 10760 const content = this.file.content; 10761 let startOffset = this.offset; 10762 10763 if (startOffset != null) { 10764 if (startOffset > content.length - 1) { 10765 startOffset = content.length - 1; 10766 } 10767 10768 let endOffset = startOffset; 10769 let ctxChars = 0; 10770 let ctxLines = 0; 10771 10772 while (ctxChars < maxChars && startOffset > 0) { 10773 startOffset--; 10774 ctxChars++; 10775 10776 if (content[startOffset] == '\n') { 10777 if (++ctxLines == maxLines) { 10778 break; 10779 } 10780 } 10781 } 10782 10783 ctxChars = 0; 10784 ctxLines = 0; 10785 10786 while (ctxChars < maxChars && endOffset < content.length - 1) { 10787 endOffset++; 10788 ctxChars++; 10789 10790 if (content[endOffset] == '\n') { 10791 if (++ctxLines == maxLines) { 10792 break; 10793 } 10794 } 10795 } 10796 10797 return { 10798 before: content.substring(startOffset, this.offset), 10799 after: content.substring(this.offset, endOffset + 1) 10800 }; 10801 } 10802 10803 return null; 10804 } 10805 10806} 10807 10808class ParseSourceFile {
10809 constructor(content, url) { 10810 this.content = content; 10811 this.url = url; 10812 } 10813 10814} 10815 10816class ParseSourceSpan { 10817 /** 10818 * Create an object that holds information about spans of tokens/nodes captured during 10819 * lexing/parsing of text. 10820 * 10821 * @param start 10822 * The location of the start of the span (having skipped leading trivia). 10823 * Skipping leading trivia makes source-spans more "user friendly", since things like HTML 10824 * elements will appear to begin at the start of the opening tag, rather than at the start of any 10825 * leading trivia, which could include newlines. 10826 * 10827 * @param end 10828 * The location of the end of the span. 10829 * 10830 * @param fullStart 10831 * The start of the token without skipping the leading trivia. 10832 * This is used by tooling that splits tokens further, such as extracting Angular interpolations 10833 * from text tokens. Such tooling creates new source-spans relative to the original token's 10834 * source-span. If leading trivia characters have been skipped then the new source-spans may be 10835 * incorrectly offset. 10836 * 10837 * @param details 10838 * Additional information (such as identifier names) that should be associated with the span. 10839 */ 10840 constructor(start, end, fullStart = start, details = null) { 10841 this.start = start; 10842 this.end = end; 10843 this.fullStart = fullStart; 10844 this.details = details; 10845 } 10846 10847 toString() { 10848 return this.start.file.content.substring(this.start.offset, this.end.offset); 10849 } 10850 10851} 10852 10853var ParseErrorLevel; 10854 10855(function (ParseErrorLevel) { 10856 ParseErrorLevel[ParseErrorLevel["WARNING"] = 0] = "WARNING"; 10857 ParseErrorLevel[ParseErrorLevel["ERROR"] = 1] = "ERROR"; 10858})(ParseErrorLevel || (ParseErrorLevel = {})); 10859 10860class ParseError { 10861 constructor(span, msg, level = ParseErrorLevel.ERROR) { 10862 this.span = span; 10863 this.msg = msg; 10864 this.level = level; 10865 } 10866 10867 contextualMessage() { 10868 const ctx = this.span.start.getContext(100, 3); 10869 return ctx ? `${this.msg} ("${ctx.before}[${ParseErrorLevel[this.level]} ->]${ctx.after}")` : this.msg; 10870 } 10871 10872 toString() { 10873 const details = this.span.details ? `, ${this.span.details}` : ''; 10874 return `${this.contextualMessage()}: ${this.span.start}${details}`; 10875 } 10876 10877} 10878/** 10879 * Generates Source Span object for a given R3 Type for JIT mode. 10880 * 10881 * @param kind Component or Directive. 10882 * @param typeName name of the Component or Directive. 10883 * @param sourceUrl reference to Component or Directive source. 10884 * @returns instance of ParseSourceSpan that represent a given Component or Directive. 10885 */ 10886 10887 10888function r3JitTypeSourceSpan(kind, typeName, sourceUrl) { 10889 const sourceFileName = `in ${kind} ${typeName} in ${sourceUrl}`; 10890 const sourceFile = new ParseSourceFile('', sourceFileName); 10891 return new ParseSourceSpan(new ParseLocation(sourceFile, -1, -1, -1), new ParseLocation(sourceFile, -1, -1, -1)); 10892} 10893 10894let _anonymousTypeIndex = 0; 10895 10896function identifierName(compileIdentifier) { 10897 if (!compileIdentifier || !compileIdentifier.reference) { 10898 return null; 10899 } 10900 10901 const ref = compileIdentifier.reference; 10902 10903 if (ref['__anonymousType']) { 10904 return ref['__anonymousType']; 10905 } 10906 10907 if (ref['__forward_ref__']) { 10908 // We do not want to try to stringify a `forwardRef()` function because that would cause the 10909 // inner function to be evaluated too early, defeating the whole point of the `forwardRef`. 10910 return '__forward_ref__';
10911 } 10912 10913 let identifier = stringify(ref); 10914 10915 if (identifier.indexOf('(') >= 0) { 10916 // case: anonymous functions! 10917 identifier = `anonymous_${_anonymousTypeIndex++}`; 10918 ref['__anonymousType'] = identifier; 10919 } else { 10920 identifier = sanitizeIdentifier(identifier); 10921 } 10922 10923 return identifier; 10924} 10925 10926function sanitizeIdentifier(name) { 10927 return name.replace(/\W/g, '_'); 10928} 10929/** 10930 * @license 10931 * Copyright Google LLC All Rights Reserved. 10932 * 10933 * Use of this source code is governed by an MIT-style license that can be 10934 * found in the LICENSE file at https://angular.io/license 10935 */ 10936 10937/** 10938 * In TypeScript, tagged template functions expect a "template object", which is an array of 10939 * "cooked" strings plus a `raw` property that contains an array of "raw" strings. This is 10940 * typically constructed with a function called `__makeTemplateObject(cooked, raw)`, but it may not 10941 * be available in all environments. 10942 * 10943 * This is a JavaScript polyfill that uses __makeTemplateObject when it's available, but otherwise 10944 * creates an inline helper with the same functionality. 10945 * 10946 * In the inline function, if `Object.defineProperty` is available we use that to attach the `raw` 10947 * array. 10948 */ 10949 10950
10951const makeTemplateObjectPolyfill = '(this&&this.__makeTemplateObject||function(e,t){return Object.defineProperty?Object.defineProperty(e,"raw",{value:t}):e.raw=t,e})'; 10952 10953class AbstractJsEmitterVisitor extends AbstractEmitterVisitor { 10954 constructor() { 10955 super(false); 10956 } 10957 10958 visitWrappedNodeExpr(ast, ctx) { 10959 throw new Error('Cannot emit a WrappedNodeExpr in Javascript.'); 10960 } 10961 10962 visitDeclareVarStmt(stmt, ctx) { 10963 ctx.print(stmt, `var ${stmt.name}`); 10964 10965 if (stmt.value) { 10966 ctx.print(stmt, ' = '); 10967 stmt.value.visitExpression(this, ctx); 10968 } 10969 10970 ctx.println(stmt, `;`); 10971 return null; 10972 } 10973 10974 visitTaggedTemplateExpr(ast, ctx) { 10975 // The following convoluted piece of code is effectively the downlevelled equivalent of 10976 // ``` 10977 // tag`...` 10978 // ``` 10979 // which is effectively like: 10980 // ``` 10981 // tag(__makeTemplateObject(cooked, raw), expression1, expression2, ...); 10982 // ``` 10983 const elements = ast.template.elements; 10984 ast.tag.visitExpression(this, ctx); 10985 ctx.print(ast, `(${makeTemplateOb
10985jectPolyfill}(`); 10986 ctx.print(ast, `[${elements.map(part => escapeIdentifier(part.text, false)).join(', ')}], `); 10987 ctx.print(ast, `[${elements.map(part => escapeIdentifier(part.rawText, false)).join(', ')}])`); 10988 ast.template.expressions.forEach(expression => { 10989 ctx.print(ast, ', '); 10990 expression.visitExpression(this, ctx); 10991 }); 10992 ctx.print(ast, ')'); 10993 return null; 10994 } 10995 10996 visitFunctionExpr(ast, ctx) { 10997 ctx.print(ast, `function${ast.name ? ' ' + ast.name : ''}(`); 10998 10999 this._visitParams(ast.params, ctx); 11000 11001 ctx.println(ast, `) {`); 11002 ctx.incIndent(); 11003 this.visitAllStatements(ast.statements, ctx); 11004 ctx.decIndent(); 11005 ctx.print(ast, `}`); 11006 return null; 11007 } 11008 11009 visitDeclareFunctionStmt(stmt, ctx) { 11010 ctx.print(stmt, `function ${stmt.name}(`); 11011 11012 this._visitParams(stmt.params, ctx); 11013 11014 ctx.println(stmt, `) {`); 11015 ctx.incIndent(); 11016 this.visitAllStatements(stmt.statements, ctx); 11017 ctx.decIndent(); 11018 ctx.println(stmt, `}`); 11019 return null; 11020 } 11021 11022 visitLocalizedString(ast, ctx) { 11023 // The following convoluted piece of code is effectively the downlevelled equivalent of 11024 // ``` 11025 // $localize `...` 11026 // ``` 11027 // which is effectively like: 11028 // ```
11029 // $localize(__makeTemplateObject(cooked, raw), expression1, expression2, ...); 11030 // ``` 11031 ctx.print(ast, `$localize(${makeTemplateObjectPolyfill}(`); 11032 const parts = [ast.serializeI18nHead()]; 11033 11034 for (let i = 1; i < ast.messageParts.length; i++) { 11035 parts.push(ast.serializeI18nTemplatePart(i)); 11036 } 11037 11038 ctx.print(ast, `[${parts.map(part => escapeIdentifier(part.cooked, false)).join(', ')}], `); 11039 ctx.print(ast, `[${parts.map(part => escapeIdentifier(part.raw, false)).join(', ')}])`); 11040 ast.expressions.forEach(expression => { 11041 ctx.print(ast, ', '); 11042 expression.visitExpression(this, ctx); 11043 }); 11044 ctx.print(ast, ')'); 11045 return null; 11046 } 11047 11048 _visitParams(params, ctx) { 11049 this.visitAllObjects(param => ctx.print(null, param.name), params, ctx, ','); 11050 } 11051 11052} 11053/** 11054 * @license 11055 * Copyright Google LLC All Rights Reserved. 11056 * 11057 * Use of this source code is governed by an MIT-style license that can be 11058 * found in the LICENSE file at https://angular.io/license 11059 */ 11060 11061/** 11062 * The Trusted Types policy, or null if Trusted Types are not 11063 * enabled/supported, or undefined if the policy has not been created yet. 11064 */ 11065 11066 11067let policy; 11068/** 11069 * Returns the Trusted Types policy, or null if Trusted Types are not 11070 * enabled/supported. The first call to this function will create the policy. 11071 */ 11072 11073function getPolicy() { 11074 if (policy === undefined) { 11075 policy = null; 11076 11077 if (_global.trustedTypes) { 11078 try { 11079 policy = _global.trustedTypes.createPolicy('angular#unsafe-jit', { 11080 createScript: s => s 11081 }); 11082 } catch {// trustedTypes.createPolicy throws if called with a name that is 11083 // already registered, even in report-only mode. Until the API changes, 11084 // catch the error not to break the applications functionally. In such 11085 // cases, the code will fall back to using strings. 11086 } 11087 } 11088 } 11089 11090 return policy; 11091} 11092/** 11093 * Unsafely promote a string to a TrustedScript, falling back to strings when 11094 * Trusted Types are not available. 11095 * @security In particular, it must be assured that the provided string will 11096 * never cause an XSS vulnerability if used in a context that will be 11097 * interpreted and executed as a script by a browser, e.g. when calling eval. 11098 */ 11099 11100 11101function trustedScriptFromString(script) { 11102 return getPolicy()?.createScript(script) || script; 11103} 11104/** 11105 * Unsafely call the Function constructor with the given string arguments. 11106 * @security This is a security-sensitive function; any use of this function 11107 * must go through security review. In particular, it must be assured that it 11108 * is only called from the JIT compiler, as use in other code can lead to XSS 11109 * vulnerabilities. 11110 */ 11111 11112 11113function newTrustedFunctionForJIT(...args) { 11114 if (!_global.trustedTypes) { 11115 // In environments that don't support Trusted Types, fall back to the most 11116 // straightforward implementation: 11117 return new Function(...args); 11118 } // Chrome currently does not support passing TrustedScript to the Function 11119 // constructor. The following implements the workaround proposed on the page 11120 // below, where the Chromium bug is also referenced: 11121 // https://github.com/w3c/webappsec-trusted-types/wiki/Trusted-Types-for-function-constructor 11122 11123 11124 const fnArgs = args.slice(0, -1).join(','); 11125 const fnBody = args[args.length - 1]; 11126 const body = `(function anonymous(${fnArgs} 11127) { ${fnBody} 11128})`; // Using eval directly confuses the compiler and prevents this module from 11129 // being stripped out of JS binaries even if not used. The global['eval'] 11130 // indirection fixes that. 11131 11132 const fn = _global['eval'](trustedScriptFromString(body)); 11133 11134 if (fn.bind === undefined) { 11135 // Workaround for a browser bug that only exists in Chrome 83, where passing 11136 // a TrustedScript to eval just returns the TrustedScript back without 11137 // evaluating it. In that case, fall back to the most straightforward 11138 // implementation: 11139 return new Function(...args); 11140 } // To completely mimic the behavior of calling "new Function", two more 11141 // things need to happen: 11142 // 1. Stringifying the resulting function should return its source code 11143 11144 11145 fn.toString = () => body; // 2. When calling the resulting function, `this` should refer to `global` 11146 11147 11148 return fn.bind(_global); // When Trusted Types support in Function constructors is widely available, 11149 // the implementation of this function can be simplified to: 11150 // return new Function(...args.map(a => trustedScriptFromString(a))); 11151} 11152/** 11153 * @license 11154 * Copyright Google LLC All Rights Reserved. 11155 * 11156 * Use of this source code is governed by an MIT-style license that can be 11157 * found in the LICENSE file at https://angular.io/license 11158 */ 11159 11160/** 11161 * A helper class to manage the evaluation of JIT generated code. 11162 */ 11163 11164 11165class JitEvaluator { 11166 /** 11167 * 11168 * @param sourceUrl The URL of the generated code. 11169 * @param statements An array of Angular statement AST nodes to be evaluated. 11170 * @param refResolver Resolves `o.ExternalReference`s into values. 11171 * @param createSourceMaps If true then create a source-map for the generated code and include it 11172 * inline as a source-map comment. 11173 * @returns A map of all the variables in the generated code. 11174 */ 11175 evaluateStatements(sourceUrl, statements, refResolver, createSourceMaps) { 11176 const converter = new JitEmitterVisitor(refResolver); 11177 const ctx = EmitterVisitorContext.createRoot(); // Ensure generated code is in strict mode 11178 11179 if (statements.length >
11179 0 && !isUseStrictStatement(statements[0])) { 11180 statements = [literal('use strict').toStmt(), ...statements]; 11181 } 11182 11183 converter.visitAllStatements(statements, ctx); 11184 converter.createReturnStmt(ctx); 11185 return this.evaluateCode(sourceUrl, ctx, converter.getArgs(), createSourceMaps); 11186 } 11187 /** 11188 * Evaluate a piece of JIT generated code. 11189 * @param sourceUrl The URL of this generated code. 11190 * @param ctx A context object that contains an AST of the code to be evaluated. 11191 * @param vars A map containing the names and values of variables that the evaluated code might 11192 * reference. 11193 * @param createSourceMap If true then create a source-map for the generated code and include it 11194 * inline as a source-map comment. 11195 * @returns The result of evaluating the code. 11196 */ 11197 11198 11199 evaluateCode(sourceUrl, ctx, vars, createSourceMap) { 11200 let fnBody = `"use strict";${ctx.toSource()}\n//# sourceURL=${sourceUrl}`; 11201 const fnArgNames = []; 11202 const fnArgValues = []; 11203 11204 for (const argName in vars) { 11205 fnArgValues.push(vars[argName]); 11206 fnArgNames.push(argName); 11207 } 11208 11209 if (createSourceMap) { 11210 // using `new Function(...)` generates a header, 1 line of no arguments, 2 lines otherwise 11211 // E.g. ``` 11212 // function anonymous(a,b,c 11213 // /**/) { ... }``` 11214 // We don't want to hard code this fact, so we auto detect it via an empty function first. 11215 const emptyFn = newTrustedFunctionForJIT(...fnArgNames.concat('return null;')).toString(); 11216 const headerLines = emptyFn.slice(0, emptyFn.indexOf('return null;')).split('\n').length - 1; 11217 fnBody += `\n${ctx.toSourceMapGenerator(sourceUrl, headerLines).toJsComment()}`; 11218 } 11219 11220 const fn = newTrustedFunctionForJIT(...fnArgNames.concat(fnBody)); 11221 return this.executeFunction(fn, fnArgValues); 11222 } 11223 /** 11224 * Execute a JIT generated function by calling it. 11225 * 11226 * This method can be overridden in tests to capture the functions that are generated 11227 * by this `JitEvaluator` class. 11228 * 11229 * @param fn A function to execute. 11230 * @param args The arguments to pass to the function being executed. 11231 * @returns The return value of the executed function. 11232 */ 11233 11234 11235 executeFunction(fn, args) { 11236 return fn(...args); 11237 } 11238 11239} 11240/** 11241 * An Angular AST visitor that converts AST nodes into executable JavaScript code. 11242 */ 11243 11244 11245class JitEmitterVisitor extends AbstractJsEmitterVisitor { 11246 constructor(refResolver) { 11247 super(); 11248 this.refResolver = refResolver; 11249 this._evalArgNames = []; 11250 this._evalArgValues = []; 11251 this._evalExportedVars = []; 11252 } 11253 11254 createReturnStmt(ctx) {
11255 const stmt = new ReturnStatement(new LiteralMapExpr(this._evalExportedVars.map(resultVar => new LiteralMapEntry(resultVar, variable(resultVar), false)))); 11256 stmt.visitStatement(this, ctx); 11257 } 11258 11259 getArgs() { 11260 const result = {}; 11261 11262 for (let i = 0; i < this._evalArgNames.length; i++) { 11263 result[this._evalArgNames[i]] = this._evalArgValues[i]; 11264 } 11265 11266 return result; 11267 } 11268 11269 visitExternalExpr(ast, ctx) { 11270 this._emitReferenceToExternal(ast, this.refResolver.resolveExternalReference(ast.value), ctx); 11271 11272 return null; 11273 } 11274 11275 visitWrappedNodeExpr(ast, ctx) { 11276 this._emitReferenceToExternal(ast, ast.node, ctx); 11277 11278 return null; 11279 } 11280 11281 visitDeclareVarStmt(stmt, ctx) { 11282 if (stmt.hasModifier(StmtModifier.Exported)) { 11283 this._evalExportedVars.push(stmt.name); 11284 } 11285 11286 return super.visitDeclareVarStmt(stmt, ctx); 11287 } 11288 11289 visitDeclareFunctionStmt(stmt, ctx) { 11290 if (stmt.hasModifier(StmtModifier.Exported)) { 11291 this._evalExportedVars.push(stmt.name); 11292 } 11293 11294 return super.visitDeclareFunctionStmt(stmt, ctx); 11295 } 11296 11297 _emitReferenceToExternal(ast, value, ctx) { 11298 let id = this._evalArgValues.indexOf(value); 11299 11300 if (id === -1) { 11301 id = this._evalArgValues.length; 11302 11303 this._evalArgValues.push(value); 11304 11305 const name = identifierName({ 11306 reference: value 11307 }) || 'val'; 11308 11309 this._evalArgNames.push(`jit_${name}_${id}`); 11310 } 11311 11312 ctx.print(ast, this._evalArgNames[id]); 11313 } 11314 11315} 11316 11317function isUseStrictStatement(statement) { 11318 return statement.isEquivalent(literal('use strict').toStmt()); 11319} 11320/** 11321 * @license 11322 * Copyright Google LLC All Rights Reserved. 11323 * 11324 * Use of this source code is governed by an MIT-style license that can be 11325 * found in the LICENSE file at https://angular.io/license 11326 */ 11327 11328 11329function compileInjector(meta) { 11330 const definitionMap = new DefinitionMap(); 11331 11332 if (meta.providers !== null) { 11333 definitionMap.set('providers', meta.providers); 11334 } 11335 11336 if (meta.imports.length > 0) { 11337 definitionMap.set('imports', literalArr(meta.imports)); 11338 } 11339 11340 const expression = importExpr(Identifiers.defineInjector).callFn([definitionMap.toLiteralMap()], undefined, true); 11341 const type = createInjectorType(meta); 11342 return { 11343 expression, 11344 type, 11345 statements: [] 11346 }; 11347} 11348 11349function createInjectorType(meta) { 11350 return new ExpressionType(importExpr(Identifiers.InjectorDeclaration, [new ExpressionType(meta.type.type)])); 11351} 11352/** 11353 * @license 11354 * Copyright Google LLC All Rights Reserved. 11355 * 11356 * Use of this source code is governed by an MIT-style license that can be 11357 * found in the LICENSE file at https://angular.io/license 11358 */ 11359 11360/** 11361 * Implementation of `CompileReflector` which resolves references to @angular/core 11362 * symbols at runtime, according to a consumer-provided mapping. 11363 * 11364 * Only supports `resolveExternalReference`, all other methods throw. 11365 */ 11366 11367 11368class R3JitReflector { 11369 constructor(context) { 11370 this.context = context; 11371 } 11372 11373 resolveExternalReference(ref) { 11374 // This reflector only handles @angular/core imports. 11375 if (ref.moduleName !== '@angular/core') { 11376 throw new Error(`Cannot resolve external reference to ${ref.moduleName}, only references to @angular/core are supported.`); 11377 } 11378
11379 if (!this.context.hasOwnProperty(ref.name)) { 11380 throw new Error(`No value provided for @angular/core symbol '${ref.name}'.`); 11381 } 11382 11383 return this.context[ref.name]; 11384 } 11385 11386} 11387/** 11388 * @license 11389 * Copyright Google LLC All Rights Reserved. 11390 * 11391 * Use of this source code is governed by an MIT-style license that can be 11392 * found in the LICENSE file at https://angular.io/license 11393 */ 11394 11395/** 11396 * How the selector scope of an NgModule (its declarations, imports, and exports) should be emitted 11397 * as a part of the NgModule definition. 11398 */ 11399 11400 11401var R3SelectorScopeMode; 11402 11403(function (R3SelectorScopeMode) { 11404 /** 11405 * Emit the declarations inline into the module definition. 11406 * 11407 * This option is useful in certain contexts where it's known that JIT support is required. The 11408 * tradeoff here is that this emit style prevents directives and pipes from being tree-shaken if 11409 * they are unused, but the NgModule is used. 11410 */ 11411 R3SelectorScopeMode[R3SelectorScopeMode["Inline"] = 0] = "Inline"; 11412 /** 11413 * Emit the declarations using a side effectful function call, `ɵɵsetNgModuleScope`, that is 11414 * guarded with the `ngJitMode` flag. 11415 * 11416 * This form of emit supports JIT and can be optimized away if the `ngJitMode` flag is set to 11417 * false, which allows unused directives and pipes to be tree-shaken. 11418 */ 11419 11420 R3SelectorScopeMode[R3SelectorScopeMode["SideEffect"] = 1] = "SideEffect"; 11421 /** 11422 * Don't generate selector scopes at all. 11423 * 11424 * This is useful for contexts where JIT support is known to be unnecessary. 11425 */ 11426 11427 R3SelectorScopeMode[R3SelectorScopeMode["Omit"] = 2] = "Omit"; 11428})(R3SelectorScopeMode || (R3SelectorScopeMode = {})); 11429/** 11430 * Construct an `R3NgModuleDef` for the given `R3NgModuleMetadata`. 11431 */ 11432 11433 11434function compileNgModule(meta) { 11435 const { 11436 adjacentType, 11437 internalType, 11438 bootstrap, 11439 declarations, 11440 imports, 11441 exports, 11442 schemas, 11443 containsForwardDecls, 11444 selectorScopeMode, 11445 id 11446 } = meta; 11447 const statements = []; 11448 const definitionMap = new DefinitionMap(); 11449 definitionMap.set('type', internalType); 11450 11451 if (bootstrap.length > 0) { 11452 definitionMap.set('bootstrap', refsToArray(bootstrap, containsForwardDecls)); 11453 } 11454 11455 if (selectorScopeMode === R3SelectorScopeMode.Inline) { 11456 // If requested to emit scope information inline, pass the `declarations`, `imports` and 11457 // `exports` to the `ɵɵdefineNgModule()` call directly. 11458 if (declarations.length > 0) { 11459 definitionMap.set('declarations', refsToArray(declarations, containsForwardDecls)); 11460 } 11461 11462 if (imports.length > 0) { 11463 definitionMap.set('imports', refsToArray(imports, containsForwardDecls)); 11464 } 11465 11466 if (exports.length > 0) { 11467 definitionMap.set('exports', refsToArray(exports, containsForwardDecls)); 11468 } 11469 } else if (selectorScopeMode === R3SelectorScopeMode.SideEffect) { 11470 // In this mode, scope information is not passed into `ɵɵdefineNgModule` as it 11471 // would prevent tree-shaking of the declarations, imports and exports references. Instead, it's 11472 // patched onto the NgModule definition with a `ɵɵsetNgModuleScope` call that's guarded by the 11473 // `ngJitMode` flag. 11474 const setNgModuleScopeCall = generateSetNgModuleScopeCall(meta); 11475 11476 if (setNgModuleScopeCall !== null) { 11477 statements.push(setNgModuleScopeCall); 11478 } 11479 } else {// Selector scope emit was not requested, so skip it. 11480 } 11481 11482 if (schemas !== null && schemas.length > 0) { 11483 definitionMap.set('schemas', literalArr(schemas.map(ref => ref.value))); 11484 } 11485 11486 if (id !== null) { 11487 definitionMap.set('id', id); // Generate a side-effectful call to register this NgModule by its id, as per the semantics of 11488 // NgModule ids. 11489 11490 statements.push(importExpr(Identifiers.registerNgModuleType).callFn([adjacentType, id]).toStmt()); 11491 } 11492 11493 const expression = importExpr(Identifiers.defineNgModule).callFn([definitionMap.toLiteralMap()], undefined, true); 11494 const type = createNgModuleType(meta); 11495 return { 11496 expression, 11497 type, 11498 statements 11499 }; 11500} 11501/** 11502 * This function is used in JIT mode to generate the call to `ɵɵdefineNgModule()` from a call to
11503 * `ɵɵngDeclareNgModule()`. 11504 */ 11505 11506 11507function compileNgModuleDeclarationExpression(meta) { 11508 const definitionMap = new DefinitionMap(); 11509 definitionMap.set('type', new WrappedNodeExpr(meta.type)); 11510 11511 if (meta.bootstrap !== undefined) { 11512 definitionMap.set('bootstrap', new WrappedNodeExpr(meta.bootstrap)); 11513 } 11514 11515 if (meta.declarations !== undefined) { 11516 definitionMap.set('declarations', new WrappedNodeExpr(meta.declarations)); 11517 } 11518 11519 if (meta.imports !== undefined) { 11520 definitionMap.set('imports', new WrappedNodeExpr(meta.imports)); 11521 } 11522 11523 if (meta.exports !== undefined) { 11524 definitionMap.set('exports', new WrappedNodeExpr(meta.exports)); 11525 } 11526 11527 if (meta.schemas !== undefined) { 11528 definitionMap.set('schemas', new WrappedNodeExpr(meta.schemas)); 11529 } 11530 11531 if (meta.id !== undefined) { 11532 definitionMap.set('id', new WrappedNodeExpr(meta.id)); 11533 } 11534 11535 return importExpr(Identifiers.defineNgModule).callFn([definitionMap.toLiteralMap()]); 11536} 11537 11538function createNgModuleType({ 11539 type: moduleType, 11540 declarations, 11541 exports, 11542 imports, 11543 includeImportTypes, 11544 publicDeclarationTypes 11545}) { 11546 return new ExpressionType(importExpr(Identifiers.NgModuleDeclaration, [new ExpressionType(moduleType.type), publicDeclarationTypes === null ? tupleTypeOf(declarations) : tupleOfTypes(publicDeclarationTypes), includeImportTypes ? tupleTypeOf(imports) : NONE_TYPE, tupleTypeOf(exports)])); 11547} 11548/** 11549 * Generates a function call to `ɵɵsetNgModuleScope` with all necessary information so that the 11550 * transitive module scope can be computed during runtime in JIT mode. This call is marked pure 11551 * such that the references to declarations, imports and exports may be elided causing these 11552 * symbols to become tree-shakeable. 11553 */ 11554 11555 11556function generateSetNgModuleScopeCall(meta) { 11557 const { 11558 adjacentType: moduleType, 11559 declarations, 11560 imports, 11561 exports, 11562 containsForwardDecls 11563 } = meta; 11564 const scopeMap = new DefinitionMap(); 11565 11566 if (declarations.length > 0) { 11567 scopeMap.set('declarations', refsToArray(declarations, containsForwardDecls)); 11568 } 11569 11570 if (imports.length > 0) { 11571 scopeMap.set('imports', refsToArray(imports, containsForwardDecls)); 11572 } 11573 11574 if (exports.length > 0) { 11575 scopeMap.set('exports', refsToArray(exports, containsForwardDecls)); 11576 } 11577 11578 if (Object.keys(scopeMap.values).length === 0) { 11579 return null; 11580 } // setNgModuleScope(...) 11581 11582 11583 const fnCall = new InvokeFunctionExpr( 11584 /* fn */ 11585 importExpr(Identifiers.setNgModuleScope), 11586 /* args */ 11587 [moduleType, scopeMap.toLiteralMap()]); // (ngJitMode guard) && setNgModuleScope(...) 11588 11589 const guardedCall = jitOnlyGuardedExpression(fnCall); // function() { (ngJitMode guard) && setNgModuleScope(...); } 11590 11591 const iife = new FunctionExpr( 11592 /* params */ 11593 [], 11594 /* statements */ 11595 [guardedCall.toStmt()]); // (function() { (ngJitMode guard) && setNgModuleScope(...); })() 11596 11597 const iifeCall = new InvokeFunctionExpr( 11598 /* fn */ 11599 iife, 11600 /* args */ 11601 []); 11602 return iifeCall.toStmt(); 11603} 11604 11605function tupleTypeOf(exp) { 11606 const types = exp.map(ref => typeofExpr(ref.type)); 11607 return exp.length > 0 ? expressionType(literalArr(types)) : NONE_TYPE; 11608} 11609 11610function tupleOfTypes(types) { 11611 const typeofTypes = types.map(type => typeofExpr(type)); 11612 return types.length > 0 ? expressionType(literalArr(typeofTypes)) : NONE_TYPE; 11613} 11614/** 11615 * @license 11616 * Copyright Google LLC All Rights Reserved. 11617 * 11618 * Use of this source code is governed by an MIT-style license that can be 11619 * found in the LICENSE file at https://angular.io/license 11620 */ 11621 11622 11623function compilePipeFromMetadata(metadata) { 11624 const definitionMapValues = []; // e.g. `name: 'myPipe'` 11625 11626 definitionMapValues.push({ 11627 key: 'name', 11628 value: literal(metadata.pipeName), 11629 quoted: false 11630 }); // e.g. `type: MyPipe` 11631 11632 definitionMapValues.push({ 11633 key: 'type', 11634 value: metadata.type.value, 11635 quoted: false 11636 }); // e.g. `pure: true` 11637 11638 definitionMapValues.push({ 11639 key: 'pure', 11640 value: literal(metadata.pure), 11641 quoted: false 11642 }); 11643 11644 if (metadata.isStandalone) { 11645 definitionMapValues.push({ 11646 key: 'standalone', 11647 value: literal(true), 11648 quoted: false 11649 }); 11650 } 11651 11652 const expression = importExpr(Identifiers.definePipe).callFn([literalMap(definitionMapValues)], undefined, true); 11653 const type = createPipeType(metadata); 11654 return { 11655 expression, 11656 type, 11657 statements: [] 11658 }; 11659} 11660 11661function createPipeType(metadata) { 11662 return new ExpressionType(importExpr(Identifiers.PipeDeclaration, [typeWithParameters(metadata.type.type, metadata.typeArgumentCount), new ExpressionType(new LiteralExpr(metadata.pipeName)), new ExpressionType(new LiteralExpr(metadata.isStandalone))])); 11663} 11664/** 11665 * @license 11666 * Copyright Google LLC All Rights Reserved. 11667 * 11668 * Use of this source code is governed by an MIT-style license that can be 11669 * found in the LICENSE file at https://angular.io/license 11670 */ 11671 11672 11673var R3TemplateDependencyKind; 11674 11675(function (R3TemplateDependencyKind) { 11676 R3TemplateDependencyKind[R3TemplateDependencyKind["Directive"] = 0] = "Directive"; 11677 R3TemplateDependencyKind[R3TemplateDependencyKind["Pipe"] = 1] = "Pipe"; 11678 R3TemplateDependencyKind[R3TemplateDependencyKind["NgModule"] = 2] = "NgModule"; 11679})(R3TemplateDependencyKind || (R3TemplateDependencyKind = {})); 11680/** 11681 * @license 11682 * Copyright Google LLC All Rights Reserved. 11683 * 11684 * Use of this source code is governed by an MIT-style license that can be 11685 * found in the LICENSE file at https://angular.io/license 11686 */ 11687 11688 11689class ParserError { 11690 constructor(message, input, errLocation, ctxLocation) { 11691 this.input = input; 11692 this.errLocation = errLocation; 11693 this.ctxLocation = ctxLocation; 11694 this.message = `Parser Error: ${message} ${errLocation} [${input}] in ${ctxLocation}`; 11695 } 11696 11697} 11698 11699class ParseSpan { 11700 constructor(start, end) { 11701 this.start = start; 11702 this.end = end; 11703 } 11704 11705 toAbsolute(absoluteOffset) { 11706 return new AbsoluteSourceSpan(absoluteOffset + this.start, absoluteOffset + this.end); 11707 } 11708 11709} 11710 11711class AST { 11712 constructor(span, 11713 /** 11714 * Absolute location of the expression AST in a source code file. 11715 */ 11716 sourceSpan) { 11717 this.span = span; 11718 this.sourceSpan = sourceSpan; 11719 } 11720 11721 toString() { 11722 return 'AST'; 11723 } 11724 11725} 11726 11727class ASTWithName extends AST { 11728 constructor(span, sourceSpan, nameSpan) { 11729 super(span, sourceSpan); 11730 this.nameSpan = nameSpan; 11731 } 11732 11733} 11734 11735class EmptyExpr extends AST { 11736 visit(visitor, context = null) {// do nothing 11737 } 11738 11739} 11740 11741class ImplicitReceiver extends AST { 11742 visit(visitor, context = null) { 11743 return visitor.visitImplicitReceiver(this, context); 11744 } 11745 11746} 11747/** 11748 * Receiver when something is accessed through `this` (e.g. `this.foo`). Note that this class 11749 * inherits from `ImplicitReceiver`, because accessing something through `this` is treated the 11750 * same as accessing it implicitly inside of an Angular template (e.g. `[attr.title]="this.title"` 11751 * is the same as `[attr.title]="title"`.). Inheriting allows for the `this` accesses to be treated 11752 * the same as implicit ones, except for a couple of exceptions like `$event` and `$any`. 11753 * TODO: we should find a way for this class not to extend from `ImplicitReceiver` in the future. 11754 */ 11755 11756 11757class ThisReceiver extends ImplicitReceiver { 11758 visit(visitor, context = null) { 11759 return visitor.visitThisReceiver?.(this, context); 11760 } 11761 11762} 11763/** 11764 * Multiple expressions separated by a semicolon. 11765 */ 11766 11767 11768class Chain extends AST { 11769 constructor(span, sourceSpan, expressions) { 11770 super(span, sourceSpan); 11771 this.expressions = expressions; 11772 } 11773 11774 visit(visitor, context = null) { 11775 return visitor.visitChain(this, context); 11776 } 11777 11778} 11779 11780class Conditional extends AST { 11781 constructor(span, sourceSpan, condition, trueExp, falseExp) { 11782 super(span, sourceSpan); 11783 this.condition = condition; 11784 this.trueExp = trueExp; 11785 this.falseExp = falseExp; 11786 } 11787 11788 visit(visitor, context = null) { 11789 return visitor.visitConditional(this, context); 11790 } 11791 11792} 11793 11794class PropertyRead extends ASTWithName { 11795 constructor(span, sourceSpan, nameSpan, receiver, name) { 11796 super(span, sourceSpan, nameSpan); 11797 this.receiver = receiver; 11798 this.name = name; 11799 } 11800 11801 visit(visitor, context = null) { 11802 return visitor.visitPropertyRead(this, context); 11803 } 11804 11805} 11806 11807class PropertyWrite extends ASTWithName { 11808 constructor(span, sourceSpan, nameSpan, receiver, name, value) { 11809 super(span, sourceSpan, nameSpan); 11810 this.receiver = receiver; 11811 this.name = name; 11812 this.value = value; 11813 } 11814 11815 visit(visitor, context = null) { 11816 return visitor.visitPropertyWrite(this, context); 11817 } 11818 11819} 11820 11821class SafePropertyRead extends ASTWithName { 11822 constructor(span, sourceSpan, nameSpan, receiver, name) { 11823 super(span, sourceSpan, nameSpan); 11824 this.receiver = receiver; 11825 this.name = name; 11826 } 11827 11828 visit(visitor, context = null) { 11829 return visitor.visitSafePropertyRead(this, context); 11830 } 11831 11832} 11833 11834class KeyedRead extends AST { 11835 constructor(span, sourceSpan, receiver, key) { 11836 super(span, sourceSpan); 11837 this.receiver = receiver; 11838 this.key = key; 11839 } 11840 11841 visit(visitor, context = null) { 11842 return visitor.visitKeyedRead(this, context); 11843 } 11844 11845} 11846 11847class SafeKeyedRead extends AST { 11848 constructor(span, sourceSpan, receiver, key) { 11849 super(span, sourceSpan); 11850 this.receiver = receiver; 11851 this.key = key; 11852 } 11853 11854 visit(visitor, context = null) { 11855 return visitor.visitSafeKeyedRead(this, context); 11856 } 11857 11858} 11859 11860class KeyedWrite extends AST { 11861 constructor(span, sourceSpan, receiver, key, value) { 11862 super(span, sourceSpan); 11863 this.receiver = receiver; 11864 this.key = key; 11865 this.value = value; 11866 } 11867 11868 visit(visitor, context = null) { 11869 return visitor.visitKeyedWrite(this, context); 11870 } 11871 11872} 11873 11874class BindingPipe extends ASTWithName { 11875 constructor(span, sourceSpan, exp, name, args, nameSpan) { 11876 super(span, sourceSpan, nameSpan); 11877 this.exp = exp; 11878 this.name = name; 11879 this.args = args; 11880 } 11881 11882 visit(visitor, context = null) { 11883 return visitor.visitPipe(this, context); 11884 } 11885 11886} 11887 11888class LiteralPrimitive extends AST { 11889 constructor(span, sourceSpan, value) { 11890 super(span, sourceSpan); 11891 this.value = value; 11892 } 11893 11894 visit(visitor, context = null) { 11895 return visitor.visitLiteralPrimitive(this, context); 11896 } 11897 11898} 11899 11900class LiteralArray extends AST { 11901 constructor(span, sourceSpan, expressions) { 11902 super(span, sourceSpan); 11903 this.expressions = expressions; 11904 } 11905 11906 visit(visitor, context = null) { 11907 return visitor.visitLiteralArray(this, context); 11908 } 11909 11910} 11911 11912class LiteralMap extends AST { 11913 constructor(span, sourceSpan, keys, values) { 11914 super(span, sourceSpan); 11915 this.keys = keys; 11916 this.values = values; 11917 } 11918 11919 visit(visitor, context = null) { 11920 return visitor.visitLiteralMap(this, context); 11921 } 11922 11923} 11924 11925class Interpolation extends AST { 11926 constructor(span, sourceSpan, strings, expressions) { 11927 super(span, sourceSpan); 11928 this.strings = strings; 11929 this.expressions = expressions; 11930 } 11931 11932 visit(visitor, context = null) { 11933 return visitor.visitInterpolation(this, context); 11934 } 11935 11936} 11937 11938class Binary extends AST { 11939 constructor(span, sourceSpan, operation, left, right) { 11940 super(span, sourceSpan); 11941 this.operation = operation; 11942 this.left = left; 11943 this.right = right; 11944 } 11945 11946 visit(visitor, context = null) { 11947 return visitor.visitBinary(this, context); 11948 } 11949 11950} 11951/** 11952 * For backwards compatibility reasons, `Unary` inherits from `Binary` and mimics the binary AST 11953 * node that was originally used. This inheritance relation can be deleted in some future major, 11954 * after consumers have been given a chance to fully support Unary. 11955 */ 11956 11957 11958class Unary extends Binary { 11959 /** 11960 * During the deprecation period this constructor is private, to avoid consumers from creating 11961 * a `Unary` with the fallback properties for `Binary`. 11962 */ 11963 constructor(span, sourceSpan, operator, expr, binaryOp, binaryLeft, binaryRight) { 11964 super(span, sourceSpan, binaryOp, binaryLeft, binaryRight); 11965 this.operator = operator; 11966 this.expr = expr; // Redeclare the properties that are inherited from `Binary` as `never`, as consumers should not 11967 // depend on these fields when operating on `Unary`. 11968 11969 this.left = null; 11970 this.right = null; 11971 this.operation = null; 11972 } 11973 /** 11974 * Creates a unary minus expression "-x", represented as `Binary` using "0 - x". 11975 */ 11976 11977 11978 static createMinus(span, sourceSpan, expr) { 11979 return new Unary(span, sourceSpan, '-', expr, '-', new LiteralPrimitive(span, sourceSpan, 0), expr); 11980 } 11981 /** 11982 * Creates a unary plus expression "+x", represented as `Binary` using "x - 0". 11983 */ 11984 11985 11986 static createPlus(span, sourceSpan, expr) { 11987 return new Unary(span, sourceSpan, '+', expr, '-', expr, new LiteralPrimitive(span, sourceSpan, 0)); 11988 } 11989 11990 visit(visitor, context = null) { 11991 if (visitor.visitUnary !== undefined) { 11992 return visitor.visitUnary(this, context); 11993 } 11994 11995 return visitor.visitBinary(this, context); 11996 } 11997 11998} 11999 12000class PrefixNot extends AST { 12001 constructor(span, sourceSpan, expression) { 12002 super(span, sourceSpan); 12003 this.expression = expression; 12004 } 12005 12006 visit(visitor, context = null) { 12007 return visitor.visitPrefixNot(this, context); 12008 } 12009 12010} 12011 12012class NonNullAssert extends AST { 12013 constructor(span, sourceSpan, expression) { 12014 super(span, sourceSpan); 12015 this.expression = expression; 12016 } 12017 12018 visit(visitor, context = null) { 12019 return visitor.visitNonNullAssert(this, context); 12020 } 12021 12022} 12023 12024class Call extends AST { 12025 constructor(span, sourceSpan, receiver, args, argumentSpan) { 12026 super(span, sourceSpan); 12027 this.receiver = receiver; 12028 this.args = args; 12029 this.argumentSpan = argumentSpan; 12030 } 12031 12032 visit(visitor, context = null) { 12033 return visitor.visitCall(this, context); 12034 } 12035 12036} 12037 12038class SafeCall extends AST { 12039 constructor(span, sourceSpan, receiver, args, argumentSpan) { 12040 super(span, sourceSpan); 12041 this.receiver = receiver; 12042 this.args = args; 12043 this.argumentSpan = argumentSpan; 12044 } 12045 12046 visit(visitor, context = null) { 12047 return visitor.visitSafeCall(this, context); 12048 } 12049 12050} 12051/** 12052 * Records the absolute position of a text span in a source file, where `start` and `end` are the 12053 * starting and ending byte offsets, respectively, of the text span in a source file. 12054 */ 12055 12056 12057class AbsoluteSourceSpan { 12058 constructor(start, end) { 12059 this.start = start; 12060 this.end = end; 12061 } 12062 12063} 12064 12065class ASTWithSource extends AST { 12066 constructor(ast, source, location, absoluteOffset, errors) { 12067 super(new ParseSpan(0, source === null ? 0 : source.length), new AbsoluteSourceSpan(absoluteOffset, source === null ? absoluteOffset : absoluteOffset + source.length)); 12068 this.ast = ast; 12069 this.source = source; 12070 this.location = location; 12071 this.errors = errors; 12072 } 12073 12074 visit(visitor, context = null) { 12075 if (visitor.visitASTWithSource) { 12076 return visitor.visitASTWithSource(this, context); 12077 } 12078 12079 return this.ast.visit(visitor, context); 12080 } 12081 12082 toString() { 12083 return `${this.source} in ${this.location}`; 12084 } 12085 12086} 12087 12088class VariableBinding { 12089 /** 12090 * @param sourceSpan entire span of the binding. 12091 * @param key name of the LHS along with its span. 12092 * @param value optional value for the RHS along with its span. 12093 */ 12094 constructor(sourceSpan, key, value) { 12095 this.sourceSpan = sourceSpan; 12096 this.key = key; 12097 this.value = value; 12098 } 12099 12100} 12101 12102class ExpressionBinding { 12103 /** 12104 * @param sourceSpan entire span of the binding. 12105 * @param key binding name, like ngForOf, ngForTrackBy, ngIf, along with its 12106 * span. Note that the length of the span may not be the same as 12107 * `key.source.length`. For example,
12108 * 1. key.source = ngFor, key.span is for "ngFor" 12109 * 2. key.source = ngForOf, key.span is for "of" 12110 * 3. key.source = ngForTrackBy, key.span is for "trackBy" 12111 * @param value optional expression for the RHS. 12112 */ 12113 constructor(sourceSpan, key, value) { 12114 this.sourceSpan = sourceSpan; 12115 this.key = key; 12116 this.value = value; 12117 } 12118 12119} 12120 12121class RecursiveAstVisitor { 12122 visit(ast, context) { 12123 // The default implementation just visits every node. 12124 // Classes that extend RecursiveAstVisitor should override this function 12125 // to selectively visit the specified node. 12126 ast.visit(this, context); 12127 } 12128 12129 visitUnary(ast, context) { 12130 this.visit(ast.expr, context); 12131 } 12132 12133 visitBinary(ast, context) { 12134 this.visit(ast.left, context); 12135 this.visit(ast.right, context); 12136 } 12137 12138 visitChain(ast, context) { 12139 this.visitAll(ast.expressions, context); 12140 } 12141 12142 visitConditional(ast, context) { 12143 this.visit(ast.condition, context); 12144 this.visit(ast.trueExp, context); 12145 this.visit(ast.falseExp, context); 12146 } 12147 12148 visitPipe(ast, context) { 12149 this.visit(ast.exp, context); 12150 this.visitAll(ast.args, context); 12151 } 12152 12153 visitImplicitReceiver(ast, context) {} 12154 12155 visitThisReceiver(ast, context) {} 12156 12157 visitInterpolation(ast, context) { 12158 this.visitAll(ast.expressions, context); 12159 } 12160 12161 visitKeyedRead(ast, context) { 12162 this.visit(ast.receiver, context); 12163 this.visit(ast.key, context); 12164 } 12165 12166 visitKeyedWrite(ast, context) { 12167 this.visit(ast.receiver, context); 12168 this.visit(ast.key, context); 12169 this.visit(ast.value, context); 12170 } 12171 12172 visitLiteralArray(ast, context) { 12173 this.visitAll(ast.expressions, context); 12174 } 12175 12176 visitLiteralMap(ast, context) { 12177 this.visitAll(ast.values, context); 12178 } 12179 12180 visitLiteralPrimitive(ast, context) {} 12181 12182 visitPrefixNot(ast, context) { 12183 this.visit(ast.expression, context); 12184 } 12185 12186 visitNonNullAssert(ast, context) { 12187 this.visit(ast.expression, context); 12188 } 12189 12190 visitPropertyRead(ast, context) { 12191 this.visit(ast.receiver, context); 12192 } 12193 12194 visitPropertyWrite(ast, context) { 12195 this.visit(ast.receiver, context); 12196 this.visit(ast.value, context); 12197 } 12198 12199 visitSafePropertyRead(ast, context) { 12200 this.visit(ast.receiver, context); 12201 } 12202 12203 visitSafeKeyedRead(ast, context) { 12204 this.visit(ast.receiver, context); 12205 this.visit(ast.key, context); 12206 } 12207 12208 visitCall(ast, context) { 12209 this.visit(ast.receiver, context); 12210 this.visitAll(ast.args, context); 12211 } 12212 12213 visitSafeCall(ast, context) { 12214 this.visit(ast.receiver, context); 12215 this.visitAll(ast.args, context); 12216 } // This is not part of the AstVisitor interface, just a helper method 12217 12218 12219 visitAll(asts, context) { 12220 for (const ast of asts) { 12221 this.visit(ast, context); 12222 } 12223 } 12224 12225} 12226 12227class AstTransformer { 12228 visitImplicitReceiver(ast, context) { 12229 return ast; 12230 } 12231 12232 visitThisReceiver(ast, context) { 12233 return ast; 12234 } 12235 12236 visitInterpolation(ast, context) { 12237 return new Interpolation(ast.span, ast.sourceSpan, ast.strings, this.visitAll(ast.expressions)); 12238 } 12239 12240 visitLiteralPrimitive(ast, context) { 12241 return new LiteralPrimitive(ast.span, ast.sourceSpan, ast.value); 12242 } 12243 12244 visitPropertyRead(ast, context) { 12245 return new PropertyRead(ast.span, ast.sourceSpan, ast.nameSpan, ast.receiver.visit(this), ast.name); 12246 } 12247 12248 visitPropertyWrite(ast, context) { 12249 return new PropertyWrite(ast.span, ast.sourceSpan, ast.nameSpan, ast.receiver.visit(this), ast.name, ast.value.visit(this)); 12250 } 12251 12252 visitSafePropertyRead(ast, context) { 12253 return new SafePropertyRead(ast.span, ast.sourceSpan, ast.nameSpan, ast.receiver.visit(this), ast.name); 12254 } 12255 12256 visitLiteralArray(ast, context) { 12257 return new LiteralArray(ast.span, ast.sourceSpan, this.visitAll(ast.expressions)); 12258 } 12259 12260 visitLiteralMap(ast, context) { 12261 return new LiteralMap(ast.span, ast.sourceSpan, ast.keys, this.visitAll(ast.values)); 12262 } 12263 12264 visitUnary(ast, context) { 12265 switch (ast.operator) { 12266 case '+': 12267 return Unary.createPlus(ast.span, ast.sourceSpan, ast.expr.visit(this)); 12268 12269 case '-': 12270 return Unary.createMinus(ast.span, ast.sourceSpan, ast.expr.visit(this)); 12271 12272 default: 12273 throw new Error(`Unknown unary operator ${ast.operator}`); 12274 } 12275 } 12276 12277 visitBinary(ast, context) { 12278 return new Binary(ast.span, ast.sourceSpan, ast.operation, ast.left.visit(this), ast.right.visit(this)); 12279 } 12280 12281 visitPrefixNot(ast, context) { 12282 return new PrefixNot(ast.span, ast.sourceSpan, ast.expression.visit(this)); 12283 } 12284 12285 visitNonNullAssert(ast, context) { 12286 return new NonNullAssert(ast.span, ast.sourceSpan, ast.expression.visit(this)); 12287 } 12288 12289 visitConditional(ast, context) { 12290 return new Conditional(ast.span, ast.sourceSpan, ast.condition.visit(this), ast.trueExp.visit(this), ast.falseExp.visit(this)); 12291 } 12292 12293 visitPipe(ast, context) { 12294 return new BindingPipe(ast.span, ast.sourceSpan, ast.exp.visit(this), ast.name, this.visitAll(ast.args), ast.nameSpan); 12295 } 12296 12297 visitKeyedRead(ast, context) { 12298 return new KeyedRead(ast.span, ast.sourceSpan, ast.receiver.visit(this), ast.key.visit(this)); 12299 } 12300 12301 visitKeyedWrite(ast, context) { 12302 return new KeyedWrite(ast.span, ast.sourceSpan, ast.receiver.visit(this), ast.key.visit(this), ast.value.visit(this)); 12303 } 12304 12305 visitCall(ast, context) { 12306 return new Call(ast.span, ast.sourceSpan, ast.receiver.visit(this), this.visitAll(ast.args), ast.argumentSpan); 12307 } 12308 12309 visitSafeCall(ast, context) { 12310 return new SafeCall(ast.span, ast.sourceSpan, ast.receiver.visit(this), this.visitAll(ast.args), ast.argumentSpan); 12311 } 12312 12313 visitAll(asts) { 12314 const res = []; 12315 12316 for (let i = 0; i < asts.length; ++i) { 12317 res[i] = asts[i].visit(this); 12318 } 12319 12320 return res; 12321 } 12322 12323 visitChain(ast, context) { 12324 return new Chain(ast.span, ast.sourceSpan, this.visitAll(ast.expressions)); 12325 } 12326 12327 visitSafeKeyedRead(ast, context) { 12328 return new SafeKeyedRead(ast.span, ast.sourceSpan, ast.receiver.visit(this), ast.key.visit(this)); 12329 } 12330 12331} // A transformer that only creates new nodes if the transformer makes a change or 12332// a change is made a child node. 12333 12334 12335class AstMemoryEfficientTransformer { 12336 visitImplicitReceiver(ast, context) { 12337 return ast; 12338 } 12339 12340 visitThisReceiver(ast, context) { 12341 return ast; 12342 } 12343 12344 visitInterpolation(ast, context) { 12345 const expressions = this.visitAll(ast.expressions); 12346 if (expressions !== ast.expressions) return new Interpolation(ast.span, ast.sourceSpan, ast.strings, expressions); 12347 return ast; 12348 } 12349 12350 visitLiteralPrimitive(ast, context) { 12351 return ast; 12352 } 12353 12354 visitPropertyRead(ast, context) { 12355 const receiver = ast.receiver.visit(this); 12356 12357 if (receiver !== ast.receiver) { 12358 return new PropertyRead(ast.span, ast.sourceSpan, ast.nameSpan, receiver, ast.name); 12359 } 12360 12361 return ast; 12362 } 12363 12364 visitPropertyWrite(ast, context) { 12365 const receiver = ast.receiver.visit(this); 12366 const value = ast.value.visit(this); 12367 12368 if (receiver !== ast.receiver || value !== ast.value) { 12369 return new PropertyWrite(ast.span, ast.sourceSpan, ast.nameSpan, receiver, ast.name, value); 12370 } 12371 12372 return ast; 12373 } 12374 12375 visitSafePropertyRead(ast, context) { 12376 const receiver = ast.receiver.visit(this); 12377 12378 if (receiver !== ast.receiver) { 12379 return new SafePropertyRead(ast.span, ast.sourceSpan, ast.nameSpan, receiver, ast.name); 12380 } 12381 12382 return ast; 12383 } 12384 12385 visitLiteralArray(ast, context) { 12386 const expressions = this.visitAll(ast.expressions); 12387 12388 if (expressions !== ast.expressions) { 12389 return new LiteralArray(ast.span, ast.sourceSpan, expressions); 12390 } 12391 12392 return ast; 12393 } 12394 12395 visitLiteralMap(ast, context) { 12396 const values = this.visitAll(ast.values); 12397 12398 if (values !== ast.values) { 12399 return new LiteralMap(ast.span, ast.sourceSpan, ast.keys, values); 12400 } 12401 12402 return ast; 12403 } 12404 12405 visitUnary(ast, context) { 12406 const expr = ast.expr.visit(this); 12407 12408 if (expr !== ast.expr) { 12409 switch (ast.operator) { 12410 case '+': 12411 return Unary.createPlus(ast.span, ast.sourceSpan, expr); 12412 12413 case '-': 12414 return Unary.createMinus(ast.span, ast.sourceSpan, expr); 12415 12416 default: 12417 throw new Error(`Unknown unary operator ${ast.operator}`); 12418 } 12419 } 12420 12421 return ast; 12422 } 12423 12424 visitBinary(ast, context) { 12425 const left = ast.left.visit(this); 12426 const right = ast.right.visit(this); 12427 12428 if (left !== ast.left || right !== ast.right) { 12429 return new Binary(ast.span, ast.sourceSpan, ast.operation, left, right); 12430 } 12431 12432 return ast; 12433 } 12434 12435 visitPrefixNot(ast, context) { 12436 const expression = ast.expression.visit(this); 12437 12438 if (expression !== ast.expression) { 12439 return new PrefixNot(ast.span, ast.sourceSpan, expression); 12440 } 12441 12442 return ast; 12443 } 12444 12445 visitNonNullAssert(ast, context) { 12446 const expression = ast.expression.visit(this); 12447 12448 if (expression !== ast.expression) { 12449 return new NonNullAssert(ast.span, ast.sourceSpan, expression); 12450 } 12451 12452 return ast; 12453 } 12454 12455 visitConditional(ast, context) { 12456 const condition = ast.condition.visit(this);
12457 const trueExp = ast.trueExp.visit(this); 12458 const falseExp = ast.falseExp.visit(this); 12459 12460 if (condition !== ast.condition || trueExp !== ast.trueExp || falseExp !== ast.falseExp) { 12461 return new Conditional(ast.span, ast.sourceSpan, condition, trueExp, falseExp); 12462 } 12463 12464 return ast; 12465 } 12466 12467 visitPipe(ast, context) { 12468 const exp = ast.exp.visit(this); 12469 const args = this.visitAll(ast.args); 12470 12471 if (exp !== ast.exp || args !== ast.args) { 12472 return new BindingPipe(ast.span, ast.sourceSpan, exp, ast.name, args, ast.nameSpan); 12473 } 12474 12475 return ast; 12476 } 12477 12478 visitKeyedRead(ast, context) { 12479 const obj = ast.receiver.visit(this); 12480 const key = ast.key.visit(this); 12481 12482 if (obj !== ast.receiver || key !== ast.key) { 12483 return new KeyedRead(ast.span, ast.sourceSpan, obj, key); 12484 } 12485 12486 return ast; 12487 } 12488 12489 visitKeyedWrite(ast, context) { 12490 const obj = ast.receiver.visit(this); 12491 const key = ast.key.visit(this); 12492 const value = ast.value.visit(this); 12493 12494 if (obj !== ast.receiver || key !== ast.key || value !== ast.value) { 12495 return new KeyedWrite(ast.span, ast.sourceSpan, obj, key, value); 12496 } 12497 12498 return ast; 12499 } 12500 12501 visitAll(asts) { 12502 const res = []; 12503 let modified = false; 12504 12505 for (let i = 0; i < asts.length; ++i) { 12506 const original = asts[i]; 12507 const value = original.visit(this); 12508 res[i] = value; 12509 modified = modified || value !== original; 12510 } 12511 12512 return modified ? res : asts; 12513 } 12514 12515 visitChain(ast, context) { 12516 const expressions = this.visitAll(ast.expressions); 12517 12518 if (expressions !== ast.expressions) { 12519 return new Chain(ast.span, ast.sourceSpan, expressions); 12520 } 12521 12522 return ast; 12523 } 12524 12525 visitCall(ast, context) { 12526 const receiver = ast.receiver.visit(this); 12527 const args = this.visitAll(ast.args); 12528 12529 if (receiver !== ast.receiver || args !== ast.args) { 12530 return new Call(ast.span, ast.sourceSpan, receiver, args, ast.argumentSpan); 12531 } 12532 12533 return ast; 12534 } 12535 12536 visitSafeCall(ast, context) { 12537 const receiver = ast.receiver.visit(this); 12538 const args = this.visitAll(ast.args); 12539 12540 if (receiver !== ast.receiver || args !== ast.args) { 12541 return new SafeCall(ast.span, ast.sourceSpan, receiver, args, ast.argumentSpan); 12542 } 12543 12544 return ast; 12545 } 12546 12547 visitSafeKeyedRead(ast, context) { 12548 const obj = ast.receiver.visit(this); 12549 const key = ast.key.visit(this); 12550 12551 if (obj !== ast.receiver || key !== ast.key) { 12552 return new SafeKeyedRead(ast.span, ast.sourceSpan, obj, key); 12553 } 12554 12555 return ast; 12556 } 12557 12558} // Bindings 12559 12560 12561class ParsedProperty { 12562 constructor(name, expression, type, sourceSpan, keySpan, valueSpan) { 12563 this.name = name; 12564 this.expression = expression; 12565 this.type = type; 12566 this.sourceSpan = sourceSpan; 12567 this.keySpan = keySpan; 12568 this.valueSpan = valueSpan; 12569 this.isLiteral = this.type === ParsedPropertyType.LITERAL_ATTR; 12570 this.isAnimation = this.type === ParsedPropertyType.ANIMATION; 12571 } 12572 12573} 12574 12575var ParsedPropertyType; 12576 12577(function (ParsedPropertyType) { 12578 ParsedPropertyType[ParsedPropertyType["DEFAULT"] = 0] = "DEFAULT"; 12579 ParsedPropertyType[ParsedPropertyType["LITERAL_ATTR"] = 1] = "LITERAL_ATTR"; 12580 ParsedPropertyType[ParsedPropertyType["ANIMATION"] = 2] = "ANIMATION"; 12581})(ParsedPropertyType || (ParsedPropertyType = {})); 12582 12583class ParsedEvent { 12584 // Regular events have a target 12585 // Animation events have a phase 12586 constructor(name, targetOrPhase, type, handler, sourceSpan, handlerSpan, keySpan) { 12587 this.name = name; 12588 this.targetOrPhase = targetOrPhase; 12589 this.type = type; 12590 this.handler = handler; 12591 this.sourceSpan = sourceSpan; 12592 this.handlerSpan = handlerSpan; 12593 this.keySpan = keySpan; 12594 } 12595 12596} 12597/** 12598 * ParsedVariable represents a variable declaration in a microsyntax expression. 12599 */ 12600 12601 12602class ParsedVariable { 12603 constructor(name, value, sourceSpan, keySpan, valueSpan) { 12604 this.name = name; 12605 this.value = value; 12606 this.sourceSpan = sourceSpan; 12607 this.keySpan = keySpan; 12608 this.valueSpan = valueSpan; 12609 } 12610 12611} 12612 12613class BoundElementProperty { 12614 constructor(name, type, securityContext, value, unit, sourceSpan, keySpan, valueSpan) { 12615 this.name = name; 12616 this.type = type; 12617 this.securityContext = securityContext; 12618 this.value = value; 12619 this.unit = unit; 12620 this.sourceSpan = sourceSpan; 12621 this.keySpan = keySpan; 12622 this.valueSpan = valueSpan; 12623 } 12624 12625} 12626/** 12627 * @license 12628 * Copyright Google LLC All Rights Reserved. 12629 * 12630 * Use of this source code is governed by an MIT-style license that can be 12631 * found in the LICENSE file at https://angular.io/license 12632 */ 12633 12634 12635class EventHandlerVars {} 12636 12637EventHandlerVars.event = variable('$event'); 12638/** 12639 * Converts the given expression AST into an executable output AST, assuming the expression is 12640 * used in an action binding (e.g. an event handler). 12641 */ 12642 12643function convertActionBinding(localResolver, implicitReceiver, action, bindingId, baseSourceSpan, implicitReceiverAccesses, globals) { 12644 if (!localResolver) { 12645 localResolver = new DefaultLocalResolver(globals); 12646 } 12647
12648 const actionWithoutBuiltins = convertPropertyBindingBuiltins({ 12649 createLiteralArrayConverter: argCount => { 12650 // Note: no caching for literal arrays in actions. 12651 return args => literalArr(args); 12652 }, 12653 createLiteralMapConverter: keys => { 12654 // Note: no caching for literal maps in actions. 12655 return values => { 12656 const entries = keys.map((k, i) => ({ 12657 key: k.key, 12658 value: values[i], 12659 quoted: k.quoted 12660 })); 12661 return literalMap(entries); 12662 }; 12663 }, 12664 createPipeConverter: name => { 12665 throw new Error(`Illegal State: Actions are not allowed to contain pipes. Pipe: ${name}`); 12666 } 12667 }, action); 12668 const visitor = new _AstToIrVisitor(localResolver, implicitReceiver, bindingId, 12669 /* supportsInterpolation */ 12670 false, baseSourceSpan, implicitReceiverAccesses); 12671 const actionStmts = []; 12672 flattenStatements(actionWithoutBuiltins.visit(visitor, _Mode.Statement), actionStmts); 12673 prependTemporaryDecls(visitor.temporaryCount, bindingId, actionStmts); 12674 12675 if (visitor.usesImplicitReceiver) { 12676 localResolver.notifyImplicitReceiverUse(); 12677 } 12678 12679 const lastIndex = actionStmts.length - 1; 12680 12681 if (lastIndex >= 0) { 12682 const lastStatement = actionStmts[lastIndex]; // Ensure that the value of the last expression statement is returned 12683 12684 if (lastStatement instanceof ExpressionStatement) {
12685 actionStmts[lastIndex] = new ReturnStatement(lastStatement.expr); 12686 } 12687 } 12688 12689 return actionStmts; 12690} 12691 12692function convertPropertyBindingBuiltins(converterFactory, ast) { 12693 return convertBuiltins(converterFactory, ast); 12694} 12695 12696class ConvertPropertyBindingResult { 12697 constructor(stmts, currValExpr) { 12698 this.stmts = stmts; 12699 this.currValExpr = currValExpr; 12700 } 12701 12702} 12703/** 12704 * Converts the given expression AST into an executable output AST, assuming the expression 12705 * is used in property binding. The expression has to be preprocessed via 12706 * `convertPropertyBindingBuiltins`. 12707 */ 12708 12709 12710function convertPropertyBinding(localResolver, implicitReceiver, expressionWithoutBuiltins, bindingId) { 12711 if (!localResolver) { 12712 localResolver = new DefaultLocalResolver(); 12713 } 12714 12715 const visitor = new _AstToIrVisitor(localResolver, implicitReceiver, bindingId, 12716 /* supportsInterpolation */ 12717 false); 12718 const outputExpr = expressionWithoutBuiltins.visit(visitor, _Mode.Expression); 12719 const stmts = getStatementsFromVisitor(visitor, bindingId); 12720 12721 if (visitor.usesImplicitReceiver) { 12722 localResolver.notifyImplicitReceiverUse(); 12723 } 12724 12725 return new ConvertPropertyBindingResult(stmts, outputExpr); 12726} 12727/** 12728 * Given some expression, such as a binding or interpolation expression, and a context expression to 12729 * look values up on, visit each facet of the given expression resolving values from the context 12730 * expression such that a list of arguments can be derived from the found values that can be used as 12731 * arguments to an external update instruction. 12732 * 12733 * @param localResolver The resolver to use to look up expressions by name appropriately 12734 * @param contextVariableExpression The expression representing the context variable used to create 12735 * the final argument expressions 12736 * @param expressionWithArgumentsToExtract The expression to visit to figure out what values need to 12737 * be resolved and what arguments list to build. 12738 * @param bindingId A name prefix used to create temporary variable names if they're needed for the 12739 * arguments generated 12740 * @returns An array of expressions that can be passed as arguments to instruction expressions like 12741 * `o.importExpr(R3.propertyInterpolate).callFn(result)` 12742 */ 12743 12744 12745function convertUpdateArguments(localResolver, contextVariableExpression, expressionWithArgumentsToExtract, bindingId) { 12746 const visitor = new _AstToIrVisitor(localResolver, contextVariableExpression, bindingId, 12747 /* supportsInterpolation */ 12748 true); 12749 const outputExpr = visitor.visitInterpolation(expressionWithArgumentsToExtract, _Mode.Expression); 12750 12751 if (visitor.usesImplicitReceiver) { 12752 localResolver.notifyImplicitReceiverUse(); 12753 } 12754 12755 const stmts = getStatementsFromVisitor(visitor, bindingId); 12756 const args = outputExpr.args; 12757 return { 12758 stmts, 12759 args 12760 }; 12761} 12762 12763function getStatementsFromVisitor(visitor, bindingId) { 12764 const stmts = []; 12765 12766 for (let i = 0; i < visitor.temporaryCount; i++) { 12767 stmts.push(temporaryDeclaration(bindingId, i)); 12768 } 12769 12770 return stmts; 12771} 12772 12773function convertBuiltins(converterFactory, ast) { 12774 const visitor = new _BuiltinAstConverter(converterFactory); 12775 return ast.visit(visitor); 12776} 12777 12778function temporaryName(bindingId, temporaryNumber) { 12779 return `tmp_${bindingId}_${temporaryNumber}`; 12780} 12781 12782function temporaryDeclaration(bindingId, temporaryNumber) { 12783 return new DeclareVarStmt(temporaryName(bindingId, temporaryNumber)); 12784} 12785 12786function prependTemporaryDecls(temporaryCount, bindingId, statements) { 12787 for (let i = temporaryCount - 1; i >= 0; i--) { 12788 statements.unshift(temporaryDeclaration(bindingId, i)); 12789 } 12790} 12791 12792var _Mode; 12793 12794(function (_Mode) { 12795 _Mode[_Mode["Statement"] = 0] = "Statement"; 12796 _Mode[_Mode["Expression"] = 1] = "Expression"; 12797})(_Mode || (_Mode = {})); 12798 12799function ensureStatementMode(mode, ast) { 12800 if (mode !== _Mode.Statement) { 12801 throw new Error(`Expected a statement, but saw ${ast}`); 12802 } 12803} 12804 12805function ensureExpressionMode(mode, ast) { 12806 if (mode !== _Mode.Expression) { 12807 throw new Error(`Expected an expression, but saw ${ast}`); 12808 } 12809} 12810 12811function convertToStatementIfNeeded(mode, expr) { 12812 if (mode === _Mode.Statement) { 12813 return expr.toStmt(); 12814 } else { 12815 return expr; 12816 } 12817} 12818 12819class _BuiltinAstConverter extends AstTransformer { 12820 constructor(_converterFactory) { 12821 super(); 12822 this._converterFactory = _converterFactory; 12823 } 12824 12825 visitPipe(ast, context) { 12826 const args = [ast.exp, ...ast.args].map(ast => ast.visit(this, context)); 12827 return new BuiltinFunctionCall(ast.span, ast.sourceSpan, args, this._converterFactory.createPipeConverter(ast.name, args.length)); 12828 } 12829 12830 visitLiteralArray(ast, context) { 12831 const args = ast.expressions.map(ast => ast.visit(this, context)); 12832 return new BuiltinFunctionCall(ast.span, ast.sourceSpan, args, this._converterFactory.createLiteralArrayConverter(ast.expressions.length)); 12833 } 12834 12835 visitLiteralMap(ast, context) { 12836 const args = ast.values.map(ast => ast.visit(this, context)); 12837 return new BuiltinFunctionCall(ast.span, ast.sourceSpan, args, this._converterFactory.createLiteralMapConverter(ast.keys)); 12838 } 12839 12840} 12841 12842class _AstToIrVisitor { 12843 constructor(_localResolver, _implicitReceiver, bindingId, supportsInterpolation, baseSourceSpan, implicitReceiverAccesses) { 12844 this._localResolver = _localResolver;
12845 this._implicitReceiver = _implicitReceiver; 12846 this.bindingId = bindingId; 12847 this.supportsInterpolation = supportsInterpolation; 12848 this.baseSourceSpan = baseSourceSpan; 12849 this.implicitReceiverAccesses = implicitReceiverAccesses; 12850 this._nodeMap = new Map(); 12851 this._resultMap = new Map(); 12852 this._currentTemporary = 0; 12853 this.temporaryCount = 0; 12854 this.usesImplicitReceiver = false; 12855 } 12856 12857 visitUnary(ast, mode) { 12858 let op; 12859 12860 switch (ast.operator) { 12861 case '+': 12862 op = UnaryOperator.Plus; 12863 break; 12864 12865 case '-': 12866 op = UnaryOperator.Minus; 12867 break; 12868 12869 default: 12870 throw new Error(`Unsupported operator ${ast.operator}`); 12871 } 12872 12873 return convertToStatementIfNeeded(mode, new UnaryOperatorExpr(op, this._visit(ast.expr, _Mode.Expression), undefined, this.convertSourceSpan(ast.span))); 12874 } 12875 12876 visitBinary(ast, mode) { 12877 let op; 12878 12879 switch (ast.operation) { 12880 case '+': 12881 op = BinaryOperator.Plus; 12882 break; 12883 12884 case '-': 12885 op = BinaryOperator.Minus; 12886 break; 12887 12888 case '*': 12889 op = BinaryOperator.Multiply; 12890 break; 12891 12892 case '/': 12893 op = BinaryOperator.Divide; 12894 break; 12895 12896 case '%': 12897 op = BinaryOperator.Modulo; 12898 break; 12899 12900 case '&&': 12901 op = BinaryOperator.And; 12902 break; 12903 12904 case '||': 12905 op = BinaryOperator.Or; 12906 break; 12907 12908 case '==': 12909 op = BinaryOperator.Equals; 12910 break; 12911 12912 case '!=': 12913 op = BinaryOperator.NotEquals; 12914 break; 12915 12916 case '===': 12917 op = BinaryOperator.Identical; 12918 break; 12919 12920 case '!==': 12921 op = BinaryOperator.NotIdentical; 12922 break; 12923 12924 case '<': 12925 op = BinaryOperator.Lower; 12926 break; 12927 12928 case '>': 12929 op = BinaryOperator.Bigger; 12930 break; 12931 12932 case '<=': 12933 op = BinaryOperator.LowerEquals; 12934 break; 12935 12936 case '>=': 12937 op = BinaryOperator.BiggerEquals; 12938 break; 12939 12940 case '??': 12941 return this.convertNullishCoalesce(ast, mode); 12942 12943 default: 12944 throw new Error(`Unsupported operation ${ast.operation}`); 12945 } 12946 12947 return convertToStatementIfNeeded(mode, new BinaryOperatorExpr(op, this._visit(ast.left, _Mode.Expression), this._visit(ast.right, _Mode.Expression), undefined, this.convertSourceSpan(ast.span))); 12948 } 12949 12950 visitChain(ast, mode) { 12951 ensureStatementMode(mode, ast); 12952 return this.visitAll(ast.expressions, mode); 12953 } 12954 12955 visitConditional(ast, mode) { 12956 const value = this._visit(ast.condition, _Mode.Expression); 12957 12958 return convertToStatementIfNeeded(mode, value.conditional(this._visit(ast.trueExp, _Mode.Expression), this._visit(ast.falseExp, _Mode.Expression), this.convertSourceSpan(ast.span))); 12959 } 12960 12961 visitPipe(ast, mode) { 12962 throw new Error(`Illegal state: Pipes should have been converted into functions. Pipe: ${ast.name}`); 12963 } 12964 12965 visitImplicitReceiver(ast, mode) { 12966 ensureExpressionMode(mode, ast); 12967 this.usesImplicitReceiver = true; 12968 return this._implicitReceiver; 12969 } 12970 12971 visitThisReceiver(ast, mode) { 12972 return this.visitImplicitReceiver(ast, mode); 12973 } 12974 12975 visitInterpolation(ast, mode) { 12976 if (!this.supportsInterpolation) { 12977 throw new Error('Unexpected interpolation'); 12978 } 12979 12980 ensureExpressionMode(mode, ast); 12981 let args = []; 12982 12983 for (let i = 0; i < ast.strings.length - 1; i++) { 12984 args.push(literal(ast.strings[i])); 12985 args.push(this._visit(ast.expressions[i], _Mode.Expression)); 12986 } 12987 12988 args.push(literal(ast.strings[ast.strings.length - 1])); // If we're dealing with an interpolation of 1 value with an empty prefix and suffix, reduce the 12989 // args returned to just the value, because we're going to pass it to a special instruction. 12990 12991 const strings = ast.strings; 12992 12993 if (strings.length === 2 && strings[0] === '' && strings[1] === '') { 12994 // Single argument interpolate instructions. 12995 args = [args[1]]; 12996 } else if (ast.expressions.length >= 9) { 12997 // 9 or more arguments must be passed to the `interpolateV`-style instructions, which accept 12998 // an array of arguments 12999 args = [literalArr(args)]; 13000 } 13001 13002 return new InterpolationExpression(args); 13003 } 13004 13005 visitKeyedRead(ast, mode) { 13006 const leftMostSafe = this.leftMostSafeNode(ast); 13007 13008 if (leftMostSafe) { 13009 return this.convertSafeAccess(ast, leftMostSafe, mode); 13010 } else { 13011 return convertToStatementIfNeeded(mode, this._visit(ast.receiver, _Mode.Expression).key(this._visit(ast.key, _Mode.Expression))); 13012 } 13013 } 13014 13015 visitKeyedWrite(ast, mode) { 13016 const obj = this._visit(ast.receiver, _Mode.Expression); 13017
13018 const key = this._visit(ast.key, _Mode.Expression); 13019 13020 const value = this._visit(ast.value, _Mode.Expression); 13021 13022 if (obj === this._implicitReceiver) { 13023 this._localResolver.maybeRestoreView(); 13024 } 13025 13026 return convertToStatementIfNeeded(mode, obj.key(key).set(value)); 13027 } 13028 13029 visitLiteralArray(ast, mode) { 13030 throw new Error(`Illegal State: literal arrays should have been converted into functions`); 13031 } 13032 13033 visitLiteralMap(ast, mode) { 13034 throw new Error(`Illegal State: literal maps should have been converted into functions`); 13035 } 13036 13037 visitLiteralPrimitive(ast, mode) { 13038 // For literal values of null, undefined, true, or false allow type interference 13039 // to infer the type. 13040 const type = ast.value === null || ast.value === undefined || ast.value === true || ast.value === true ? INFERRED_TYPE : undefined; 13041 return convertToStatementIfNeeded(mode, literal(ast.value, type, this.convertSourceSpan(ast.span))); 13042 } 13043 13044 _getLocal(name, receiver) { 13045 if (this._localResolver.globals?.has(name) && receiver instanceof ThisReceiver) { 13046 return null; 13047 } 13048 13049 return this._localResolver.getLocal(name); 13050 } 13051 13052 visitPrefixNot(ast, mode) { 13053 return convertToStatementIfNeeded(mode, not(this._visit(ast.expression, _Mode.Expression))); 13054 } 13055 13056 visitNonNullAssert(ast, mode) { 13057 return convertToStatementIfNeeded(mode, this._visit(ast.expression, _Mode.Expression)); 13058 } 13059 13060 visitPropertyRead(ast, mode) { 13061 const leftMostSafe = this.leftMostSafeNode(ast); 13062 13063 if (leftMostSafe) { 13064 return this.convertSafeAccess(ast, leftMostSafe, mode); 13065 } else { 13066 let result = null; 13067 const prevUsesImplicitReceiver = this.usesImplicitReceiver; 13068 13069 const receiver = this._visit(ast.receiver, _Mode.Expression); 13070 13071 if (receiver === this._implicitReceiver) { 13072 result = this._getLocal(ast.name, ast.receiver); 13073 13074 if (result) { 13075 // Restore the previous "usesImplicitReceiver" state since the implicit 13076 // receiver has been replaced with a resolved local expression. 13077 this.usesImplicitReceiver = prevUsesImplicitReceiver; 13078 this.addImplicitReceiverAccess(ast.name); 13079 } 13080 } 13081 13082 if (result == null) { 13083 result = receiver.prop(ast.name, this.convertSourceSpan(ast.span)); 13084 } 13085 13086 return convertToStatementIfNeeded(mode, result); 13087 } 13088 } 13089 13090 visitPropertyWrite(ast, mode) { 13091 const receiver = this._visit(ast.receiver, _Mode.Expression); 13092 13093 const prevUsesImplicitReceiver = this.usesImplicitReceiver; 13094 let varExpr = null; 13095 13096 if (receiver === this._implicitReceiver) { 13097 const localExpr = this._getLocal(ast.name, ast.receiver); 13098 13099 if (localExpr) { 13100 if (localExpr instanceof ReadPropExpr) { 13101 // If the local variable is a property read expression, it's a reference 13102 // to a 'context.property' value and will be used as the target of the 13103 // write expression. 13104 varExpr = localExpr; // Restore the previous "usesImplicitReceiver" state since the implicit 13105 // receiver has been replaced with a resolved local expression. 13106 13107 this.usesImplicitReceiver = prevUsesImplicitReceiver; 13108 this.addImplicitReceiverAccess(ast.name); 13109 } else { 13110 // Otherwise it's an error. 13111 const receiver = ast.name; 13112 const value = ast.value instanceof PropertyRead ? ast.value.name : undefined; 13113 throw new Error(`Cannot assign value "${value}" to template variable "${receiver}". Template variables are read-only.`); 13114 } 13115 } 13116 } // If no local expression could be produced, use the original receiver's 13117 // property as the target. 13118 13119 13120 if (varExpr === null) { 13121 varExpr = receiver.prop(ast.name, this.convertSourceSpan(ast.span)); 13122 } 13123 13124 return convertToStatementIfNeeded(mode, varExpr.set(this._visit(ast.value, _Mode.Expression))); 13125 } 13126 13127 visitSafePropertyRead(ast, mode) { 13128 return this.convertSafeAccess(ast, this.leftMostSafeNode(ast), mode); 13129 } 13130 13131 visitSafeKeyedRead(ast, mode) { 13132 return this.convertSafeAccess(ast, this.leftMostSafeNode(ast), mode); 13133 } 13134 13135 visitAll(asts, mode) { 13136 return asts.map(ast => this._visit(ast, mode)); 13137 } 13138 13139 visitCall(ast, mode) { 13140 const leftMostSafe = this.leftMostSafeNode(ast); 13141 13142 if (leftMostSafe) { 13143 return this.convertSafeAccess(ast, leftMostSafe, mode); 13144 } 13145 13146 const convertedArgs = this.visitAll(ast.args, _Mode.Expression); 13147
13148 if (ast instanceof BuiltinFunctionCall) { 13149 return convertToStatementIfNeeded(mode, ast.converter(convertedArgs)); 13150 } 13151 13152 const receiver = ast.receiver; 13153 13154 if (receiver instanceof PropertyRead && receiver.receiver instanceof ImplicitReceiver && !(receiver.receiver instanceof ThisReceiver) && receiver.name === '$any') { 13155 if (convertedArgs.length !== 1) { 13156 throw new Error(`Invalid call to $any, expected 1 argument but received ${convertedArgs.length || 'none'}`); 13157 } 13158 13159 return convertToStatementIfNeeded(mode, convertedArgs[0]); 13160 } 13161 13162 const call = this._visit(receiver, _Mode.Expression).callFn(convertedArgs, this.convertSourceSpan(ast.span)); 13163 13164 return convertToStatementIfNeeded(mode, call); 13165 } 13166 13167 visitSafeCall(ast, mode) { 13168 return this.convertSafeAccess(ast, this.leftMostSafeNode(ast), mode); 13169 } 13170 13171 _visit(ast, mode) { 13172 const result = this._resultMap.get(ast); 13173 13174 if (result) return result; 13175 return (this._nodeMap.get(ast) || ast).visit(this, mode); 13176 } 13177 13178 convertSafeAccess(ast, leftMostSafe, mode) { 13179 // If the expression contains a safe access node on the left it needs to be converted to 13180 // an expression that guards the access to the member by checking the receiver for blank. As 13181 // execution proceeds from left to right, the left most part of the expression must be guarded 13182 // first but, because member access is left associative, the right side of the expression is at 13183 // the top of the AST. The desired result requires lifting a copy of the left part of the 13184 // expression up to test it for blank before generating the unguarded version. 13185 // Consider, for example the following expression: a?.b.c?.d.e 13186 // This results in the ast: 13187 // . 13188 // / \ 13189 // ?. e 13190 // / \ 13191 // . d 13192 // / \ 13193 // ?. c 13194 // / \ 13195 // a b 13196 // The following tree should be generated: 13197 // 13198 // /---- ? ----\ 13199 // / | \ 13200 // a /--- ? ---\ null 13201 // / | \ 13202 // . . null 13203 // / \ / \ 13204 // . c . e 13205 // / \ / \ 13206 // a b . d 13207 // / \ 13208 // . c 13209 // / \ 13210 // a b 13211 // 13212 // Notice that the first guard condition is the left hand of the left most safe access node 13213 // which comes in as leftMostSafe to this routine. 13214 let guardedExpression = this._visit(leftMostSafe.receiver, _Mode.Expression); 13215 13216 let temporary = undefined; 13217 13218 if (this.needsTemporaryInSafeAccess(leftMostSafe.receiver)) { 13219 // If the expression has method calls or pipes then we need to save the result into a 13220 // temporary variable to avoid calling stateful or impure code more than once. 13221 temporary = this.allocateTemporary(); // Preserve the result in the temporary variable 13222 13223 guardedExpression = temporary.set(guardedExpression); // Ensure all further references to the guarded expression refer to the temporary instead. 13224 13225 this._resultMap.set(leftMostSafe.receiver, temporary); 13226 } 13227 13228 const condition = guardedExpression.isBlank(); // Convert the ast to an unguarded access to the receiver's member. The map will substitute 13229 // leftMostNode with its unguarded version in the call to `this.visit()`. 13230 13231 if (leftMostSafe instanceof SafeCall) { 13232 this._nodeMap.set(leftMostSafe, new Call(leftMostSafe.span, leftMostSafe.sourceSpan, leftMostSafe.receiver, leftMostSafe.args, leftMostSafe.argumentSpan)); 13233 } else if (leftMostSafe instanceof SafeKeyedRead) { 13234 this._nodeMap.set(leftMostSafe, new KeyedRead(leftMostSafe.span, leftMostSafe.sourceSpan, leftMostSafe.receiver, leftMostSafe.key)); 13235 } else { 13236 this._nodeMap.set(leftMostSafe, new PropertyRead(leftMostSafe.span, leftMostSafe.sourceSpan, leftMostSafe.nameSpan, leftMostSafe.receiver, leftMostSafe.name)); 13237 } // Recursively convert the node now without the guarded member access. 13238 13239 13240 const access = this._visit(ast, _Mode.Expression); // Remove the mapping. This is not strictly required as the converter only traverses each node 13241 // once but is safer if the conversion is changed to traverse the nodes more than once. 13242 13243 13244 this._nodeMap.delete(leftMostSafe); // If we allocated a temporary, release it. 13245 13246 13247 if (temporary) { 13248 this.releaseTemporary(temporary); 13249 } // Produce the conditional 13250 13251 13252 return convertToStatementIfNeeded(mode, condition.conditional(NULL_EXPR, access)); 13253 } 13254 13255 convertNullishCoalesce(ast, mode) { 13256 const left = this._visit(ast.left, _Mode.Expression); 13257 13258 const right = this._visit(ast.right, _Mode.Expression); 13259 13260 const temporary = this.allocateTemporary(); 13261 this.releaseTemporary(temporary); // Generate the following expression. It is identical to how TS 13262 // transpiles binary expressions with a nullish coalescing operator. 13263 // let temp; 13264 // (temp = a) !== null && temp !== undefined ? temp : b; 13265 13266 return convertToStatementIfNeeded(mode, temporary.set(left).notIdentical(NULL_EXPR).and(temporary.notIdentical(literal(undefined))).conditional(temporary, right)); 13267 } // Given an expression of the form a?.b.c?.d.e then the left most safe node is 13268 // the (a?.b). The . and ?. are left associative thus can be rewritten as: 13269 // ((((a?.c).b).c)?.d).e. This returns the most deeply nested safe read or 13270 // safe method call as this needs to be transformed initially to: 13271 // a == null ? null : a.c.b.c?.d.e 13272 // then to: 13273 // a == null ? null : a.b.c == null ? null : a.b.c.d.e 13274 13275 13276 leftMostSafeNode(ast) { 13277 const visit = (visitor, ast) => { 13278 return (this._nodeMap.get(ast) || ast).visit(visitor); 13279 }; 13280 13281 return ast.visit({ 13282 visitUnary(ast) { 13283 return null; 13284 }, 13285 13286 visitBinary(ast) { 13287 return null; 13288 }, 13289
13290 visitChain(ast) { 13291 return null; 13292 }, 13293 13294 visitConditional(ast) { 13295 return null; 13296 }, 13297 13298 visitCall(ast) { 13299 return visit(this, ast.receiver); 13300 }, 13301 13302 visitSafeCall(ast) { 13303 return visit(this, ast.receiver) || ast; 13304 }, 13305 13306 visitImplicitReceiver(ast) { 13307 return null; 13308 }, 13309 13310 visitThisReceiver(ast) { 13311 return null; 13312 }, 13313 13314 visitInterpolation(ast) { 13315 return null; 13316 }, 13317 13318 visitKeyedRead(ast) { 13319 return visit(this, ast.receiver); 13320 }, 13321 13322 visitKeyedWrite(ast) { 13323 return null; 13324 }, 13325 13326 visitLiteralArray(ast) { 13327 return null; 13328 }, 13329 13330 visitLiteralMap(ast) { 13331 return null; 13332 }, 13333 13334 visitLiteralPrimitive(ast) { 13335 return null; 13336 }, 13337 13338 visitPipe(ast) { 13339 return null; 13340 }, 13341 13342 visitPrefixNot(ast) { 13343 return null; 13344 }, 13345 13346 visitNonNullAssert(ast) { 13347 return null; 13348 }, 13349 13350 visitPropertyRead(ast) { 13351 return visit(this, ast.receiver); 13352 }, 13353 13354 visitPropertyWrite(ast) { 13355 return null; 13356 }, 13357 13358 visitSafePropertyRead(ast) { 13359 return visit(this, ast.receiver) || ast; 13360 }, 13361 13362 visitSafeKeyedRead(ast) { 13363 return visit(this, ast.receiver) || ast; 13364 } 13365 13366 }); 13367 } // Returns true of the AST includes a method or a pipe indicating that, if the 13368 // expression is used as the target of a safe property or method access then 13369 // the expression should be stored into a temporary variable. 13370 13371 13372 needsTemporaryInSafeAccess(ast) { 13373 const visit = (visitor, ast) => { 13374 return ast && (this._nodeMap.get(ast) || ast).visit(visitor); 13375 }; 13376 13377 const visitSome = (visitor, ast) => { 13378 return ast.some(ast => visit(visitor, ast)); 13379 }; 13380 13381 return ast.visit({ 13382 visitUnary(ast) { 13383 return visit(this, ast.expr); 13384 }, 13385 13386 visitBinary(ast) { 13387 return visit(this, ast.left) || visit(this, ast.right); 13388 }, 13389 13390 visitChain(ast) { 13391 return false; 13392 }, 13393 13394 visitConditional(ast) { 13395 return visit(this, ast.condition) || visit(this, ast.trueExp) || visit(this, ast.falseExp); 13396 }, 13397 13398 visitCall(ast) { 13399 return true; 13400 }, 13401 13402 visitSafeCall(ast) { 13403 return true; 13404 }, 13405 13406 visitImplicitReceiver(ast) { 13407 return false; 13408 }, 13409 13410 visitThisReceiver(ast) { 13411 return false; 13412 }, 13413 13414 visitInterpolation(ast) { 13415 return visitSome(this, ast.expressions); 13416 }, 13417 13418 visitKeyedRead(ast) { 13419 return false; 13420 }, 13421 13422 visitKeyedWrite(ast) { 13423 return false; 13424 }, 13425 13426 visitLiteralArray(ast) { 13427 return true; 13428 }, 13429 13430 visitLiteralMap(ast) { 13431 return true; 13432 }, 13433 13434 visitLiteralPrimitive(ast) { 13435 return false; 13436 }, 13437 13438 visitPipe(ast) { 13439 return true; 13440 }, 13441 13442 visitPrefixNot(ast) { 13443 return visit(this, ast.expression); 13444 }, 13445 13446 visitNonNullAssert(ast) { 13447 return visit(this, ast.expression); 13448 }, 13449 13450 visitPropertyRead(ast) { 13451 return false; 13452 }, 13453 13454 visitPropertyWrite(ast) { 13455 return false; 13456 }, 13457 13458 visitSafePropertyRead(ast) { 13459 return false; 13460 }, 13461 13462 visitSafeKeyedRead(ast) { 13463 return false; 13464 } 13465 13466 }); 13467 } 13468 13469 allocateTemporary() { 13470 const tempNumber = this._currentTemporary++; 13471 this.temporaryCount = Math.max(this._currentTemporary, this.temporaryCount); 13472 return new ReadVarExpr(temporaryName(this.bindingId, tempNumber)); 13473 } 13474 13475 releaseTemporary(temporary) { 13476 this._currentTemporary--; 13477 13478 if (temporary.name != temporaryName(this.bindingId, this._currentTemporary)) { 13479 throw new Error(`Temporary ${temporary.name} released out of order`); 13480 } 13481 } 13482 /** 13483 * Creates an absolute `ParseSourceSpan` from the relative `ParseSpan`. 13484 * 13485 * `ParseSpan` objects are relative to the start of the expression. 13486 * This method converts these to full `ParseSourceSpan` objects that 13487 * show where the span is within the overall source file. 13488 * 13489 * @param span the relative span to convert. 13490 * @returns a `ParseSourceSpan` for the given span or null if no 13491 * `baseSourceSpan` was provided to this class. 13492 */ 13493 13494 13495 convertSourceSpan(span) { 13496 if (this.baseSourceSpan) { 13497 const start = this.baseSourceSpan.start.moveBy(span.start); 13498 const end = this.baseSourceSpan.start.moveBy(span.end); 13499 const fullStart = this.baseSourceSpan.fullStart.moveBy(span.start); 13500 return new ParseSourceSpan(start, end, fullStart); 13501 } else { 13502 return null; 13503 } 13504 } 13505 /** Adds the name of an AST to the list of implicit receiver accesses. */ 13506 13507 13508 addImplicitReceiverAccess(name) {
13509 if (this.implicitReceiverAccesses) { 13510 this.implicitReceiverAccesses.add(name); 13511 } 13512 } 13513 13514} 13515 13516function flattenStatements(arg, output) { 13517 if (Array.isArray(arg)) { 13518 arg.forEach(entry => flattenStatements(entry, output)); 13519 } else { 13520 output.push(arg); 13521 } 13522} 13523 13524function unsupported() { 13525 throw new Error('Unsupported operation'); 13526} 13527 13528class InterpolationExpression extends Expression { 13529 constructor(args) { 13530 super(null, null); 13531 this.args = args; 13532 this.isConstant = unsupported; 13533 this.isEquivalent = unsupported; 13534 this.visitExpression = unsupported; 13535 } 13536 13537} 13538 13539class DefaultLocalResolver { 13540 constructor(globals) { 13541 this.globals = globals; 13542 } 13543 13544 notifyImplicitReceiverUse() {} 13545 13546 maybeRestoreView() {} 13547 13548 getLocal(name) { 13549 if (name === EventHandlerVars.event.name) { 13550 return EventHandlerVars.event; 13551 } 13552 13553 return null; 13554 } 13555 13556} 13557 13558class BuiltinFunctionCall extends Call { 13559 constructor(span, sourceSpan, args, converter) { 13560 super(span, sourceSpan, new EmptyExpr(span, sourceSpan), args, null); 13561 this.converter = converter; 13562 } 13563 13564} 13565/** 13566 * @license 13567 * Copyright Google LLC All Rights Reserved. 13568 * 13569 * Use of this source code is governed by an MIT-style license that can be 13570 * found in the LICENSE file at https://angular.io/license 13571 */ 13572// ================================================================================================= 13573// ================================================================================================= 13574// =========== S T O P - S T O P - S T O P - S T O P - S T O P - S T O P =========== 13575// ================================================================================================= 13576// ================================================================================================= 13577// 13578// DO NOT EDIT THIS LIST OF SECURITY SENSITIVE PROPERTIES WITHOUT A SECURITY REVIEW! 13579// Reach out to mprobst for details. 13580// 13581// ================================================================================================= 13582 13583/** Map from tagName|propertyName to SecurityContext. Properties applying to all tags use '*'. */ 13584 13585 13586let _SECURITY_SCHEMA; 13587 13588function SECURITY_SCHEMA() { 13589 if (!_SECURITY_SCHEMA) { 13590 _SECURITY_SCHEMA = {}; // Case is insignificant below, all element and attribute names are lower-cased for lookup. 13591 13592 registerContext(SecurityContext.HTML, ['iframe|srcdoc', '*|innerHTML', '*|outerHTML']); 13593 registerContext(SecurityContext.STYLE, ['*|style']); // NB: no SCRIPT contexts here, they are never allowed due to the parser stripping them. 13594 13595 registerContext(SecurityContext.URL, ['*|formAction', 'area|href', 'area|ping', 'audio|src', 'a|href', 'a|ping', 'blockquote|cite', 'body|background', 'del|cite', 'form|action', 'img|src', 'input|src', 'ins|cite', 'q|cite', 'source|src', 'track|src', 'video|poster', 'video|src']); 13596 registerContext(SecurityContext.RESOURCE_URL, ['applet|code', 'applet|codebase', 'base|href', 'embed|src', 'frame|src', 'head|profile', 'html|manifest', 'iframe|src', 'link|href', 'media|src', 'object|codebase', 'object|data', 'script|src']); 13597 } 13598 13599 return _SECURITY_SCHEMA; 13600} 13601 13602function registerContext(ctx, specs) { 13603 for (const spec of specs) _SECURITY_SCHEMA[spec.toLowerCase()] = ctx; 13604} 13605/** 13606 * The set of security-sensitive attributes of an `<iframe>` that *must* be 13607 * applied as a static attribute only. This ensures that all security-sensitive 13608 * attributes are taken into account while creating an instance of an `<iframe>` 13609 * at runtime. 13610 * 13611 * Note: avoid using this set directly, use the `isIframeSecuritySensitiveAttr` function 13612 * in the code instead. 13613 */ 13614 13615 13616const IFRAME_SECURITY_SENSITIVE_ATTRS = new Set(['sandbox', 'allow', 'allowfullscreen', 'referrerpolicy', 'csp', 'fetchpriority']); 13617/** 13618 * Checks whether a given attribute name might represent a security-sensitive 13619 * attribute of an <iframe>. 13620 */ 13621 13622function isIframeSecuritySensitiveAttr(attrName) { 13623 // The `setAttribute` DOM API is case-insensitive, so we lowercase the value 13624 // before checking it against a known security-sensitive attributes. 13625 return IFRAME_SECURITY_SENSITIVE_ATTRS.has(attrName.toLowerCase()); 13626} 13627/** 13628 * @license 13629 * Copyright Google LLC All Rights Reserved. 13630 * 13631 * Use of this source code is governed by an MIT-style license that can be 13632 * found in the LICENSE file at https://angular.io/license 13633 */ 13634 13635/** 13636 * This file is a port of shadowCSS from webcomponents.js to TypeScript. 13637 * 13638 * Please make sure to keep to edits in sync with the source file. 13639 * 13640 * Source: 13641 * https://github.com/webcomponents/webcomponentsjs/blob/4efecd7e0e/src/ShadowCSS/ShadowCSS.js 13642 * 13643 * The original file level comment is reproduced below 13644 */ 13645 13646/* 13647 This is a limited shim for ShadowDOM css styling. 13648 https://dvcs.w3.org/hg/webcomponents/raw-file/tip/spec/shadow/index.html#styles 13649 13650 The intention here is to support only the styling features which can be 13651 relatively simply implemented. The goal is to allow users to avoid the 13652 most obvious pitfalls and do so without compromising performance significantly. 13653 For ShadowDOM styling that's not covered here, a set of best practices 13654 can be provided that should allow users to accomplish more complex styling. 13655 13656 The following is a list of specific ShadowDOM styling features and a brief 13657 discussion of the approach used to shim. 13658 13659 Shimmed features: 13660 13661 * :host, :host-context: ShadowDOM allows styling of the shadowRoot's host 13662 element using the :host rule. To shim this feature, the :host styles are 13663 reformatted and prefixed with a given scope name and promoted to a 13664 document level stylesheet. 13665 For example, given a scope name of .foo, a rule like this: 13666 13667 :host { 13668 background: red; 13669 } 13670 } 13671 13672 becomes: 13673 13674 .foo { 13675 background: red; 13676 } 13677 13678 * encapsulation: Styles defined within ShadowDOM, apply only to 13679 dom inside the ShadowDOM. Polymer uses one of two techniques to implement 13680 this feature. 13681 13682 By default, rules are prefixed with the host element tag name 13683 as a descendant selector. This ensures styling does not leak out of the 'top' 13684 of the element's ShadowDOM. For example, 13685 13686 div { 13687 font-weight: bold; 13688 } 13689 13690 becomes: 13691 13692 x-foo div { 13693 font-weight: bold; 13694 } 13695 13696 becomes: 13697 13698 13699 Alternatively, if WebComponents.ShadowCSS.strictStyling is set to true then 13700 selectors are scoped by adding an attribute selector suffix to each
13701 simple selector that contains the host element tag name. Each element 13702 in the element's ShadowDOM template is also given the scope attribute. 13703 Thus, these rules match only elements that have the scope attribute. 13704 For example, given a scope name of x-foo, a rule like this: 13705 13706 div { 13707 font-weight: bold; 13708 } 13709 13710 becomes: 13711 13712 div[x-foo] { 13713 font-weight: bold; 13714 } 13715 13716 Note that elements that are dynamically added to a scope must have the scope 13717 selector added to them manually. 13718 13719 * upper/lower bound encapsulation: Styles which are defined outside a 13720 shadowRoot should not cross the ShadowDOM boundary and should not apply 13721 inside a shadowRoot. 13722 13723 This styling behavior is not emulated. Some possible ways to do this that 13724 were rejected due to complexity and/or performance concerns include: (1) reset 13725 every possible property for every possible selector for a given scope name; 13726 (2) re-implement css in javascript. 13727 13728 As an alternative, users should make sure to use selectors 13729 specific to the scope in which they are working. 13730 13731 * ::distributed: This behavior is not emulated. It's often not necessary 13732 to style the contents of a specific insertion point and instead, descendants 13733 of the host element can be styled selectively. Users can also create an 13734 extra node around an insertion point and style that node's contents 13735 via descendent selectors. For example, with a shadowRoot like this: 13736 13737 <style> 13738 ::content(div) { 13739 background: red; 13740 } 13741 </style> 13742 <content></content> 13743 13744 could become: 13745 13746 <style> 13747 / *@polyfill .content-container div * / 13748 ::content(div) { 13749 background: red; 13750 } 13751 </style> 13752 <div class="content-container"> 13753 <content></content> 13754 </div> 13755 13756 Note the use of @polyfill in the comment above a ShadowDOM specific style 13757 declaration. This is a directive to the styling shim to use the selector 13758 in comments in lieu of the next selector when running under polyfill. 13759*/ 13760 13761 13762class ShadowCss { 13763 constructor() { 13764 this.strictStyling = true; 13765 } 13766 /* 13767 * Shim some cssText with the given selector. Returns cssText that can 13768 * be included in the document via WebComponents.ShadowCSS.addCssToDocument(css). 13769 * 13770 * When strictStyling is true: 13771 * - selector is the attribute added to all elements inside the host, 13772 * - hostSelector is the attribute added to the host itself. 13773 */ 13774 13775 13776 shimCssText(cssText, selector, hostSelector = '') { 13777 const commentsWithHash = extractCommentsWithHash(cssText); 13778 cssText = stripComments(cssText); 13779 cssText = this._insertDirectives(cssText); 13780 13781 const scopedCssText = this._scopeCssText(cssText, selector, hostSelector); 13782 13783 return [scopedCssText, ...commentsWithHash].join('\n'); 13784 } 13785 13786 _insertDirectives(cssText) { 13787 cssText = this._insertPolyfillDirectivesInCssText(cssText); 13788 return this._insertPolyfillRulesInCssText(cssText); 13789 } 13790 /* 13791 * Process styles to convert native ShadowDOM rules that will trip 13792 * up the css parser; we rely on decorating the stylesheet with inert rules. 13793 * 13794 * For example, we convert this rule: 13795 * 13796 * polyfill-next-selector { content: ':host menu-item'; } 13797 * ::content menu-item { 13798 * 13799 * to this: 13800 * 13801 * scopeName menu-item { 13802 * 13803 **/ 13804 13805 13806 _insertPolyfillDirectivesInCssText(cssText) { 13807 // Difference with webcomponents.js: does not handle comments 13808 return cssText.replace(_cssContentNextSelectorRe, function (...m) { 13809 return m[2] + '{'; 13810 }); 13811 } 13812 /* 13813 * Process styles to add rules which will only apply under the polyfill 13814 * 13815 * For example, we convert this rule: 13816 * 13817 * polyfill-rule { 13818 * content: ':host menu-item'; 13819 * ... 13820 * } 13821 * 13822 * to this: 13823 * 13824 * scopeName menu-item {...} 13825 * 13826 **/ 13827 13828 13829 _insertPolyfillRulesInCssText(cssText) { 13830 // Difference with webcomponents.js: does not handle comments 13831 return cssText.replace(_cssContentRuleRe, (...m) => { 13832 const rule = m[0].replace(m[1], '').replace(m[2], ''); 13833 return m[4] + rule; 13834 }); 13835 } 13836 /* Ensure styles are scoped. Pseudo-scoping takes a rule like: 13837 * 13838 * .foo {... } 13839 * 13840 * and converts this to 13841 * 13842 * scopeName .foo { ... } 13843 */ 13844 13845 13846 _scopeCssText(cssText, scopeSelector, hostSelector) { 13847 const unscopedRules = this._extractUnscopedRulesFromCssText(cssText); // replace :host and :host-context -shadowcsshost and -shadowcsshost respectively 13848 13849 13850 cssText = this._insertPolyfillHostInCssText(cssText); 13851 cssText = this._convertColonHost(cssText); 13852 cssText = this._convertColonHostContext(cssText); 13853 cssText = this._convertShadowDOMSelectors(cssText); 13854 13855 if (scopeSelector) { 13856 cssText = this._scopeSelectors(cssText, scopeSelector, hostSelector); 13857 } 13858 13859 cssText = cssText + '\n' + unscopedRules; 13860 return cssText.trim(); 13861 } 13862 /* 13863 * Process styles to add rules which will only apply under the polyfill 13864 * and do not process via CSSOM. (CSSOM is destructive to rules on rare 13865 * occasions, e.g. -webkit-calc on Safari.) 13866 * For example, we convert this rule: 13867 * 13868 * @polyfill-unscoped-rule { 13869 * content: 'menu-item'; 13870 * ... } 13871 * 13872 * to this: 13873 * 13874 * menu-item {...} 13875 * 13876 **/ 13877 13878 13879 _extractUnscopedRulesFromCssText(cssText) { 13880 // Difference with webcomponents.js: does not handle comments 13881 let r = ''; 13882 let m; 13883 _cssContentUnscopedRuleRe.lastIndex = 0; 13884 13885 while ((m = _cssContentUnscopedRuleRe.exec(cssText)) !== null) { 13886 const rule = m[0].replace(m[2], '').replace(m[1], m[4]); 13887 r += rule + '\n\n'; 13888 } 13889 13890 return r; 13891 } 13892 /* 13893 * convert a rule like :host(.foo) > .bar { } 13894 * 13895 * to 13896 * 13897 * .foo<scopeName> > .bar 13898 */ 13899 13900 13901 _convertColonHost(cssText) { 13902 return cssText.replace(_cssColonHostRe, (_, hostSelectors, otherSelectors) => { 13903 if (hostSelectors) { 13904 const convertedSelectors = []; 13905 const hostSelectorArray = hostSelectors.split(',').map(p => p.trim()); 13906 13907 for (const hostSelector of hostSelectorArray) { 13908 if (!hostSelector) break; 13909 const convertedSelector = _polyfillHostNoCombinator + hostSelector.replace(_polyfillHost, '') + otherSelectors; 13910 convertedSelectors.push(convertedSelector); 13911 } 13912 13913 return convertedSelectors.join(','); 13914 } else { 13915 return _polyfillHostNoCombinator + otherSelectors; 13916 } 13917 }); 13918 } 13919 /* 13920 * convert a rule like :host-context(.foo) > .bar { } 13921 * 13922 * to 13923 * 13924 * .foo<scopeName> > .bar, .foo <scopeName> > .bar { } 13925 * 13926 * and 13927 * 13928 * :host-context(.foo:host) .bar { ... } 13929 * 13930 * to 13931 * 13932 * .foo<scopeName> .bar { ... } 13933 */ 13934 13935 13936 _convertColonHostContext(cssText) { 13937 return cssText.replace(_cssColonHostContextReGlobal, selectorText => { 13938 // We have captured a selector that contains a `:host-context` rule. 13939 // For backward compatibility `:host-context` may contain a comma separated list of selectors. 13940 // Each context selector group will contain a list of host-context selectors that must match 13941 // an ancestor of the host. 13942 // (Normally `contextSelectorGroups` will only contain a single array of context selectors.) 13943 const contextSelectorGroups = [[]]; // There may be more than `:host-context` in this selector so `selectorText` could look like: 13944 // `:host-context(.one):host-context(.two)`. 13945 // Execute `_cssColonHostContextRe` over and over until we have extracted all the 13946 // `:host-context` selectors from this selector. 13947 13948 let match; 13949 13950 while (match = _cssColonHostContextRe.exec(selectorText)) { 13951 // `match` = [':host-context(<selectors>)<rest>', <selectors>, <rest>] 13952 // The `<selectors>` could actually be a comma separated list: `:host-context(.one, .two)`. 13953 const newContextSelectors = (match[1] ?? '').trim().split(',').map(m => m.trim()).filter(m => m !== ''); // We must duplicate the current selector group for each of these new selectors. 13954 // For example if the current groups are: 13955 // ``` 13956 // [ 13957 // ['a', 'b', 'c'], 13958 // ['x', 'y', 'z'], 13959 // ] 13960 // ``` 13961 // And we have a new set of comma separated selectors: `:host-context(m,n)` then the new 13962 // groups are: 13963 // ``` 13964 // [ 13965 // ['a', 'b', 'c', 'm'], 13966 // ['x', 'y', 'z', 'm'], 13967 // ['a', 'b', 'c', 'n'], 13968 // ['x', 'y', 'z', 'n'], 13969 // ] 13970 // ``` 13971 13972 const contextSelectorGroupsLength = contextSelectorGroups.length; 13973 repeatGroups(contextSelectorGroups, newContextSelectors.length); 13974 13975 for (let i = 0; i < newContextSelectors.length; i++) { 13976 for (let j = 0; j < contextSelectorGroupsLength; j++) { 13977 contextSelectorGroups[j + i * contextSelectorGroupsLength].push(newContextSelectors[i]); 13978 } 13979 } // Update the `selectorText` and see repeat to see if there are more `:host-context`s. 13980 13981 13982 selectorText = match[2]; 13983 } // The context selectors now must be combined with each other to capture all the possible
13984 // selectors that `:host-context` can match. See `combineHostContextSelectors()` for more 13985 // info about how this is done. 13986 13987 13988 return contextSelectorGroups.map(contextSelectors => combineHostContextSelectors(contextSelectors, selectorText)).join(', '); 13989 }); 13990 } 13991 /* 13992 * Convert combinators like ::shadow and pseudo-elements like ::content 13993 * by replacing with space. 13994 */ 13995 13996 13997 _convertShadowDOMSelectors(cssText) { 13998 return _shadowDOMSelectorsRe.reduce((result, pattern) => result.replace(pattern, ' '), cssText); 13999 } // change a selector like 'div' to 'name div' 14000 14001 14002 _scopeSelectors(cssText, scopeSelector, hostSelector) { 14003 return processRules(cssText, rule => { 14004 let selector = rule.selector; 14005 let content = rule.content; 14006 14007 if (rule.selector[0] !== '@') { 14008 selector = this._scopeSelector(rule.selector, scopeSelector, hostSelector, this.strictStyling); 14009 } else if (rule.selector.startsWith('@media') || rule.selector.startsWith('@supports') || rule.selector.startsWith('@document') || rule.selector.startsWith('@layer')) { 14010 content = this._scopeSelectors(rule.content, scopeSelector, hostSelector); 14011 } else if (rule.selector.startsWith('@font-face') || rule.selector.startsWith('@page')) { 14012 content = this._stripScopingSelectors(rule.content); 14013 } 14014 14015 return new CssRule(selector, content); 14016 }); 14017 } 14018 /** 14019 * Handle a css text that is within a rule that should not contain scope selectors by simply 14020 * removing them! An example of such a rule is `@font-face`. 14021 * 14022 * `@font-face` rules cannot contain nested selectors. Nor can they be nested under a selector. 14023 * Normally this would be a syntax error by the author of the styles. But in some rare cases, such 14024 * as importing styles from a library, and applying `:host ::ng-deep` to the imported styles, we 14025 * can end up with broken css if the imported styles happen to contain @font-face rules. 14026 * 14027 * For example: 14028 * 14029 * ``` 14030 * :host ::ng-deep { 14031 * import 'some/lib/containing/font-face'; 14032 * } 14033 * 14034 * Similar logic applies to `@page` rules which can contain a particular set of properties, 14035 * as well as some specific at-rules. Since they can't be encapsulated, we have to strip 14036 * any scoping selectors from them. For more information: https://www.w3.org/TR/css-page-3 14037 * ``` 14038 */ 14039 14040 14041 _stripScopingSelectors(cssText) { 14042 return processRules(cssText, rule => { 14043 const selector = rule.selector.replace(_shadowDeepSelectors, ' ').replace(_polyfillHostNoCombinatorRe, ' '); 14044 return new CssRule(selector, rule.content); 14045 }); 14046 } 14047 14048 _scopeSelector(selector, scopeSelector, hostSelector, strict) { 14049 return selector.split(',').map(part => part.trim().split(_shadowDeepSelectors)).map(deepParts => { 14050 const [shallowPart, ...otherParts] = deepParts; 14051 14052 const applyScope = shallowPart => { 14053 if (this._selectorNeedsScoping(shallowPart, scopeSelector)) { 14054 return strict ? this._applyStrictSelectorScope(shallowPart, scopeSelector, hostSelector) : this._applySelectorScope(shallowPart, scopeSelector, hostSelector); 14055 } else { 14056 return shallowPart; 14057 } 14058 }; 14059 14060 return [applyScope(shallowPart), ...otherParts].join(' '); 14061 }).join(', '); 14062 } 14063 14064 _selectorNeedsScoping(selector, scopeSelector) { 14065 const re = this._makeScopeMatcher(scopeSelector); 14066 14067 return !re.test(selector); 14068 } 14069 14070 _makeScopeMatcher(scopeSelector) { 14071 const lre = /\[/g; 14072 const rre = /\]/g; 14073 scopeSelector = scopeSelector.replace(lre, '\\[').replace(rre, '\\]'); 14074 return new RegExp('^(' + scopeSelector + ')' + _selectorReSuffix, 'm'); 14075 } 14076 14077 _applySelectorScope(selector, scopeSelector, hostSelector) { 14078 // Difference from webcomponents.js: scopeSelector could not be an array 14079 return this._applySimpleSelectorScope(selector, scopeSelector, hostSelector); 14080 } // scope via name and [is=name] 14081 14082 14083 _applySimpleSelectorScope(selector, scopeSelector, hostSelector) { 14084 // In Android browser, the lastIndex is not reset when the regex is used in String.replace() 14085 _polyfillHostRe.lastIndex = 0; 14086 14087 if (_polyfillHostRe.test(selector)) { 14088 const replaceBy = this.strictStyling ? `[${hostSelector}]` : scopeSelector; 14089 return selector.replace(_polyfillHostNoCombinatorRe, (hnc, selector) => { 14090 return selector.replace(/([^:]*)(:*)(.*)/, (_, before, colon, after) => { 14091 return before + replaceBy + colon + after; 14092 }); 14093 }).replace(_polyfillHostRe, replaceBy + ' '); 14094 } 14095 14096 return scopeSelector + ' ' + selector; 14097 } // return a selector with [name] suffix on each simple selector 14098 // e.g. .foo.bar > .zot becomes .foo[name].bar[name] > .zot[name] /** @internal */ 14099 14100 14101 _applyStrictSelectorScope(selector, scopeSelector, hostSelector) { 14102 const isRe = /\[is=([^\]]*)\]/g; 14103 scopeSelector = scopeSelector.replace(isRe, (_, ...parts) => parts[0]); 14104 const attrName = '[' + scopeSelector + ']'; 14105 14106 const _scopeSelectorPart = p => { 14107 let scopedP = p.trim(); 14108 14109 if (!scopedP) { 14110 return ''; 14111 } 14112 14113 if (p.indexOf(_polyfillHostNoCombinator) > -1) { 14114 scopedP = this._applySimpleSelectorScope(p, scopeSelector, hostSelector); 14115 } else { 14116 // remove :host since it should be unnecessary 14117 const t = p.replace(_polyfillHostRe, ''); 14118 14119 if (t.length > 0) { 14120 const matches = t.match(/([^:]*)(:*)(.*)/); 14121 14122 if (matches) { 14123 scopedP = matches[1] + attrName + matches[2] + matches[3]; 14124 } 14125 } 14126 } 14127 14128 return scopedP; 14129 }; 14130 14131 const safeContent = new SafeSelector(selector); 14132 selector = safeContent.content(); 14133 let scopedSelector = ''; 14134 let startIndex = 0; 14135 let res; 14136 const sep = /( |>|\+|~(?!=))\s*/g; // If a selector appears before :host it should not be shimmed as it 14137 // matches on ancestor elements and not on elements in the host's shadow 14138 // `:host-context(div)` is transformed to 14139 // `-shadowcsshost-no-combinatordiv, div -shadowcsshost-no-combinator` 14140 // the `div` is not part of the component in the 2nd selectors and should not be scoped. 14141 // Historically `component-tag:host` was matching the component so we also want to preserve 14142 // this behavior to avoid breaking legacy apps (it should not match). 14143 // The behavior should be: 14144 // - `tag:host` -> `tag[h]` (this is to avoid breaking legacy apps, should not match anything) 14145 // - `tag :host` -> `tag [h]` (`tag` is not scoped because it's considered part of a 14146 // `:host-context(tag)`) 14147 14148 const hasHost = selector.indexOf(_polyfillHostNoCombinator) > -1; // Only scope parts after the first `-shadowcsshost-no-combinator` when it is present 14149 14150 let shouldScope = !hasHost; 14151 14152 while ((res = sep.exec(selector)) !== null) { 14153 const separator = res[1]; 14154 const part = selector.slice(startIndex, res.index).trim(); 14155 shouldScope = shouldScope || part.indexOf(_polyfillHostNoCombinator) > -1; 14156 const scopedPart = shouldScope ? _scopeSelectorPart(part) : part;
14157 scopedSelector += `${scopedPart} ${separator} `; 14158 startIndex = sep.lastIndex; 14159 } 14160 14161 const part = selector.substring(startIndex); 14162 shouldScope = shouldScope || part.indexOf(_polyfillHostNoCombinator) > -1; 14163 scopedSelector += shouldScope ? _scopeSelectorPart(part) : part; // replace the placeholders with their original values 14164 14165 return safeContent.restore(scopedSelector); 14166 } 14167 14168 _insertPolyfillHostInCssText(selector) { 14169 return selector.replace(_colonHostContextRe, _polyfillHostContext).replace(_colonHostRe, _polyfillHost); 14170 } 14171 14172} 14173 14174class SafeSelector { 14175 constructor(selector) { 14176 this.placeholders = []; 14177 this.index = 0; // Replaces attribute selectors with placeholders. 14178 // The WS in [attr="va lue"] would otherwise be interpreted as a selector separator. 14179 14180 selector = this._escapeRegexMatches(selector, /(\[[^\]]*\])/g); // CSS allows for certain special characters to be used in selectors if they're escaped. 14181 // E.g. `.foo:blue` won't match a class called `foo:blue`, because the colon denotes a 14182 // pseudo-class, but writing `.foo\:blue` will match, because the colon was escaped. 14183 // Replace all escape sequences (`\` followed by a character) with a placeholder so 14184 // that our handling of pseudo-selectors doesn't mess with them. 14185 14186 selector = this._escapeRegexMatches(selector, /(\\.)/g); // Replaces the expression in `:nth-child(2n + 1)` with a placeholder. 14187 // WS and "+" would otherwise be interpreted as selector separators. 14188 14189 this._content = selector.replace(/(:nth-[-\w]+)(\([^)]+\))/g, (_, pseudo, exp) => { 14190 const replaceBy = `__ph-${this.index}__`; 14191 this.placeholders.push(exp); 14192 this.index++; 14193 return pseudo + replaceBy; 14194 }); 14195 } 14196 14197 restore(content) { 14198 return content.replace(/__ph-(\d+)__/g, (_ph, index) => this.placeholders[+index]); 14199 } 14200 14201 content() { 14202 return this._content; 14203 } 14204 /** 14205 * Replaces all of the substrings that match a regex within a 14206 * special string (e.g. `__ph-0__`, `__ph-1__`, etc). 14207 */ 14208 14209 14210 _escapeRegexMatches(content, pattern) { 14211 return content.replace(pattern, (_, keep) => { 14212 const replaceBy = `__ph-${this.index}__`; 14213 this.placeholders.push(keep); 14214 this.index++; 14215 return replaceBy; 14216 }); 14217 } 14218 14219} 14220 14221const _cssContentNextSelectorRe = /polyfill-next-selector[^}]*content:[\s]*?(['"])(.*?)\1[;\s]*}([^{]*?){/gim; 14222const _cssContentRuleRe = /(polyfill-rule)[^}]*(content:[\s]*(['"])(.*?)\3)[;\s]*[^}]*}/gim; 14223const _cssContentUnscopedRuleRe = /(polyfill-unscoped-rule)[^}]*(content:[\s]*(['"])(.*?)\3)[;\s]*[^}]*}/gim; 14224const _polyfillHost = '-shadowcsshost'; // note: :host-context pre-processed to -shadowcsshostcontext. 14225 14226const _polyfillHostContext = '-shadowcsscontext'; 14227 14228const _parenSuffix = '(?:\\((' + '(?:\\([^)(]*\\)|[^)(]*)+?' + ')\\))?([^,{]*)'; 14229 14230const _cssColonHostRe = new RegExp(_polyfillHost + _parenSuffix, 'gim'); 14231 14232const _cssColonHostContextReGlobal = new RegExp(_polyfillHostContext + _parenSuffix, 'gim'); 14233 14234const _cssColonHostContextRe = new RegExp(_polyfillHostContext + _parenSuffix, 'im'); 14235 14236const _polyfillHostNoCombinator = _polyfillHost + '-no-combinator'; 14237 14238const _polyfillHostNoCombinatorRe = /-shadowcsshost-no-combinator([^\s]*)/; 14239const _shadowDOMSelectorsRe = [/::shadow/g, /::content/g, // Deprecated selectors 14240/\/shadow-deep\//g, /\/shadow\//g]; // The deep combinator is deprecated in the CSS spec 14241// Support for `>>>`, `deep`, `::ng-deep` is then also deprecated and will be removed in the future. 14242// see https://github.com/angular/angular/pull/17677 14243 14244const _shadowDeepSelectors = /(?:>>>)|(?:\/deep\/)|(?:::ng-deep)/g; 14245const _selectorReSuffix = '([>\\s~+[.,{:][\\s\\S]*)?$'; 14246const _polyfillHostRe = /-shadowcsshost/gim; 14247const _colonHostRe = /:host/gim; 14248const _colonHostContextRe = /:host-context/gim; 14249const _commentRe = /\/\*[\s\S]*?\*\//g; 14250 14251function stripComments(input) { 14252 return input.replace(_commentRe, ''); 14253} 14254 14255const _commentWithHashRe = /\/\*\s*#\s*source(Mapping)?URL=[\s\S]+?\*\//g; 14256 14257function extractCommentsWithHash(input) { 14258 return input.match(_commentWithHashRe) || []; 14259} 14260 14261const BLOCK_PLACEHOLDER = '%BLOCK%'; 14262const QUOTE_PLACEHOLDER = '%QUOTED%'; 14263const _ruleRe = /(\s*)([^;\{\}]+?)(\s*)((?:{%BLOCK%}?\s*;?)|(?:\s*;))/g; 14264const _quotedRe = /%QUOTED%/g; 14265const CONTENT_PAIRS = new Map([['{', '}']]); 14266const QUOTE_PAIRS = new Map([[`"`, `"`], [`'`, `'`]]); 14267 14268class CssRule { 14269 constructor(selector, content) { 14270 this.selector = selector; 14271 this.content = content; 14272 } 14273 14274} 14275
14276function processRules(input, ruleCallback) { 14277 const inputWithEscapedQuotes = escapeBlocks(input, QUOTE_PAIRS, QUOTE_PLACEHOLDER); 14278 const inputWithEscapedBlocks = escapeBlocks(inputWithEscapedQuotes.escapedString, CONTENT_PAIRS, BLOCK_PLACEHOLDER); 14279 let nextBlockIndex = 0; 14280 let nextQuoteIndex = 0; 14281 return inputWithEscapedBlocks.escapedString.replace(_ruleRe, (...m) => { 14282 const selector = m[2]; 14283 let content = ''; 14284 let suffix = m[4]; 14285 let contentPrefix = ''; 14286 14287 if (suffix && suffix.startsWith('{' + BLOCK_PLACEHOLDER)) { 14288 content = inputWithEscapedBlocks.blocks[nextBlockIndex++]; 14289 suffix = suffix.substring(BLOCK_PLACEHOLDER.length + 1); 14290 contentPrefix = '{'; 14291 } 14292 14293 const rule = ruleCallback(new CssRule(selector, content)); 14294 return `${m[1]}${rule.selector}${m[3]}${contentPrefix}${rule.content}${suffix}`; 14295 }).replace(_quotedRe, () => inputWithEscapedQuotes.blocks[nextQuoteIndex++]); 14296} 14297 14298class StringWithEscapedBlocks { 14299 constructor(escapedString, blocks) { 14300 this.escapedString = escapedString; 14301 this.blocks = blocks; 14302 } 14303 14304} 14305 14306function escapeBlocks(input, charPairs, placeholder) { 14307 const resultParts = []; 14308 const escapedBlocks = []; 14309 let openCharCount = 0; 14310 let nonBlockStartIndex = 0; 14311 let blockStartIndex = -1; 14312 let openChar; 14313 let closeChar; 14314 14315 for (let i = 0; i < input.length; i++) { 14316 const char = input[i]; 14317 14318 if (char === '\\') { 14319 i++; 14320 } else if (char === closeChar) { 14321 openCharCount--; 14322 14323 if (openCharCount === 0) { 14324 escapedBlocks.push(input.substring(blockStartIndex, i)); 14325 resultParts.push(placeholder); 14326 nonBlockStartIndex = i; 14327 blockStartIndex = -1; 14328 openChar = closeChar = undefined; 14329 } 14330 } else if (char === openChar) { 14331 openCharCount++; 14332 } else if (openCharCount === 0 && charPairs.has(char)) { 14333 openChar = char; 14334 closeChar = charPairs.get(char); 14335 openCharCount = 1; 14336 blockStartIndex = i + 1; 14337 resultParts.push(input.substring(nonBlockStartIndex, blockStartIndex)); 14338 } 14339 } 14340 14341 if (blockStartIndex !== -1) { 14342 escapedBlocks.push(input.substring(blockStartIndex)); 14343 resultParts.push(placeholder); 14344 } else { 14345 resultParts.push(input.substring(nonBlockStartIndex)); 14346 } 14347 14348 return new StringWithEscapedBlocks(resultParts.join(''), escapedBlocks); 14349} 14350/** 14351 * Combine the `contextSelectors` with the `hostMarker` and the `otherSelectors` 14352 * to create a selector that matches the same as `:host-context()`. 14353 * 14354 * Given a single context selector `A` we need to output selectors that match on the host and as an 14355 * ancestor of the host: 14356 * 14357 * ``` 14358 * A <hostMarker>, A<hostMarker> {} 14359 * ``` 14360 * 14361 * When there is more than one context selector we also have to create combinations of those 14362 * selectors with each other. For example if there are `A` and `B` selectors the output is: 14363 * 14364 * ``` 14365 * AB<hostMarker>, AB <hostMarker>, A B<hostMarker>, 14366 * B A<hostMarker>, A B <hostMarker>, B A <hostMarker> {} 14367 * ``` 14368 * 14369 * And so on... 14370 * 14371 * @param hostMarker the string that selects the host element. 14372 * @param contextSelectors an array of context selectors that will be combined. 14373 * @param otherSelectors the rest of the selectors that are not context selectors. 14374 */ 14375 14376 14377function combineHostContextSelectors(contextSelectors, otherSelectors) { 14378 const hostMarker = _polyfillHostNoCombinator; 14379 _polyfillHostRe.lastIndex = 0; // reset the regex to ensure we get an accurate test 14380 14381 const otherSelectorsHasHost = _polyfillHostRe.test(otherSelectors); // If there are no context selectors then just output a host marker 14382 14383 14384 if (contextSelectors.length === 0) { 14385 return hostMarker + otherSelectors; 14386 } 14387 14388 const combined = [contextSelectors.pop() || '']; 14389 14390 while (contextSelectors.length > 0) { 14391 const length = combined.length; 14392 const contextSelector = contextSelectors.pop(); 14393 14394 for (let i = 0; i < length; i++) { 14395 const previousSelectors = combined[i]; // Add the new selector as a descendant of the previous selectors 14396 14397 combined[length * 2 + i] = previousSelectors + ' ' + contextSelector; // Add the new selector as an ancestor of the previous selectors 14398 14399 combined[length + i] = contextSelector + ' ' + previousSelectors; // Add the new selector to act on the same element as the previous selectors 14400 14401 combined[i] = contextSelector + previousSelectors; 14402 } 14403 } // Finally connect the selector to the `hostMarker`s: either acting directly on the host 14404 // (A<hostMarker>) or as an ancestor (A <hostMarker>). 14405 14406 14407 return combined.map(s => otherSelectorsHasHost ? `${s}${otherSelectors}` : `${s}${hostMarker}${otherSelectors}, ${s} ${hostMarker}${otherSelectors}`).join(','); 14408} 14409/** 14410 * Mutate the given `groups` array so that there are `multiples` clones of the original array 14411 * stored. 14412 * 14413 * For example `repeatGroups([a, b], 3)` will result in `[a, b, a, b, a, b]` - but importantly the 14414 * newly added groups will be clones of the original. 14415 *
14416 * @param groups An array of groups of strings that will be repeated. This array is mutated 14417 * in-place. 14418 * @param multiples The number of times the current groups should appear. 14419 */ 14420 14421 14422function repeatGroups(groups, multiples) { 14423 const length = groups.length; 14424 14425 for (let i = 1; i < multiples; i++) { 14426 for (let j = 0; j < length; j++) { 14427 groups[j + i * length] = groups[j].slice(0); 14428 } 14429 } 14430} 14431/** 14432 * @license 14433 * Copyright Google LLC All Rights Reserved. 14434 * 14435 * Use of this source code is governed by an MIT-style license that can be 14436 * found in the LICENSE file at https://angular.io/license 14437 */ 14438 14439/** 14440 * Parses string representation of a style and converts it into object literal. 14441 * 14442 * @param value string representation of style as used in the `style` attribute in HTML. 14443 * Example: `color: red; height: auto`. 14444 * @returns An array of style property name and value pairs, e.g. `['color', 'red', 'height', 14445 * 'auto']` 14446 */ 14447 14448 14449function parse(value) { 14450 // we use a string array here instead of a string map 14451 // because a string-map is not guaranteed to retain the 14452 // order of the entries whereas a string array can be 14453 // constructed in a [key, value, key, value] format. 14454 const styles = []; 14455 let i = 0; 14456 let parenDepth = 0; 14457 let quote = 0 14458 /* Char.QuoteNone */ 14459 ; 14460 let valueStart = 0; 14461 let propStart = 0; 14462 let currentProp = null; 14463 let valueHasQuotes = false; 14464 14465 while (i < value.length) { 14466 const token = value.charCodeAt(i++); 14467 14468 switch (token) { 14469 case 40 14470 /* Char.OpenParen */ 14471 : 14472 parenDepth++; 14473 break; 14474 14475 case 41 14476 /* Char.CloseParen */ 14477 : 14478 parenDepth--; 14479 break; 14480 14481 case 39 14482 /* Char.QuoteSingle */ 14483 : 14484 // valueStart needs to be there since prop values don't 14485 // have quotes in CSS 14486 valueHasQuotes = valueHasQuotes || valueStart > 0; 14487 14488 if (quote === 0 14489 /* Char.QuoteNone */ 14490 ) { 14491 quote = 39 14492 /* Char.QuoteSingle */ 14493 ; 14494 } else if (quote === 39 14495 /* Char.QuoteSingle */ 14496 && value.charCodeAt(i - 1) !== 92 14497 /* Char.BackSlash */ 14498 ) { 14499 quote = 0 14500 /* Char.QuoteNone */ 14501 ; 14502 } 14503 14504 break; 14505 14506 case 34 14507 /* Char.QuoteDouble */ 14508 : 14509 // same logic as above 14510 valueHasQuotes = valueHasQuotes || valueStart > 0; 14511 14512 if (quote === 0 14513 /* Char.QuoteNone */ 14514 ) { 14515 quote = 34 14516 /* Char.QuoteDouble */ 14517 ; 14518 } else if (quote === 34 14519 /* Char.QuoteDouble */ 14520 && value.charCodeAt(i - 1) !== 92 14521 /* Char.BackSlash */ 14522 ) { 14523 quote = 0 14524 /* Char.QuoteNone */ 14525 ; 14526 } 14527 14528 break; 14529 14530 case 58 14531 /* Char.Colon */ 14532 : 14533 if (!currentProp && parenDepth === 0 && quote === 0 14534 /* Char.QuoteNone */ 14535 ) { 14536 currentProp = hyphenate(value.substring(propStart, i - 1).trim()); 14537 valueStart = i; 14538 } 14539 14540 break; 14541 14542 case 59 14543 /* Char.Semicolon */ 14544 : 14545 if (currentProp && valueStart > 0 && parenDepth === 0 && quote === 0 14546 /* Char.QuoteNone */ 14547 ) { 14548 const styleVal = value.substring(valueStart, i - 1).trim(); 14549 styles.push(currentProp, valueHasQuotes ? stripUnnecessaryQuotes(styleVal) : styleVal); 14550 propStart = i; 14551 valueStart = 0; 14552 currentProp = null; 14553 valueHasQuotes = false; 14554 } 14555 14556 break; 14557 } 14558 } 14559 14560 if (currentProp && valueStart) { 14561 const styleVal = value.slice(valueStart).trim(); 14562 styles.push(currentProp, valueHasQuotes ? stripUnnecessaryQuotes(styleVal) : styleVal); 14563 } 14564 14565 return styles; 14566} 14567 14568function stripUnnecessaryQuotes(value) { 14569 const qS = value.charCodeAt(0); 14570 const qE = value.charCodeAt(value.length - 1); 14571 14572 if (qS == qE && (qS == 39 14573 /* Char.QuoteSingle */ 14574 || qS == 34 14575 /* Char.QuoteDouble */ 14576 )) { 14577 const tempValue = value.substring(1, value.length - 1); // special case to avoid using a multi-quoted string that was just chomped 14578 // (e.g. `font-family: "Verdana", "sans-serif"`) 14579 14580 if (tempValue.indexOf('\'') == -1 && tempValue.indexOf('"') == -1) { 14581 value = tempValue; 14582 } 14583 } 14584 14585 return value; 14586} 14587 14588function hyphenate(value) { 14589 return value.replace(/[a-z][A-Z]/g, v => { 14590 return v.charAt(0) + '-' + v.charAt(1); 14591 }).toLowerCase(); 14592} 14593 14594const IMPORTANT_FLAG = '!important'; 14595/** 14596 * Minimum amount of binding slots required in the runtime for style/class bindings. 14597 * 14598 * Styling in Angular uses up two slots in the runtime LView/TData data structures to 14599 * record binding data, property information and metadata. 14600 * 14601 * When a binding is registered it will place the following information in the `LView`: 14602 * 14603 * slot 1) binding value 14604 * slot 2) cached value (all other values collected before it in string form) 14605 * 14606 * When a binding is registered it will place the following information in the `TData`: 14607 * 14608 * slot 1) prop name 14609 * slot 2) binding index that points to the previous style/class binding (and some extra config 14610 * values) 14611 * 14612 * Let's imagine we have a binding that looks like so: 14613 * 14614 * ``` 14615 * <div [style.width]="x" [style.height]="y"> 14616 * ``` 14617 * 14618 * Our `LView` and `TData` data-structures look like so: 14619 * 14620 * ```typescript 14621 * LView = [ 14622 * // ... 14623 * x, // value of x 14624 * "width: x", 14625 * 14626 * y, // value of y 14627 * "width: x; height: y", 14628 * // ... 14629 * ]; 14630 * 14631 * TData = [ 14632 * // ... 14633 * "width", // binding slot 20 14634 * 0, 14635 *
14636 * "height", 14637 * 20, 14638 * // ... 14639 * ]; 14640 * ``` 14641 * 14642 * */ 14643 14644const MIN_STYLING_BINDING_SLOTS_REQUIRED = 2; 14645/** 14646 * Produces creation/update instructions for all styling bindings (class and style) 14647 * 14648 * It also produces the creation instruction to register all initial styling values 14649 * (which are all the static class="..." and style="..." attribute values that exist 14650 * on an element within a template). 14651 * 14652 * The builder class below handles producing instructions for the following cases: 14653 * 14654 * - Static style/class attributes (style="..." and class="...") 14655 * - Dynamic style/class map bindings ([style]="map" and [class]="map|string") 14656 * - Dynamic style/class property bindings ([style.prop]="exp" and [class.name]="exp") 14657 * 14658 * Due to the complex relationship of all of these cases, the instructions generated 14659 * for these attributes/properties/bindings must be done so in the correct order. The 14660 * order which these must be generated is as follows: 14661 * 14662 * if (createMode) { 14663 * styling(...) 14664 * } 14665 * if (updateMode) { 14666 * styleMap(...) 14667 * classMap(...) 14668 * styleProp(...) 14669 * classProp(...) 14670 * } 14671 * 14672 * The creation/update methods within the builder class produce these instructions. 14673 */ 14674 14675class StylingBuilder { 14676 constructor(_directiveExpr) { 14677 this._directiveExpr = _directiveExpr; 14678 /** Whether or not there are any static styling values present */ 14679 14680 this._hasInitialValues = false; 14681 /** 14682 * Whether or not there are any styling bindings present 14683 * (i.e. `[style]`, `[class]`, `[style.prop]` or `[class.name]`) 14684 */ 14685 14686 this.hasBindings = false; 14687 this.hasBindingsWithPipes = false; 14688 /** the input for [class] (if it exists) */ 14689 14690 this._classMapInput = null; 14691 /** the input for [style] (if it exists) */ 14692 14693 this._styleMapInput = null; 14694 /** an array of each [style.prop] input */ 14695 14696 this._singleStyleInputs = null; 14697 /** an array of each [class.name] input */ 14698 14699 this._singleClassInputs = null; 14700 this._lastStylingInput = null; 14701 this._firstStylingInput = null; // maps are used instead of hash maps because a Map will 14702 // retain the ordering of the keys 14703 14704 /** 14705 * Represents the location of each style binding in the template 14706 * (e.g. `<div [style.width]="w" [style.height]="h">` implies 14707 * that `width=0` and `height=1`) 14708 */ 14709 14710 this._stylesIndex = new Map(); 14711 /** 14712 * Represents the location of each class binding in the template 14713 * (e.g. `<div [class.big]="b" [class.hidden]="h">` implies 14714 * that `big=0` and `hidden=1`) 14715 */ 14716 14717 this._classesIndex = new Map(); 14718 this._initialStyleValues = []; 14719 this._initialClassValues = []; 14720 } 14721 /** 14722 * Registers a given input to the styling builder to be later used when producing AOT code. 14723 * 14724 * The code below will only accept the input if it is somehow tied to styling (whether it be 14725 * style/class bindings or static style/class attributes). 14726 */ 14727 14728 14729 registerBoundInput(input) { 14730 // [attr.style] or [attr.class] are skipped in the code below, 14731 // they should not be treated as styling-based bindings since 14732 // they are intended to be written directly to the attr and 14733 // will therefore skip all style/class resolution that is present 14734 // with style="", [style]="" and [style.prop]="", class="", 14735 // [class.prop]="". [class]="" assignments 14736 let binding = null; 14737 let name = input.name; 14738 14739 switch (input.type) { 14740 case 0 14741 /* BindingType.Property */ 14742 : 14743 binding = this.registerInputBasedOnName(name, input.value, input.sourceSpan); 14744 break; 14745 14746 case 3 14747 /* BindingType.Style */ 14748 : 14749 binding = this.registerStyleInput(name, false, input.value, input.sourceSpan, input.unit); 14750 break; 14751 14752 case 2 14753 /* BindingType.Class */ 14754 : 14755 binding = this.registerClassInput(name, false, input.value, input.sourceSpan); 14756 break; 14757 } 14758 14759 return binding ? true : false; 14760 } 14761 14762 registerInputBasedOnName(name, expression, sourceSpan) { 14763 let binding = null; 14764 const prefix = name.substring(0, 6); 14765 const isStyle = name === 'style' || prefix === 'style.' || prefix === 'style!'; 14766 const isClass = !isStyle && (name === 'class' || prefix === 'class.' || prefix === 'class!'); 14767 14768 if (isStyle || isClass) { 14769 const isMapBased = name.charAt(5) !== '.'; // style.prop or class.prop makes this a no 14770 14771 const property = name.slice(isMapBased ? 5 : 6); // the dot explains why there's a +1 14772 14773 if (isStyle) { 14774 binding = this.registerStyleInput(property, isMapBased, expression, sourceSpan); 14775 } else { 14776 binding = this.registerClassInput(property, isMapBased, expression, sourceSpan); 14777 } 14778 } 14779 14780 return binding; 14781 } 14782 14783 registerStyleInput(name, isMapBased, value, sourceSpan, suffix) { 14784 if (isEmptyExpression(value)) { 14785 return null; 14786 } // CSS custom properties are case-sensitive so we shouldn't normalize them. 14787 // See: https://www.w3.org/TR/css-variables-1/#defining-variables 14788 14789 14790 if (!isCssCustomProperty(name)) { 14791 name = hyphenate(name); 14792 } 14793 14794 const { 14795 property, 14796 hasOverrideFlag, 14797 suffix: bindingSuffix 14798 } = parseProperty(name); 14799 suffix = typeof suffix === 'string' && suffix.length !== 0 ? suffix : bindingSuffix; 14800 const entry = { 14801 name: property, 14802 suffix: suffix, 14803 value, 14804 sourceSpan, 14805 hasOverrideFlag 14806 }; 14807 14808 if (isMapBased) { 14809 this._styleMapInput = entry; 14810 } else { 14811 (this._singleStyleInputs = this._singleStyleInputs || []).push(entry); 14812 registerIntoMap(this._stylesIndex, property); 14813 } 14814 14815 this._lastStylingInput = entry; 14816 this._firstStylingInput = this._firstStylingInput || entry; 14817 14818 this._checkForPipes(value); 14819 14820 this.hasBindings = true; 14821 return entry; 14822 } 14823 14824 registerClassInput(name, isMapBased, value, sourceSpan) { 14825 if (isEmptyExpression(value)) { 14826 return null; 14827 } 14828 14829 const { 14830 property, 14831 hasOverrideFlag 14832 } = parseProperty(name); 14833 const entry = { 14834 name: property, 14835 value, 14836 sourceSpan, 14837 hasOverrideFlag, 14838 suffix: null 14839 }; 14840 14841 if (isMapBased) { 14842 this._classMapInput = entry; 14843 } else { 14844 (this._singleClassInputs = this._singleClassInputs || []).push(entry); 14845 registerIntoMap(this._classesIndex, property); 14846 } 14847 14848 this._lastStylingInput = entry; 14849 this._firstStylingInput = this._firstStylingInput || entry; 14850 14851 this._checkForPipes(value); 14852 14853 this.hasBindings = true; 14854 return entry; 14855 } 14856 14857 _checkForPipes(value) { 14858 if (value instanceof ASTWithSource && value.ast instanceof BindingPipe) { 14859 this.hasBindingsWithPipes = true; 14860 } 14861 } 14862 /** 14863 * Registers the element's static style string value to the builder. 14864 * 14865 * @param value the style string (e.g. `width:100px; height:200px;`) 14866 */ 14867 14868 14869 registerStyleAttr(value) { 14870 this._initialStyleValues = parse(value); 14871 this._hasInitialValues = true; 14872 } 14873 /** 14874 * Registers the element's static class string value to the builder. 14875 * 14876 * @param value the className string (e.g. `disabled gold zoom`) 14877 */ 14878 14879 14880 registerClassAttr(value) { 14881 this._initialClassValues = value.trim().split(/\s+/g); 14882 this._hasInitialValues = true; 14883 } 14884 /** 14885 * Appends all styling-related expressions to the provided attrs array. 14886 * 14887 * @param attrs an existing array where each of the styling expressions 14888 * will be inserted into. 14889 */ 14890 14891 14892 populateInitialStylingAttrs(attrs) { 14893 // [CLASS_MARKER, 'foo', 'bar', 'baz' ...] 14894 if (this._initialClassValues.length) { 14895 attrs.push(literal(1 14896 /* AttributeMarker.Classes */ 14897 )); 14898 14899 for (let i = 0; i < this._initialClassValues.length; i++) { 14900 attrs.push(literal(this._initialClassValues[i])); 14901 } 14902 } // [STYLE_MARKER, 'width', '200px', 'height', '100px', ...] 14903 14904 14905 if (this._initialStyleValues.length) { 14906 attrs.push(literal(2 14907 /* AttributeMarker.Styles */ 14908 )); 14909 14910 for (let i = 0; i < this._initialStyleValues.length; i += 2) { 14911 attrs.push(literal(this._initialStyleValues[i]), literal(this._initialStyleValues[i + 1])
14911); 14912 } 14913 } 14914 } 14915 /** 14916 * Builds an instruction with all the expressions and parameters for `elementHostAttrs`. 14917 * 14918 * The instruction generation code below is used for producing the AOT statement code which is 14919 * responsible for registering initial styles (within a directive hostBindings' creation block), 14920 * as well as any of the provided attribute values, to the directive host element. 14921 */ 14922 14923 14924 assignHostAttrs(attrs, definitionMap) { 14925 if (this._directiveExpr && (attrs.length || this._hasInitialValues)) { 14926 this.populateInitialStylingAttrs(attrs); 14927 definitionMap.set('hostAttrs', literalArr(attrs)); 14928 } 14929 } 14930 /** 14931 * Builds an instruction with all the expressions and parameters for `classMap`. 14932 * 14933 * The instruction data will contain all expressions for `classMap` to function 14934 * which includes the `[class]` expression params. 14935 */ 14936 14937 14938 buildClassMapInstruction(valueConverter) { 14939 if (this._classMapInput) { 14940 return this._buildMapBasedInstruction(valueConverter, true, this._classMapInput); 14941 } 14942 14943 return null; 14944 } 14945 /** 14946 * Builds an instruction with all the expressions and parameters for `styleMap`. 14947 * 14948 * The instruction data will contain all expressions for `styleMap` to function 14949 * which includes the `[style]` expression params. 14950 */ 14951 14952 14953 buildStyleMapInstruction(valueConverter) { 14954 if (this._styleMapInput) { 14955 return this._buildMapBasedInstruction(valueConverter, false, this._styleMapInput); 14956 } 14957 14958 return null; 14959 } 14960 14961 _buildMapBasedInstruction(valueConverter, isClassBased, stylingInput) { 14962 // each styling binding value is stored in the LView 14963 // map-based bindings allocate two slots: one for the 14964 // previous binding value and another for the previous 14965 // className or style attribute value. 14966 let totalBindingSlotsRequired = MIN_STYLING_BINDING_SLOTS_REQUIRED; // these values must be outside of the update block so that they can 14967 // be evaluated (the AST visit call) during creation time so that any 14968 // pipes can be picked up in time before the template is built 14969 14970 const mapValue = stylingInput.value.visit(valueConverter); 14971 let reference; 14972 14973 if (mapValue instanceof Interpolation) { 14974 totalBindingSlotsRequired += mapValue.expressions.length; 14975 reference = isClassBased ? getClassMapInterpolationExpression(mapValue) : getStyleMapInterpolationExpression(mapValue); 14976 } else { 14977 reference = isClassBased ? Identifiers.classMap : Identifiers.styleMap; 14978 } 14979 14980 return { 14981 reference, 14982 calls: [{ 14983 supportsInterpolation: true, 14984 sourceSpan: stylingInput.sourceSpan, 14985 allocateBindingSlots: totalBindingSlotsRequired, 14986 params: convertFn => { 14987 const convertResult = convertFn(mapValue); 14988 const params = Array.isArray(convertResult) ? convertResult : [convertResult]; 14989 return params; 14990 } 14991 }] 14992 }; 14993 } 14994 14995 _buildSingleInputs(reference, inputs, valueConverter, getInterpolationExpressionFn, isClassBased) { 14996 const instructions = []; 14997 inputs.forEach(input => { 14998 const previousInstruction = instructions[instructions.length - 1]; 14999 const value = input.value.visit(valueConverter); 15000 let referenceForCall = reference; // each styling binding value is stored in the LView 15001 // but there are two values stored for each binding: 15002 // 1) the value itself 15003 // 2) an intermediate value (concatenation of style up to this point). 15004 // We need to store the intermediate value so that we don't allocate 15005 // the strings on each CD. 15006 15007 let totalBindingSlotsRequired = MIN_STYLING_BINDING_SLOTS_REQUIRED; 15008 15009 if (value instanceof Interpolation) { 15010 totalBindingSlotsRequired += value.expressions.length; 15011 15012 if (getInterpolationExpressionFn) { 15013 referenceForCall = getInterpolationExpressionFn(value); 15014 } 15015 } 15016 15017 const call = { 15018 sourceSpan: input.sourceSpan, 15019 allocateBindingSlots: totalBindingSlotsRequired, 15020 supportsInterpolation: !!getInterpolationExpressionFn, 15021 params: convertFn => { 15022 // params =>
15022 stylingProp(propName, value, suffix) 15023 const params = []; 15024 params.push(literal(input.name)); 15025 const convertResult = convertFn(value); 15026 15027 if (Array.isArray(convertResult)) { 15028 params.push(...convertResult); 15029 } else { 15030 params.push(convertResult); 15031 } // [style.prop] bindings may use suffix values (e.g. px, em, etc...), therefore, 15032 // if that is detected then we need to pass that in as an optional param. 15033 15034 15035 if (!isClassBased && input.suffix !== null) { 15036 params.push(literal(input.suffix)); 15037 } 15038 15039 return params; 15040 } 15041 }; // If we ended up generating a call to the same instruction as the previous styling property 15042 // we can chain the calls together safely to save some bytes, otherwise we have to generate 15043 // a separate instruction call. This is primarily a concern with interpolation instructions 15044 // where we may start off with one `reference`, but end up using another based on the 15045 // number of interpolations. 15046 15047 if (previousInstruction && previousInstruction.reference === referenceForCall) { 15048 previousInstruction.calls.push(call); 15049 } else { 15050 instructions.push({ 15051 reference: referenceForCall, 15052 calls: [call] 15053 }); 15054 } 15055 }); 15056 return instructions; 15057 } 15058 15059 _buildClassInputs(valueConverter) { 15060 if (this._singleClassInputs) { 15061 return this._buildSingleInputs(Identifiers.classProp, this._singleClassInputs, valueConverter, null, true); 15062 } 15063 15064 return []; 15065 } 15066 15067 _buildStyleInputs(valueConverter) { 15068 if (this._singleStyleInputs) { 15069 return this._buildSingleInputs(Identifiers.styleProp, this._singleStyleInputs, valueConverter, getStylePropInterpolationExpression, false); 15070 } 15071 15072 return []; 15073 } 15074 /** 15075 * Constructs all instructions which contain the expressions that will be placed 15076 * into the update block of a template function or a directive hostBindings function. 15077 */ 15078 15079 15080 buildUpdateLevelInstructions(valueConverter) { 15081 const instructions = []; 15082 15083 if (this.hasBindings) { 15084 const styleMapInstruction = this.buildStyleMapInstruction(valueConverter); 15085 15086 if (styleMapInstruction) { 15087 instructions.push(styleMapInstruction); 15088 } 15089 15090 const classMapInstruction = this.buildClassMapInstruction(valueConverter); 15091 15092 if (classMapInstruction) { 15093 instructions.push(classMapInstruction); 15094 } 15095 15096 instructions.push(...this._buildStyleInputs(valueConverter)); 15097 instructions.push(...this._buildClassInputs(valueConverter)); 15098 } 15099 15100 return instructions; 15101 } 15102 15103} 15104 15105function registerIntoMap(map, key) { 15106 if (!map.has(key)) { 15107 map.set(key, map.size); 15108 } 15109} 15110 15111function parseProperty(name) { 15112 let hasOverrideFlag = false; 15113 const overrideIndex = name.indexOf(IMPORTANT_FLAG); 15114 15115 if (overrideIndex !== -1) { 15116 name = overrideIndex > 0 ? name.substring(0, overrideIndex) : ''; 15117 hasOverrideFlag = true; 15118 } 15119 15120 let suffix = null; 15121 let property = name; 15122 const unitIndex = name.lastIndexOf('.'); 15123 15124 if (unitIndex > 0) { 15125 suffix = name.slice(unitIndex + 1); 15126 property = name.substring(0, unitIndex); 15127 } 15128 15129 return { 15130 property, 15131 suffix, 15132 hasOverrideFlag 15133 }; 15134} 15135/** 15136 * Gets the instruction to generate for an interpolated class map. 15137 * @param interpolation An Interpolation AST 15138 */ 15139 15140 15141function getClassMapInterpolationExpression(interpolation) { 15142 switch (getInterpolationArgsLength(interpolation)) { 15143 case 1: 15144 return Identifiers.classMap; 15145 15146 case 3: 15147 return Identifiers.classMapInterpolate1; 15148 15149 case 5: 15150 return Identifiers.classMapInterpolate2; 15151 15152 case 7: 15153 return Identifiers.classMapInterpolate3; 15154 15155 case 9: 15156 return Identifiers.classMapInterpolate4; 15157 15158 case 11: 15159 return Identifiers.classMapInterpolate5; 15160 15161 case 13: 15162 return Identifiers.classMapInterpolate6; 15163 15164 case 15: 15165 return Identifiers.classMapInterpolate7; 15166 15167 case 17: 15168 return Identifiers.classMapInterpolate8; 15169 15170 default: 15171 return Identifiers.classMapInterpolateV; 15172 } 15173} 15174/** 15175 * Gets the instruction to generate for an interpolated style map. 15176 * @param interpolation An Interpolation AST 15177 */ 15178 15179 15180function getStyleMapInterpolationExpression(interpolation) { 15181 switch (getInterpolationArgsLength(interpolation)) { 15182 case 1: 15183 return Identifiers.styleMap; 15184 15185 case 3: 15186 return Identifiers.styleMapInterpolate1; 15187 15188 case 5: 15189 return Identifiers.styleMapInterpolate2; 15190 15191 case 7: 15192 return Identifiers.styleMapInterpolate3; 15193 15194 case 9: 15195 return Identifiers.styleMapInterpolate4; 15196 15197 case 11: 15198 return Identifiers.styleMapInterpolate5; 15199 15200 case 13: 15201 return Identifiers.styleMapInterpolate6; 15202 15203 case 15: 15204 return Identifiers.styleMapInterpolate7; 15205 15206 case 17: 15207 return Identifiers.styleMapInterpolate8; 15208 15209 default: 15210 return Identifiers.styleMapInterpolateV; 15211 } 15212} 15213/** 15214 * Gets the instruction to generate for an interpolated style prop. 15215 * @param interpolation An Interpolation AST 15216 */ 15217 15218 15219function getStylePropInterpolationExpression(interpolation) { 15220 switch (getInterpolationArgsLength(interpolation)) { 15221 case 1: 15222 return Identifiers.styleProp; 15223 15224 case 3: 15225 return Identifiers.stylePropInterpolate1; 15226 15227 case 5: 15228 return Identifiers.stylePropInterpolate2; 15229 15230 case 7: 15231 return Identifiers.stylePropInterpolate3; 15232 15233 case 9: 15234 return Identifiers.stylePropInterpolate4; 15235 15236 case 11: 15237 return Identifiers.stylePropInterpolate5; 15238 15239 case 13: 15240 return Identifiers.stylePropInterpolate6; 15241 15242 case 15: 15243 return Identifiers.stylePropInterpolate7; 15244 15245 case 17: 15246 return Identifiers.stylePropInterpolate8; 15247 15248 default: 15249 return Identifiers.stylePropInterpolateV; 15250 } 15251} 15252/** 15253 * Checks whether property name is a custom CSS property. 15254 * See: https://www.w3.org/TR/css-variables-1 15255 */ 15256 15257 15258function isCssCustomProperty(name) { 15259 return name.startsWith('--'); 15260} 15261 15262function isEmptyExpression(ast) { 15263 if (ast instanceof ASTWithSource) { 15264 ast = ast.ast; 15265 } 15266 15267 return ast instanceof EmptyExpr; 15268} 15269/** 15270 * @license 15271 * Copyright Google LLC All Rights Reserved. 15272 * 15273 * Use of this source code is governed by an MIT-style license that can be 15274 * found in the LICENSE file at https://angular.io/license 15275 */ 15276 15277 15278var TokenType; 15279 15280(function (TokenType) { 15281 TokenType[TokenType["Character"] = 0] = "Character"; 15282 TokenType[TokenType["Identifier"] = 1] = "Identifier"; 15283 TokenType[TokenType["PrivateIdentifier"] = 2] = "PrivateIdentifier"; 15284 TokenType[TokenType["Keyword"] = 3] = "Keyword"; 15285 TokenType[TokenType["String"] = 4] = "String"; 15286 TokenType[TokenType["Operator"] = 5] = "Operator"; 15287 TokenType[TokenType["Number"] = 6] = "Number"; 15288 TokenType[TokenType["Error"] = 7] = "Error"; 15289})(TokenType || (TokenType = {})); 15290 15291const KEYWORDS = ['var', 'let', 'as', 'null', 'undefined', 'true', 'false', 'if', 'else', 'this']; 15292 15293class Lexer { 15294 tokenize(text) { 15295 const scanner = new _Scanner(text); 15296 const tokens = []; 15297 let token = scanner.scanToken(); 15298 15299 while (token != null) { 15300 tokens.push(token); 15301 token = scanner.scanToken(); 15302 } 15303 15304 return tokens; 15305 } 15306 15307} 15308 15309class Token { 15310 constructor(index, end, type, numValue, strValue) { 15311 this.index = index; 15312 this.end = end; 15313 this.type = type; 15314 this.numValue = numValue; 15315 this.strValue = strValue; 15316 } 15317 15318 isCharacter(code) { 15319 return this.type == TokenType.Character && this.numValue == code; 15320 } 15321 15322 isNumber() { 15323 return this.type == TokenType.Number; 15324 } 15325 15326 isString() { 15327 return this.type == TokenType.String; 15328 } 15329 15330 isOperator(operator) { 15331 return this.type == TokenType.Operator && this.strValue == operator; 15332 } 15333 15334 isIdentifier() { 15335 return this.type == TokenType.Identifier; 15336 } 15337 15338 isPrivateIdentifier() { 15339 return this.type == TokenType.PrivateIdentifier; 15340 } 15341 15342 isKeyword() { 15343 return this.type == TokenType.Keyword; 15344 } 15345 15346 isKeywordLet() { 15347 return this.type == TokenType.Keyword && this.strValue == 'let'; 15348 } 15349 15350 isKeywordAs() { 15351 return this.type == TokenType.Keyword && this.strValue == 'as'; 15352 } 15353 15354 isKeywordNull() { 15355 return this.type == TokenType.Keyword && this.strValue == 'null';
15356 } 15357 15358 isKeywordUndefined() { 15359 return this.type == TokenType.Keyword && this.strValue == 'undefined'; 15360 } 15361 15362 isKeywordTrue() { 15363 return this.type == TokenType.Keyword && this.strValue == 'true'; 15364 } 15365 15366 isKeywordFalse() { 15367 return this.type == TokenType.Keyword && this.strValue == 'false'; 15368 } 15369 15370 isKeywordThis() { 15371 return this.type == TokenType.Keyword && this.strValue == 'this'; 15372 } 15373 15374 isError() { 15375 return this.type == TokenType.Error; 15376 } 15377 15378 toNumber() { 15379 return this.type == TokenType.Number ? this.numValue : -1; 15380 } 15381 15382 toString() { 15383 switch (this.type) { 15384 case TokenType.Character: 15385 case TokenType.Identifier: 15386 case TokenType.Keyword: 15387 case TokenType.Operator: 15388 case TokenType.PrivateIdentifier: 15389 case TokenType.String: 15390 case TokenType.Error: 15391 return this.strValue; 15392 15393 case TokenType.Number: 15394 return this.numValue.toString(); 15395 15396 default: 15397 return null; 15398 } 15399 } 15400 15401} 15402 15403function newCharacterToken(index, end, code) { 15404 return new Token(index, end, TokenType.Character, code, String.fromCharCode(code)); 15405} 15406 15407function newIdentifierToken(index, end, text) { 15408 return new Token(index, end, TokenType.Identifier, 0, text); 15409} 15410 15411function newPrivateIdentifierToken(index, end, text) { 15412 return new Token(index, end, TokenType.PrivateIdentifier, 0, text); 15413} 15414 15415function newKeywordToken(index, end, text) { 15416 return new Token(index, end, TokenType.Keyword, 0, text); 15417} 15418 15419function newOperatorToken(index, end, text) { 15420 return new Token(index, end, TokenType.Operator, 0, text); 15421} 15422 15423function newStringToken(index, end, text) { 15424 return new Token(index, end, TokenType.String, 0, text); 15425} 15426 15427function newNumberToken(index, end, n) { 15428 return new Token(index, end, TokenType.Number, n, ''); 15429} 15430 15431function newErrorToken(index, end, message) { 15432 return new Token(index, end, TokenType.Error, 0, message); 15433} 15434 15435const EOF = new Token(-1, -1, TokenType.Character, 0, ''); 15436 15437class _Scanner { 15438 constructor(input) { 15439 this.input = input; 15440 this.peek = 0; 15441 this.index = -1; 15442 this.length = input.length; 15443 this.advance(); 15444 } 15445 15446 advance() { 15447 this.peek = ++this.index >= this.length ? $EOF : this.input.charCodeAt(this.index); 15448 } 15449 15450 scanToken() { 15451 const input = this.input, 15452 length = this.length; 15453 let peek = this.peek, 15454 index = this.index; // Skip whitespace. 15455 15456 while (peek <= $SPACE) { 15457 if (++index >= length) { 15458 peek = $EOF; 15459 break; 15460 } else { 15461 peek = input.charCodeAt(index); 15462 } 15463 } 15464 15465 this.peek = peek; 15466 this.index = index; 15467 15468 if (index >= length) { 15469 return null; 15470 } // Handle identifiers and numbers. 15471 15472 15473 if (isIdentifierStart(peek)) return this.scanIdentifier(); 15474 if (isDigit(peek)) return this.scanNumber(index); 15475 const start = index; 15476 15477 switch (peek) { 15478 case $PERIOD: 15479 this.advance(); 15480 return isDigit(this.peek) ? this.scanNumber(start) : newCharacterToken(start, this.index, $PERIOD); 15481 15482 case $LPAREN: 15483 case $RPAREN: 15484 case $LBRACE: 15485 case $RBRACE: 15486 case $LBRACKET: 15487 case $RBRACKET: 15488 case $COMMA: 15489 case $COLON: 15490 case $SEMICOLON: 15491 return this.scanCharacter(start, peek); 15492 15493 case $SQ: 15494 case $DQ: 15495 return this.scanString(); 15496 15497 case $HASH: 15498 return this.scanPrivateIdentifier(); 15499 15500 case $PLUS: 15501 case $MINUS: 15502 case $STAR: 15503 case $SLASH: 15504 case $PERCENT: 15505 case $CARET: 15506 return this.scanOperator(start, String.fromCharCode(peek)); 15507 15508 case $QUESTION: 15509 return this.scanQuestion(start); 15510 15511 case $LT: 15512 case $GT: 15513 return this.scanComplexOperator(start, String.fromCharCode(peek), $EQ, '='); 15514 15515 case $BANG: 15516 case $EQ: 15517 return this.scanComplexOperator(start, String.fromCharCode(peek), $EQ, '=', $EQ, '='); 15518 15519 case $AMPERSAND: 15520 return this.scanComplexOperator(start, '&', $AMPERSAND, '&'); 15521 15522 case $BAR: 15523 return this.scanComplexOperator(start, '|', $BAR, '|'); 15524 15525 case $NBSP: 15526 while (isWhitespace(this.peek)) this.advance(); 15527 15528 return this.scanToken(); 15529 } 15530 15531 this.advance(); 15532 return this.error(`Unexpected character [${String.fromCharCode(peek)}]`, 0); 15533 } 15534
15535 scanCharacter(start, code) { 15536 this.advance(); 15537 return newCharacterToken(start, this.index, code); 15538 } 15539 15540 scanOperator(start, str) { 15541 this.advance(); 15542 return newOperatorToken(start, this.index, str); 15543 } 15544 /** 15545 * Tokenize a 2/3 char long operator 15546 * 15547 * @param start start index in the expression 15548 * @param one first symbol (always part of the operator) 15549 * @param twoCode code point for the second symbol 15550 * @param two second symbol (part of the operator when the second code point matches) 15551 * @param threeCode code point for the third symbol 15552 * @param three third symbol (part of the operator when provided and matches source expression) 15553 */ 15554 15555 15556 scanComplexOperator(start, one, twoCode, two, threeCode, three) { 15557 this.advance(); 15558 let str = one; 15559 15560 if (this.peek == twoCode) { 15561 this.advance(); 15562 str += two; 15563 } 15564 15565 if (threeCode != null && this.peek == threeCode) { 15566 this.advance(); 15567 str += three; 15568 } 15569 15570 return newOperatorToken(start, this.index, str); 15571 } 15572 15573 scanIdentifier() { 15574 const start = this.index; 15575 this.advance(); 15576 15577 while (isIdentifierPart(this.peek)) this.advance(); 15578 15579 const str = this.input.substring(start, this.index); 15580 return KEYWORDS.indexOf(str) > -1 ? newKeywordToken(start, this.index, str) : newIdentifierToken(start, this.index, str); 15581 } 15582 /** Scans an ECMAScript private identifier. */ 15583 15584 15585 scanPrivateIdentifier() { 15586 const start = this.index; 15587 this.advance(); 15588 15589 if (!isIdentifierStart(this.peek)) { 15590 return this.error('Invalid character [#]', -1); 15591 } 15592 15593 while (isIdentifierPart(this.peek)) this.advance(); 15594 15595 const identifierName = this.input.substring(start, this.index); 15596 return newPrivateIdentifierToken(start, this.index, identifierName); 15597 } 15598 15599 scanNumber(start) { 15600 let simple = this.index === start; 15601 let hasSeparators = false; 15602 this.advance(); // Skip initial digit. 15603 15604 while (true) { 15605 if (isDigit(this.peek)) {// Do nothing. 15606 } else if (this.peek === $_) { 15607 // Separators are only valid when they're surrounded by digits. E.g. `1_0_1` is 15608 // valid while `_101` and `101_` are not. The separator can't be next to the decimal 15609 // point or another separator either. Note that it's unlikely that we'll hit a case where 15610 // the underscore is at the start, because that's a valid identifier and it will be picked 15611 // up earlier in the parsing. We validate for it anyway just in case. 15612 if (!isDigit(this.input.charCodeAt(this.index - 1)) || !isDigit(this.input.charCodeAt(this.index + 1))) { 15613 return this.error('Invalid numeric separator', 0); 15614 } 15615 15616 hasSeparators = true; 15617 } else if (this.peek === $PERIOD) { 15618 simple = false; 15619 } else if (isExponentStart(this.peek)) { 15620 this.advance(); 15621 if (isExponentSign(this.peek)) this.advance(); 15622 if (!isDigit(this.peek)) return this.error('Invalid exponent', -1); 15623 simple = false; 15624 } else { 15625 break; 15626 } 15627 15628 this.advance(); 15629 } 15630 15631 let str = this.input.substring(start, this.index); 15632 15633 if (hasSeparators) { 15634 str = str.replace(/_/g, ''); 15635 } 15636 15637 const value = simple ? parseIntAutoRadix(str) : parseFloat(str); 15638 return newNumberToken(start, this.index, value); 15639 } 15640 15641 scanString() { 15642 const start = this.index; 15643 const quote = this.peek; 15644 this.advance(); // Skip initial quote. 15645 15646 let buffer = ''; 15647 let marker = this.index; 15648 const input = this.input; 15649 15650 while (this.peek != quote) { 15651 if (this.peek == $BACKSLASH) { 15652 buffer += input.substring(marker, this.index); 15653 this.advance(); 15654 let unescapedCode; // Workaround for TS2.1-introduced type strictness 15655 15656 this.peek = this.peek; 15657 15658 if (this.peek == $u) { 15659 // 4 character hex code for unicode character. 15660 const hex = input.substring(this.index + 1, this.index + 5); 15661 15662 if (/^[0-9a-f]+$/i.test(hex)) { 15663 unescapedCode = parseInt(hex, 16); 15664 } else { 15665 return this.error(`Invalid unicode escape [\\u${hex}]`, 0); 15666 } 15667 15668 for (let i = 0; i < 5; i++) { 15669 this.advance(); 15670 } 15671 } else { 15672 unescapedCode = unescape(this.peek); 15673 this.advance(); 15674 } 15675 15676 buffer += String.fromCharCode(unescapedCode); 15677 marker = this.index; 15678 } else if (this.peek == $EOF) {
15679 return this.error('Unterminated quote', 0); 15680 } else { 15681 this.advance(); 15682 } 15683 } 15684 15685 const last = input.substring(marker, this.index); 15686 this.advance(); // Skip terminating quote. 15687 15688 return newStringToken(start, this.index, buffer + last); 15689 } 15690 15691 scanQuestion(start) { 15692 this.advance(); 15693 let str = '?'; // Either `a ?? b` or 'a?.b'. 15694 15695 if (this.peek === $QUESTION || this.peek === $PERIOD) { 15696 str += this.peek === $PERIOD ? '.' : '?'; 15697 this.advance(); 15698 } 15699 15700 return newOperatorToken(start, this.index, str); 15701 } 15702 15703 error(message, offset) { 15704 const position = this.index + offset; 15705 return newErrorToken(position, this.index, `Lexer Error: ${message} at column ${position} in expression [${this.input}]`); 15706 } 15707 15708} 15709 15710function isIdentifierStart(code) { 15711 return $a <= code && code <= $z || $A <= code && code <= $Z || code == $_ || code == $$; 15712} 15713 15714function isIdentifier(input) { 15715 if (input.length == 0) return false; 15716 const scanner = new _Scanner(input); 15717 if (!isIdentifierStart(scanner.peek)) return false; 15718 scanner.advance(); 15719 15720 while (scanner.peek !== $EOF) { 15721 if (!isIdentifierPart(scanner.peek)) return false; 15722 scanner.advance(); 15723 } 15724 15725 return true; 15726} 15727 15728function isIdentifierPart(code) { 15729 return isAsciiLetter(code) || isDigit(code) || code == $_ || code == $$; 15730} 15731 15732function isExponentStart(code) { 15733 return code == $e || code == $E; 15734} 15735 15736function isExponentSign(code) { 15737 return code == $MINUS || code == $PLUS; 15738} 15739 15740function unescape(code) { 15741 switch (code) { 15742 case $n: 15743 return $LF; 15744 15745 case $f: 15746 return $FF; 15747 15748 case $r: 15749 return $CR; 15750 15751 case $t: 15752 return $TAB; 15753 15754 case $v: 15755 return $VTAB; 15756 15757 default: 15758 return code; 15759 } 15760} 15761 15762function parseIntAutoRadix(text) { 15763 const result = parseInt(text); 15764 15765 if (isNaN(result)) { 15766 throw new Error('Invalid integer literal when parsing ' + text); 15767 } 15768 15769 return result; 15770} 15771/** 15772 * @license 15773 * Copyright Google LLC All Rights Reserved. 15774 * 15775 * Use of this source code is governed by an MIT-style license that can be 15776 * found in the LICENSE file at https://angular.io/license 15777 */ 15778 15779 15780class SplitInterpolation { 15781 constructor(strings, expressions, offsets) { 15782 this.strings = strings; 15783 this.expressions = expressions; 15784 this.offsets = offsets; 15785 } 15786 15787} 15788 15789class TemplateBindingParseResult { 15790 constructor(templateBindings, warnings, errors) { 15791 this.templateBindings = templateBindings; 15792 this.warnings = warnings; 15793 this.errors = errors; 15794 } 15795 15796} 15797 15798class Parser$1 { 15799 constructor(_lexer) { 15800 this._lexer = _lexer; 15801 this.errors = []; 15802 } 15803 15804 parseAction(input, isAssignmentEvent, location, absoluteOffset, interpolationConfig = DEFAULT_INTERPOLATION_CONFIG) { 15805 this._checkNoInterpolation(input, location, interpolationConfig); 15806 15807 const sourceToLex = this._stripComments(input); 15808 15809 const tokens = this._lexer.tokenize(sourceToLex); 15810 15811 let flags = 1 15812 /* ParseFlags.Action */ 15813 ; 15814 15815 if (isAssignmentEvent) { 15816 flags |= 2 15817 /* ParseFlags.AssignmentEvent */ 15818 ; 15819 } 15820 15821 const ast = new _ParseAST(input, location, absoluteOffset, tokens, flags, this.errors, 0).parseChain(); 15822 return new ASTWithSource(ast, input, location, absoluteOffset, this.errors); 15823 } 15824 15825 parseBinding(input, location, absoluteOffset, interpolationConfig = DEFAULT_INTERPOLATION_CONFIG) { 15826 const ast = this._parseBindingAst(input, location, absoluteOffset, interpolationConfig); 15827 15828 return new ASTWithSource(ast, input, location, absoluteOffset, this.errors); 15829 } 15830 15831 checkSimpleExpression(ast) { 15832 const checker = new SimpleExpressionChecker(); 15833 ast.visit(checker); 15834 return checker.errors; 15835 } 15836 15837 parseSimpleBinding(input, location, absoluteOffset, interpolationConfig = DEFAULT_INTERPOLATION_CONFIG) { 15838 const ast = this._parseBindingAst(input, location, absoluteOffset, interpolationConfig); 15839 15840 const errors = this.checkSimpleExpression(ast); 15841 15842 if (errors.length > 0) { 15843 this._reportError(`Host binding expression cannot contain ${errors.join(' ')}`, input, location); 15844 } 15845 15846 return new ASTWithSource(ast, input, location, absoluteOffset, this.errors); 15847 } 15848 15849 _reportError(message, input, errLocation, ctxLocation) { 15850 this.errors.push(new ParserError(message, input, errLocation, ctxLocation)); 15851 } 15852 15853 _parseBindingAst(input, location, absoluteOffset, interpolationConfig) { 15854 this._checkNoInterpolation(input, location, interpolationConfig); 15855 15856 const sourceToLex = this._stripComments(input); 15857 15858 const tokens = this._lexer.tokenize(sourceToLex); 15859 15860 return new _ParseAST(input, location, absoluteOffset, tokens, 0 15861 /* ParseFlags.None */ 15862 , this.errors, 0).parseChain(); 15863 } 15864 /** 15865 * Parse microsyntax template expression and return a list of bindings or
15866 * parsing errors in case the given expression is invalid. 15867 * 15868 * For example, 15869 * ``` 15870 * <div *ngFor="let item of items"> 15871 * ^ ^ absoluteValueOffset for `templateValue` 15872 * absoluteKeyOffset for `templateKey` 15873 * ``` 15874 * contains three bindings: 15875 * 1. ngFor -> null 15876 * 2. item -> NgForOfContext.$implicit 15877 * 3. ngForOf -> items 15878 * 15879 * This is apparent from the de-sugared template: 15880 * ``` 15881 * <ng-template ngFor let-item [ngForOf]="items"> 15882 * ``` 15883 * 15884 * @param templateKey name of directive, without the * prefix. For example: ngIf, ngFor 15885 * @param templateValue RHS of the microsyntax attribute 15886 * @param templateUrl template filename if it's external, component filename if it's inline 15887 * @param absoluteKeyOffset start of the `templateKey` 15888 * @param absoluteValueOffset start of the `templateValue` 15889 */ 15890 15891 15892 parseTemplateBindings(templateKey, templateValue, templateUrl, absoluteKeyOffset, absoluteValueOffset) { 15893 const tokens = this._lexer.tokenize(templateValue); 15894 15895 const parser = new _ParseAST(templateValue, templateUrl, absoluteValueOffset, tokens, 0 15896 /* ParseFlags.None */ 15897 , this.errors, 0 15898 /* relative offset */ 15899 ); 15900 return parser.parseTemplateBindings({ 15901 source: templateKey, 15902 span: new AbsoluteSourceSpan(absoluteKeyOffset, absoluteKeyOffset + templateKey.length) 15903 }); 15904 } 15905 15906 parseInterpolation(input, location, absoluteOffset, interpolatedTokens, interpolationConfig = DEFAULT_INTERPOLATION_CONFIG) { 15907 const { 15908 strings, 15909 expressions, 15910 offsets 15911 } = this.splitInterpolation(input, location, interpolatedTokens, interpolationConfig); 15912 if (expressions.length === 0) return null; 15913 const expressionNodes = []; 15914 15915 for (let i = 0; i < expressions.length; ++i) { 15916 const expressionText = expressions[i].text; 15917 15918 const sourceToLex = this._stripComments(expressionText); 15919 15920 const tokens = this._lexer.tokenize(sourceToLex); 15921 15922 const ast = new _ParseAST(input, location, absoluteOffset, tokens, 0 15923 /* ParseFlags.None */ 15924 , this.errors, offsets[i]).parseChain(); 15925 expressionNodes.push(ast); 15926 } 15927 15928 return this.createInterpolationAst(strings.map(s => s.text), expressionNodes, input, location, absoluteOffset); 15929 } 15930 /** 15931 * Similar to `parseInterpolation`, but treats the provided string as a single expression 15932 * element that would normally appear within the interpolation prefix and suffix (`{{` and `}}`). 15933 * This is used for parsing the switch expression in ICUs. 15934 */ 15935 15936 15937 parseInterpolationExpression(expression, location, absoluteOffset) { 15938 const sourceToLex = this._stripComments(expression); 15939 15940 const tokens = this._lexer.tokenize(sourceToLex); 15941 15942 const ast = new _ParseAST(expression, location, absoluteOffset, tokens, 0 15943 /* ParseFlags.None */ 15944 , this.errors, 0).parseChain(); 15945 const strings = ['', '']; // The prefix and suffix strings are both empty 15946 15947 return this.createInterpolationAst(strings, [ast], expression, location, absoluteOffset); 15948 } 15949 15950 createInterpolationAst(strings, expressions, input, location, absoluteOffset) { 15951 const span = new ParseSpan(0, input.length); 15952 const interpolation = new Interpolation(span, span.toAbsolute(absoluteOffset), strings, expressions); 15953 return new ASTWithSource(interpolation, input, location, absoluteOffset, this.errors); 15954 } 15955 /** 15956 * Splits a string of text into "raw" text segments and expressions present in interpolations in 15957 * the string. 15958 * Returns `null` if there are no interpolations, otherwise a 15959 * `SplitInterpolation` with splits that look like 15960 * <raw text> <expression> <raw text> ... <raw text> <expression> <raw text> 15961 */ 15962 15963 15964 splitInterpolation(input, location, interpolatedTokens, interpolationConfig = DEFAULT_INTERPOLATION_CONFIG) { 15965 const strings = []; 15966 const expressions = []; 15967 const offsets = []; 15968 const inputToTemplateIndexMap = interpolatedTokens ? getIndexMapForOriginalTemplate(interpolatedTokens) : null; 15969 let i = 0; 15970 let atInterpolation = false; 15971 let extendLastString = false; 15972 let { 15973 start: interpStart, 15974 end: interpEnd 15975 } = interpolationConfig; 15976 15977 while (i < input.length) { 15978 if (!atInterpolation) { 15979 // parse until starting {{ 15980 const start = i; 15981 i = input.indexOf(interpStart, i); 15982 15983 if (i === -1) { 15984 i = input.length; 15985 } 15986 15987 const text = input.substring(start, i);
15988 strings.push({ 15989 text, 15990 start, 15991 end: i 15992 }); 15993 atInterpolation = true; 15994 } else { 15995 // parse from starting {{ to ending }} while ignoring content inside quotes. 15996 const fullStart = i; 15997 const exprStart = fullStart + interpStart.length; 15998 15999 const exprEnd = this._getInterpolationEndIndex(input, interpEnd, exprStart); 16000 16001 if (exprEnd === -1) { 16002 // Could not find the end of the interpolation; do not parse an expression. 16003 // Instead we should extend the content on the last raw string. 16004 atInterpolation = false; 16005 extendLastString = true; 16006 break; 16007 } 16008 16009 const fullEnd = exprEnd + interpEnd.length; 16010 const text = input.substring(exprStart, exprEnd); 16011 16012 if (text.trim().length === 0) { 16013 this._reportError('Blank expressions are not allowed in interpolated strings', input, `at column ${i} in`, location); 16014 } 16015 16016 expressions.push({ 16017 text, 16018 start: fullStart, 16019 end: fullEnd 16020 }); 16021 const startInOriginalTemplate = inputToTemplateIndexMap?.get(fullStart) ?? fullStart; 16022 const offset = startInOriginalTemplate + interpStart.length; 16023 offsets.push(offset); 16024 i = fullEnd; 16025 atInterpolation = false; 16026 } 16027 } 16028 16029 if (!atInterpolation) { 16030 // If we are now at a text section, add the remaining content as a raw string. 16031 if (extendLastString) { 16032 const piece = strings[strings.length - 1]; 16033 piece.text += input.substring(i); 16034 piece.end = input.length; 16035 } else { 16036 strings.push({ 16037 text: input.substring(i), 16038 start: i, 16039 end: input.length 16040 }); 16041 } 16042 } 16043 16044 return new SplitInterpolation(strings, expressions, offsets); 16045 } 16046 16047 wrapLiteralPrimitive(input, location, absoluteOffset) { 16048 const span = new ParseSpan(0, input == null ? 0 : input.length); 16049 return new ASTWithSource(new LiteralPrimitive(span, span.toAbsolute(absoluteOffset), input), input, location, absoluteOffset, this.errors); 16050 } 16051 16052 _stripComments(input) { 16053 const i = this._commentStart(input); 16054 16055 return i != null ? input.substring(0, i) : input; 16056 } 16057 16058 _commentStart(input) { 16059 let outerQuote = null; 16060 16061 for (let i = 0; i < input.length - 1; i++) { 16062 const char = input.charCodeAt(i); 16063 const nextChar = input.charCodeAt(i + 1); 16064 if (char === $SLASH && nextChar == $SLASH && outerQuote == null) return i; 16065 16066 if (outerQuote === char) { 16067 outerQuote = null; 16068 } else if (outerQuote == null && isQuote(char)) { 16069 outerQuote = char; 16070 } 16071 } 16072 16073 return null; 16074 } 16075 16076 _checkNoInterpolation(input, location, { 16077 start, 16078 end 16079 }) { 16080 let startIndex = -1; 16081 let endIndex = -1; 16082 16083 for (const charIndex of this._forEachUnquotedChar(input, 0)) { 16084 if (startIndex === -1) { 16085 if (input.startsWith(start)) { 16086 startIndex = charIndex; 16087 } 16088 } else { 16089 endIndex = this._getInterpolationEndIndex(input, end, charIndex); 16090 16091 if (endIndex > -1) { 16092 break; 16093 } 16094 } 16095 } 16096 16097 if (startIndex > -1 && endIndex > -1) { 16098 this._reportError(`Got interpolation (${start}${end}) where expression was expected`, input, `at column ${startIndex} in`, location); 16099 } 16100 } 16101 /** 16102 * Finds the index of the end of an interpolation expression 16103 * while ignoring comments and quoted content. 16104 */ 16105 16106 16107 _getInterpolationEndIndex(input, expressionEnd, start) { 16108 for (const charIndex of this._forEachUnquotedChar(input, start)) { 16109 if (input.startsWith(expressionEnd, charIndex)) { 16110 return charIndex; 16111 } // Nothing else in the expression matters after we've 16112 // hit a comment so look directly for the end token. 16113 16114 16115 if (input.startsWith('//', charIndex)) { 16116 return input.indexOf(expressionEnd, charIndex); 16117 } 16118 } 16119 16120 return -1; 16121 } 16122 /** 16123 * Generator used to iterate over the character indexes of a string that are outside of quotes. 16124 * @param input String to loop through. 16125 * @param start Index within the string at which to start. 16126 */ 16127 16128 16129 *_forEachUnquotedChar(input, start) {
16130 let currentQuote = null; 16131 let escapeCount = 0; 16132 16133 for (let i = start; i < input.length; i++) { 16134 const char = input[i]; // Skip the characters inside quotes. Note that we only care about the outer-most 16135 // quotes matching up and we need to account for escape characters. 16136 16137 if (isQuote(input.charCodeAt(i)) && (currentQuote === null || currentQuote === char) && escapeCount % 2 === 0) { 16138 currentQuote = currentQuote === null ? char : null; 16139 } else if (currentQuote === null) { 16140 yield i; 16141 } 16142 16143 escapeCount = char === '\\' ? escapeCount + 1 : 0; 16144 } 16145 } 16146 16147} 16148/** Describes a stateful context an expression parser is in. */ 16149 16150 16151var ParseContextFlags; 16152 16153(function (ParseContextFlags) { 16154 ParseContextFlags[ParseContextFlags["None"] = 0] = "None"; 16155 /** 16156 * A Writable context is one in which a value may be written to an lvalue. 16157 * For example, after we see a property access, we may expect a write to the 16158 * property via the "=" operator. 16159 * prop 16160 * ^ possible "=" after 16161 */ 16162 16163 ParseContextFlags[ParseContextFlags["Writable"] = 1] = "Writable"; 16164})(ParseContextFlags || (ParseContextFlags = {})); 16165 16166class _ParseAST { 16167 constructor(input, location, absoluteOffset, tokens, parseFlags, errors, offset) { 16168 this.input = input; 16169 this.location = location; 16170 this.absoluteOffset = absoluteOffset; 16171 this.tokens = tokens; 16172 this.parseFlags = parseFlags; 16173 this.errors = errors; 16174 this.offset = offset; 16175 this.rparensExpected = 0; 16176 this.rbracketsExpected = 0; 16177 this.rbracesExpected = 0; 16178 this.context = ParseContextFlags.None; // Cache of expression start and input indeces to the absolute source span they map to, used to 16179 // prevent creating superfluous source spans in `sourceSpan`. 16180 // A serial of the expression start and input index is used for mapping because both are stateful 16181 // and may change for subsequent expressions visited by the parser. 16182 16183 this.sourceSpanCache = new Map(); 16184 this.index = 0; 16185 } 16186 16187 peek(offset) { 16188 const i = this.index + offset; 16189 return i < this.tokens.length ? this.tokens[i] : EOF; 16190 } 16191 16192 get next() { 16193 return this.peek(0); 16194 } 16195 /** Whether all the parser input has been processed. */ 16196 16197 16198 get atEOF() { 16199 return this.index >= this.tokens.length; 16200 } 16201 /** 16202 * Index of the next token to be processed, or the end of the last token if all have been 16203 * processed. 16204 */ 16205 16206 16207 get inputIndex() { 16208 return this.atEOF ? this.currentEndIndex : this.next.index + this.offset; 16209 } 16210 /** 16211 * End index of the last processed token, or the start of the first token if none have been 16212 * processed. 16213 */ 16214 16215 16216 get currentEndIndex() { 16217 if (this.index > 0) { 16218 const curToken = this.peek(-1); 16219 return curToken.end + this.offset; 16220 } // No tokens have been processed yet; return the next token's start or the length of the input 16221 // if there is no token. 16222 16223 16224 if (this.tokens.length === 0) { 16225 return this.input.length + this.offset; 16226 } 16227 16228 return this.next.index + this.offset; 16229 } 16230 /** 16231 * Returns the absolute offset of the start of the current token. 16232 */ 16233 16234 16235 get currentAbsoluteOffset() { 16236 return this.absoluteOffset + this.inputIndex; 16237 } 16238 /** 16239 * Retrieve a `ParseSpan` from `start` to the current position (or to `artificialEndIndex` if 16240 * provided). 16241 * 16242 * @param start Position from which the `ParseSpan` will start. 16243 * @param artificialEndIndex Optional ending index to be used if provided (and if greater than the 16244 * natural ending index) 16245 */ 16246 16247 16248 span(start, artificialEndIndex) { 16249 let endIndex = this.currentEndIndex; 16250 16251 if (artificialEndIndex !== undefined && artificialEndIndex > this.currentEndIndex) { 16252 endIndex = artificialEndIndex; 16253 } // In some unusual parsing scenarios (like when certain tokens are missing and an `EmptyExpr` is 16254 // being created), the current token may already be advanced beyond the `currentEndIndex`. This 16255 // appears to be a deep-seated parser bug. 16256 // 16257 // As a workaround for now, swap the start and end indices to ensure a valid `ParseSpan`. 16258 // TODO(alxhub): fix the bug upstream in the parser state, and remove this workaround. 16259 16260 16261 if (start > endIndex) { 16262 const tmp = endIndex; 16263 endIndex = start; 16264 start = tmp; 16265 } 16266 16267 return new ParseSpan(start, endIndex); 16268 } 16269 16270 sourceSpan(start, artificialEndIndex) { 16271 const serial = `${start}@${this.inputIndex}:${artificialEndIndex}`; 16272 16273 if (!this.sourceSpanCache.has(serial)) { 16274 this.sourceSpanCache.set(serial, this.span(start, artificialEndIndex).toAbsolute(this.absoluteOffset)); 16275 } 16276 16277 return this.sourceSpanCache.get(serial); 16278 } 16279 16280 advance() { 16281 this.index++; 16282 } 16283 /** 16284 * Executes a callback in the provided context. 16285 */ 16286 16287 16288 withContext(context, cb) { 16289 this.context |= context; 16290 const ret = cb(); 16291 this.context ^= context; 16292 return ret; 16293 } 16294 16295 consumeOptionalCharacter(code) { 16296 if (this.next.isCharacter(code)) { 16297 this.advance(); 16298 return true; 16299 } else { 16300 return false;
16301 } 16302 } 16303 16304 peekKeywordLet() { 16305 return this.next.isKeywordLet(); 16306 } 16307 16308 peekKeywordAs() { 16309 return this.next.isKeywordAs(); 16310 } 16311 /** 16312 * Consumes an expected character, otherwise emits an error about the missing expected character 16313 * and skips over the token stream until reaching a recoverable point. 16314 * 16315 * See `this.error` and `this.skip` for more details. 16316 */ 16317 16318 16319 expectCharacter(code) { 16320 if (this.consumeOptionalCharacter(code)) return; 16321 this.error(`Missing expected ${String.fromCharCode(code)}`); 16322 } 16323 16324 consumeOptionalOperator(op) { 16325 if (this.next.isOperator(op)) { 16326 this.advance(); 16327 return true; 16328 } else { 16329 return false; 16330 } 16331 } 16332 16333 expectOperator(operator) { 16334 if (this.consumeOptionalOperator(operator)) return; 16335 this.error(`Missing expected operator ${operator}`); 16336 } 16337 16338 prettyPrintToken(tok) { 16339 return tok === EOF ? 'end of input' : `token ${tok}`; 16340 } 16341 16342 expectIdentifierOrKeyword() { 16343 const n = this.next; 16344 16345 if (!n.isIdentifier() && !n.isKeyword()) { 16346 if (n.isPrivateIdentifier()) { 16347 this._reportErrorForPrivateIdentifier(n, 'expected identifier or keyword'); 16348 } else { 16349 this.error(`Unexpected ${this.prettyPrintToken(n)}, expected identifier or keyword`); 16350 } 16351 16352 return null; 16353 } 16354 16355 this.advance(); 16356 return n.toString(); 16357 } 16358 16359 expectIdentifierOrKeywordOrString() { 16360 const n = this.next; 16361 16362 if (!n.isIdentifier() && !n.isKeyword() && !n.isString()) { 16363 if (n.isPrivateIdentifier()) { 16364 this._reportErrorForPrivateIdentifier(n, 'expected identifier, keyword or string'); 16365 } else { 16366 this.error(`Unexpected ${this.prettyPrintToken(n)}, expected identifier, keyword, or string`); 16367 } 16368 16369 return ''; 16370 } 16371 16372 this.advance(); 16373 return n.toString(); 16374 } 16375 16376 parseChain() { 16377 const exprs = []; 16378 const start = this.inputIndex; 16379 16380 while (this.index < this.tokens.length) { 16381 const expr = this.parsePipe(); 16382 exprs.push(expr); 16383 16384 if (this.consumeOptionalCharacter($SEMICOLON)) { 16385 if (!(this.parseFlags & 1 16386 /* ParseFlags.Action */ 16387 )) { 16388 this.error('Binding expression cannot contain chained expression'); 16389 } 16390 16391 while (this.consumeOptionalCharacter($SEMICOLON)) {} // read all semicolons 16392 16393 } else if (this.index < this.tokens.length) { 16394 const errorIndex = this.index; 16395 this.error(`Unexpected token '${this.next}'`); // The `error` call above will skip ahead to the next recovery point in an attempt to 16396 // recover part of the expression, but that might be the token we started from which will 16397 // lead to an infinite loop. If that's the case, break the loop assuming that we can't 16398 // parse further. 16399 16400 if (this.index === errorIndex) { 16401 break; 16402 } 16403 } 16404 } 16405 16406 if (exprs.length === 0) { 16407 // We have no expressions so create an empty expression that spans the entire input length 16408 const artificialStart = this.offset; 16409 const artificialEnd = this.offset + this.input.length; 16410 return new EmptyExpr(this.span(artificialStart, artificialEnd), this.sourceSpan(artificialStart, artificialEnd)); 16411 } 16412 16413 if (exprs.length == 1) return exprs[0]; 16414 return new Chain(this.span(start), this.sourceSpan(start), exprs); 16415 } 16416 16417 parsePipe() { 16418 const start = this.inputIndex; 16419 let result = this.parseExpression(); 16420 16421 if (this.consumeOptionalOperator('|')) { 16422 if (this.parseFlags & 1 16423 /* ParseFlags.Action */ 16424 ) { 16425 this.error('Cannot have a pipe in an action expression'); 16426 } 16427 16428 do { 16429 const nameStart = this.inputIndex; 16430 let nameId = this.expectIdentifierOrKeyword(); 16431 let nameSpan; 16432 let fullSpanEnd = undefined; 16433 16434 if (nameId !== null) { 16435 nameSpan = this.sourceSpan(nameStart); 16436 } else { 16437 // No valid identifier was found, so we'll assume an empty pipe name (''). 16438 nameId = ''; // However, there may have been whitespace present between the pipe character and the next 16439 // token in the sequence (or the end of input). We want to track this whitespace so that 16440 // the `BindingPipe` we produce covers not just the pipe character, but any trailing 16441 // whitespace beyond it. Another way of thinking about this is that the zero-length name 16442 // is assumed to be at the end of any whitespace beyond the pipe character. 16443 // 16444 // Therefore, we push the end of the `ParseSpan` for this pipe all the way up to the 16445 // beginning of the next token, or until the end of input if the next token is EOF.
16446 16447 fullSpanEnd = this.next.index !== -1 ? this.next.index : this.input.length + this.offset; // The `nameSpan` for an empty pipe name is zero-length at the end of any whitespace 16448 // beyond the pipe character. 16449 16450 nameSpan = new ParseSpan(fullSpanEnd, fullSpanEnd).toAbsolute(this.absoluteOffset); 16451 } 16452 16453 const args = []; 16454 16455 while (this.consumeOptionalCharacter($COLON)) { 16456 args.push(this.parseExpression()); // If there are additional expressions beyond the name, then the artificial end for the 16457 // name is no longer relevant. 16458 } 16459 16460 result = new BindingPipe(this.span(start), this.sourceSpan(start, fullSpanEnd), result, nameId, args, nameSpan); 16461 } while (this.consumeOptionalOperator('|')); 16462 } 16463 16464 return result; 16465 } 16466 16467 parseExpression() { 16468 return this.parseConditional(); 16469 } 16470 16471 parseConditional() { 16472 const start = this.inputIndex; 16473 const result = this.parseLogicalOr(); 16474 16475 if (this.consumeOptionalOperator('?')) { 16476 const yes = this.parsePipe(); 16477 let no; 16478 16479 if (!this.consumeOptionalCharacter($COLON)) { 16480 const end = this.inputIndex; 16481 const expression = this.input.substring(start, end); 16482 this.error(`Conditional expression ${expression} requires all 3 expressions`); 16483 no = new EmptyExpr(this.span(start), this.sourceSpan(start)); 16484 } else { 16485 no = this.parsePipe(); 16486 } 16487 16488 return new Conditional(this.span(start), this.sourceSpan(start), result, yes, no); 16489 } else { 16490 return result; 16491 } 16492 } 16493 16494 parseLogicalOr() { 16495 // '||' 16496 const start = this.inputIndex; 16497 let result = this.parseLogicalAnd(); 16498 16499 while (this.consumeOptionalOperator('||')) { 16500 const right = this.parseLogicalAnd(); 16501 result = new Binary(this.span(start), this.sourceSpan(start), '||', result, right); 16502 } 16503 16504 return result; 16505 } 16506 16507 parseLogicalAnd() { 16508 // '&&' 16509 const start = this.inputIndex; 16510 let result = this.parseNullishCoalescing(); 16511 16512 while (this.consumeOptionalOperator('&&')) { 16513 const right = this.parseNullishCoalescing(); 16514 result = new Binary(this.span(start), this.sourceSpan(start), '&&', result, right); 16515 } 16516 16517 return result; 16518 } 16519 16520 parseNullishCoalescing() { 16521 // '??' 16522 const start = this.inputIndex; 16523 let result = this.parseEquality(); 16524 16525 while (this.consumeOptionalOperator('??')) { 16526 const right = this.parseEquality(); 16527 result = new Binary(this.span(start), this.sourceSpan(start), '??', result, right); 16528 } 16529 16530 return result; 16531 } 16532 16533 parseEquality() { 16534 // '==','!=','===','!==' 16535 const start = this.inputIndex; 16536 let result = this.parseRelational(); 16537 16538 while (this.next.type == TokenType.Operator) { 16539 const operator = this.next.strValue; 16540 16541 switch (operator) { 16542 case '==': 16543 case '===': 16544 case '!=': 16545 case '!==': 16546 this.advance(); 16547 const right = this.parseRelational(); 16548 result = new Binary(this.span(start), this.sourceSpan(start), operator, result, right); 16549 continue; 16550 } 16551 16552 break; 16553 } 16554 16555 return result; 16556 } 16557 16558 parseRelational() { 16559 // '<', '>', '<=', '>=' 16560 const start = this.inputIndex; 16561 let result = this.parseAdditive(); 16562 16563 while (this.next.type == TokenType.Operator) { 16564 const operator = this.next.strValue; 16565 16566 switch (operator) { 16567 case '<': 16568 case '>': 16569 case '<=': 16570 case '>=': 16571 this.advance(); 16572 const right = this.parseAdditive(); 16573 result = new Binary(this.span(start), this.sourceSpan(start), operator, result, right); 16574 continue; 16575 } 16576 16577 break; 16578 } 16579 16580 return result; 16581 } 16582 16583 parseAdditive() { 16584 // '+', '-' 16585 const start = this.inputIndex; 16586 let result = this.parseMultiplicative(); 16587 16588 while (this.next.type == TokenType.Operator) { 16589 const operator = this.next.strValue; 16590 16591 switch (operator) { 16592 case '+': 16593 case '-': 16594 this.advance(); 16595 let right = this.parseMultiplicative(); 16596 result = new Binary(this.span(start), this.sourceSpan(start), operator, result, right); 16597 continue; 16598 } 16599 16600 break; 16601 } 16602 16603 return result; 16604 } 16605 16606 parseMultiplicative() { 16607 // '*', '%', '/' 16608 const start = this.inputIndex; 16609 let result = this.parsePrefix(); 16610 16611 while (this.next.type == TokenType.Operator) { 16612 const operator = this.next.strValue; 16613 16614 switch (operator) { 16615 case '*': 16616 case '%': 16617 case '/': 16618 this.advance(); 16619 let right = this.parsePrefix(); 16620 result = new Binary(this.span(start), this.sourceSpan(start), operator, result, right); 16621 continue; 16622 } 16623 16624 break; 16625 } 16626 16627 return result; 16628 } 16629 16630 parsePrefix() { 16631 if (this.next.type == TokenType.Operator) { 16632 const start = this.inputIndex; 16633 const operator = this.next.strValue; 16634 let result; 16635 16636 switch (operator) { 16637 case '+': 16638 this.advance(); 16639 result = this.parsePrefix(); 16640 return Unary.createPlus(this.span(start), this.sourceSpan(start), result); 16641 16642 case '-': 16643 this.advance(); 16644 result = this.parsePrefix(); 16645 return Unary.createMinus(this.span(start), this.sourceSpan(start), result); 16646 16647 case '!': 16648 this.advance(); 16649 result = this.parsePrefix(); 16650 return new PrefixNot(this.span(start), this.sourceSpan(start), result); 16651 } 16652 } 16653 16654 return this.parseCallChain(); 16655 } 16656 16657 parseCallChain() { 16658 const start = this.inputIndex; 16659 let result = this.parsePrimary(); 16660 16661 while (true) { 16662 if (this.consumeOptionalCharacter($PERIOD)) { 16663 result = this.parseAccessMember(result, start, false); 16664 } else if (this.consumeOptionalOperator('?.')) { 16665 if (this.consumeOptionalCharacter($LPAREN)) { 16666 result = this.parseCall(result, start, true); 16667 } else { 16668 result = this.consumeOptionalCharacter($LBRACKET) ? this.parseKeyedReadOrWrite(result, start, true) : this.parseAccessMember(result, start, true); 16669 } 16670 } else if (this.consumeOptionalCharacter($LBRACKET)) { 16671 result = this.parseKeyedReadOrWrite(result, start, false); 16672 } else if (this.consumeOptionalCharacter($LPAREN)) { 16673 result = this.parseCall(result, start, false); 16674 } else if (this.consumeOptionalOperator('!')) { 16675 result = new NonNullAssert(this.span(start), this.sourceSpan(start), result); 16676 } else { 16677 return result; 16678 } 16679 } 16680 } 16681 16682 parsePrimary() { 16683 const start = this.inputIndex; 16684 16685 if (this.consumeOptionalCharacter($LPAREN)) { 16686 this.rparensExpected++; 16687 const result = this.parsePipe(); 16688 this.rparensExpected--; 16689 this.expectCharacter($RPAREN); 16690 return result; 16691 } else if (this.next.isKeywordNull()) { 16692 this.advance(); 16693 return new LiteralPrimitive(this.span(start), this.sourceSpan(start), null); 16694 } else if (this.next.isKeywordUndefined()) { 16695 this.advance(); 16696 return new LiteralPrimitive(this.span(start), this.sourceSpan(start), void 0); 16697 } else if (this.next.isKeywordTrue()) { 16698 this.advance(); 16699 return new LiteralPrimitive(this.span(start), this.sourceSpan(start), true); 16700 } else if (this.next.isKeywordFalse()) { 16701 this.advance(); 16702 return new LiteralPrimitive(this.span(start), this.sourceSpan(start), false); 16703 } else if (this.next.isKeywordThis()) { 16704 this.advance(); 16705 return new ThisReceiver(this.span(start), this.sourceSpan(start)); 16706 } else if (this.consumeOptionalCharacter($LBRACKET)) { 16707 this.rbracketsExpected++; 16708 const elements = this.parseExpressionList($RBRACKET); 16709 this.rbracketsExpected--; 16710 this.expectCharacter($RBRACKET); 16711 return new LiteralArray(this.span(start), this.sourceSpan(start), elements); 16712 } else if (this.next.isCharacter($LBRACE)) { 16713 return this.parseLiteralMap(); 16714 } else if (this.next.isIdentifier()) { 16715 return this.parseAccessMember(new ImplicitReceiver(this.span(start), this.sourceSpan(start)), start, false); 16716 } else if (this.next.isNumber()) { 16717 const value = this.next.toNumber(); 16718 this.advance(); 16719 return new LiteralPrimitive(this.span(start), this.sourceSpan(start), value); 16720 } else if (this.next.isString()) { 16721 const literalValue = this.next.toString(); 16722 this.advance(); 16723 return new LiteralPrimitive(this.span(start), this.sourceSpan(start), literalValue); 16724 } else if (this.next.isPrivateIdentifier()) { 16725 this._reportErrorForPrivateIdentifier(this.next, null); 16726 16727 return new EmptyExpr(this.span(start), this.sourceSpan(start)); 16728 } else if (this.index >= this.tokens.length) { 16729 this.error(`Unexpected end of expression: ${this.input}`); 16730 return new EmptyExpr(this.span(start), this.sourceSpan(start)); 16731 } else { 16732 this.error(`Unexpected token ${this.next}`); 16733 return new EmptyExpr(this.span(start), this.sourceSpan(start)); 16734 } 16735 } 16736 16737 parseExpressionList(terminator) { 16738 const result = []; 16739 16740 do { 16741 if (!this.next.isCharacter(terminator)) { 16742 result.push(this.parsePipe()); 16743 } else { 16744 break; 16745 } 16746 } while (this.consumeOptionalCharacter($COMMA)); 16747 16748 return result; 16749 } 16750 16751 parseLiteralMap() {
16752 const keys = []; 16753 const values = []; 16754 const start = this.inputIndex; 16755 this.expectCharacter($LBRACE); 16756 16757 if (!this.consumeOptionalCharacter($RBRACE)) { 16758 this.rbracesExpected++; 16759 16760 do { 16761 const keyStart = this.inputIndex; 16762 const quoted = this.next.isString(); 16763 const key = this.expectIdentifierOrKeywordOrString(); 16764 keys.push({ 16765 key, 16766 quoted 16767 }); // Properties with quoted keys can't use the shorthand syntax. 16768 16769 if (quoted) { 16770 this.expectCharacter($COLON); 16771 values.push(this.parsePipe()); 16772 } else if (this.consumeOptionalCharacter($COLON)) { 16773 values.push(this.parsePipe()); 16774 } else { 16775 const span = this.span(keyStart); 16776 const sourceSpan = this.sourceSpan(keyStart); 16777 values.push(new PropertyRead(span, sourceSpan, sourceSpan, new ImplicitReceiver(span, sourceSpan), key)); 16778 } 16779 } while (this.consumeOptionalCharacter($COMMA)); 16780 16781 this.rbracesExpected--; 16782 this.expectCharacter($RBRACE); 16783 } 16784 16785 return new LiteralMap(this.span(start), this.sourceSpan(start), keys, values); 16786 } 16787 16788 parseAccessMember(readReceiver, start, isSafe) { 16789 const nameStart = this.inputIndex; 16790 const id = this.withContext(ParseContextFlags.Writable, () => { 16791 const id = this.expectIdentifierOrKeyword() ?? ''; 16792 16793 if (id.length === 0) { 16794 this.error(`Expected identifier for property access`, readReceiver.span.end); 16795 } 16796 16797 return id; 16798 }); 16799 const nameSpan = this.sourceSpan(nameStart); 16800 let receiver; 16801 16802 if (isSafe) { 16803 if (this.consumeOptionalAssignment()) { 16804 this.error('The \'?.\' operator cannot be used in the assignment'); 16805 receiver = new EmptyExpr(this.span(start), this.sourceSpan(start)); 16806 } else { 16807 receiver = new SafePropertyRead(this.span(start), this.sourceSpan(start), nameSpan, readReceiver, id); 16808 } 16809 } else { 16810 if (this.consumeOptionalAssignment()) { 16811 if (!(this.parseFlags & 1 16812 /* ParseFlags.Action */ 16813 )) { 16814 this.error('Bindings cannot contain assignments'); 16815 return new EmptyExpr(this.span(start), this.sourceSpan(start)); 16816 } 16817 16818 const value = this.parseConditional(); 16819 receiver = new PropertyWrite(this.span(start), this.sourceSpan(start), nameSpan, readReceiver, id, value); 16820 } else { 16821 receiver = new PropertyRead(this.span(start), this.sourceSpan(start), nameSpan, readReceiver, id); 16822 } 16823 } 16824 16825 return receiver; 16826 } 16827 16828 parseCall(receiver, start, isSafe) { 16829 const argumentStart = this.inputIndex; 16830 this.rparensExpected++; 16831 const args = this.parseCallArguments(); 16832 const argumentSpan = this.span(argumentStart, this.inputIndex).toAbsolute(this.absoluteOffset); 16833 this.expectCharacter($RPAREN); 16834 this.rparensExpected--; 16835 const span = this.span(start); 16836 const sourceSpan = this.sourceSpan(start); 16837 return isSafe ? new SafeCall(span, sourceSpan, receiver, args, argumentSpan) : new Call(span, sourceSpan, receiver, args, argumentSpan); 16838 } 16839 16840 consumeOptionalAssignment() { 16841 // When parsing assignment events (originating from two-way-binding aka banana-in-a-box syntax), 16842 // it is valid for the primary expression to be terminated by the non-null operator. This 16843 // primary expression is substituted as LHS of the assignment operator to achieve 16844 // two-way-binding, such that the LHS could be the non-null operator. The grammar doesn't 16845 // naturally allow for this syntax, so assignment events are parsed specially. 16846 if (this.parseFlags & 2 16847 /* ParseFlags.AssignmentEvent */ 16848 && this.next.isOperator('!') && this.peek(1).isOperator('=')) { 16849 // First skip over the ! operator. 16850 this.advance(); // Then skip over the = operator, to fully consume the optional assignment operator. 16851 16852 this.advance(); 16853 return true; 16854 } 16855 16856 return this.consumeOptionalOperator('='); 16857 } 16858 16859 parseCallArguments() { 16860 if (this.next.isCharacter($RPAREN)) return []; 16861 const positionals = []; 16862 16863 do { 16864 positionals.push(this.parsePipe()); 16865 } while (this.consumeOptionalCharacter($COMMA)); 16866 16867 return positionals; 16868 } 16869 /** 16870 * Parses an identifier, a keyword, a string with an optional `-` in between, 16871 * and returns the string along with its absolute source span. 16872 */ 16873 16874 16875 expectTemplateBindingKey() { 16876 let result = ''; 16877 let operatorFound = false;
16878 const start = this.currentAbsoluteOffset; 16879 16880 do { 16881 result += this.expectIdentifierOrKeywordOrString(); 16882 operatorFound = this.consumeOptionalOperator('-'); 16883 16884 if (operatorFound) { 16885 result += '-'; 16886 } 16887 } while (operatorFound); 16888 16889 return { 16890 source: result, 16891 span: new AbsoluteSourceSpan(start, start + result.length) 16892 }; 16893 } 16894 /** 16895 * Parse microsyntax template expression and return a list of bindings or 16896 * parsing errors in case the given expression is invalid. 16897 * 16898 * For example, 16899 * ``` 16900 * <div *ngFor="let item of items; index as i; trackBy: func"> 16901 * ``` 16902 * contains five bindings: 16903 * 1. ngFor -> null 16904 * 2. item -> NgForOfContext.$implicit 16905 * 3. ngForOf -> items 16906 * 4. i -> NgForOfContext.index 16907 * 5. ngForTrackBy -> func 16908 * 16909 * For a full description of the microsyntax grammar, see 16910 * https://gist.github.com/mhevery/d3530294cff2e4a1b3fe15ff75d08855 16911 * 16912 * @param templateKey name of the microsyntax directive, like ngIf, ngFor, 16913 * without the *, along with its absolute span. 16914 */ 16915 16916 16917 parseTemplateBindings(templateKey) { 16918 const bindings = []; // The first binding is for the template key itself 16919 // In *ngFor="let item of items", key = "ngFor", value = null 16920 // In *ngIf="cond | pipe", key = "ngIf", value = "cond | pipe" 16921 16922 bindings.push(...this.parseDirectiveKeywordBindings(templateKey)); 16923 16924 while (this.index < this.tokens.length) { 16925 // If it starts with 'let', then this must be variable declaration 16926 const letBinding = this.parseLetBinding(); 16927 16928 if (letBinding) { 16929 bindings.push(letBinding); 16930 } else { 16931 // Two possible cases here, either `value "as" key` or 16932 // "directive-keyword expression". We don't know which case, but both 16933 // "value" and "directive-keyword" are template binding key, so consume 16934 // the key first. 16935 const key = this.expectTemplateBindingKey(); // Peek at the next token, if it is "as" then this must be variable 16936 // declaration. 16937 16938 const binding = this.parseAsBinding(key); 16939 16940 if (binding) { 16941 bindings.push(binding); 16942 } else { 16943 // Otherwise the key must be a directive keyword, like "of". Transform 16944 // the key to actual key. Eg. of -> ngForOf, trackBy -> ngForTrackBy 16945 key.source = templateKey.source + key.source.charAt(0).toUpperCase() + key.source.substring(1); 16946 bindings.push(...this.parseDirectiveKeywordBindings(key)); 16947 } 16948 } 16949 16950 this.consumeStatementTerminator(); 16951 } 16952 16953 return new TemplateBindingParseResult(bindings, [] 16954 /* warnings */ 16955 , this.errors); 16956 } 16957 16958 parseKeyedReadOrWrite(receiver, start, isSafe) { 16959 return this.withContext(ParseContextFlags.Writable, () => { 16960 this.rbracketsExpected++; 16961 const key = this.parsePipe(); 16962 16963 if (key instanceof EmptyExpr) { 16964 this.error(`Key access cannot be empty`); 16965 } 16966 16967 this.rbracketsExpected--; 16968 this.expectCharacter($RBRACKET); 16969 16970 if (this.consumeOptionalOperator('=')) { 16971 if (isSafe) { 16972 this.error('The \'?.\' operator cannot be used in the assignment'); 16973 } else { 16974 const value = this.parseConditional(); 16975 return new KeyedWrite(this.span(start), this.sourceSpan(start), receiver, key, value); 16976 } 16977 } else { 16978 return isSafe ? new SafeKeyedRead(this.span(start), this.sourceSpan(start), receiver, key) : new KeyedRead(this.span(start), this.sourceSpan(start), receiver, key); 16979 } 16980 16981 return new EmptyExpr(this.span(start), this.sourceSpan(start)); 16982 }); 16983 } 16984 /** 16985 * Parse a directive keyword, followed by a mandatory expression. 16986 * For example, "of items", "trackBy: func". 16987 * The bindings are: ngForOf -> items, ngForTrackBy -> func 16988 * There could be an optional "as" binding that follows the expression. 16989 * For example, 16990 * ``` 16991 * *ngFor="let item of items | slice:0:1 as collection". 16992 * ^^ ^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^ 16993 * keyword bound target optional 'as' binding 16994 * ``` 16995 * 16996 * @param key binding key, for example, ngFor, ngIf, ngForOf, along with its 16997 * absolute span. 16998 */ 16999 17000 17001 parseDirectiveKeywordBindings(key) { 17002 const bindings = []; 17003 this.consumeOptionalCharacter($COLON); // trackBy: trackByFunction 17004 17005 const value = this.getDirectiveBoundTarget(); 17006 let spanEnd = this.currentAbsoluteOffset; // The binding could optionally be followed by "as". For example, 17007 // *ngIf="cond | pipe as x". In this case, the key in the "as" binding 17008 // is "x" and the value is the template key itself ("ngIf"). Note that the 17009 // 'key' in the current context now becomes the "value" in the next binding. 17010
17011 const asBinding = this.parseAsBinding(key); 17012 17013 if (!asBinding) { 17014 this.consumeStatementTerminator(); 17015 spanEnd = this.currentAbsoluteOffset; 17016 } 17017 17018 const sourceSpan = new AbsoluteSourceSpan(key.span.start, spanEnd); 17019 bindings.push(new ExpressionBinding(sourceSpan, key, value)); 17020 17021 if (asBinding) { 17022 bindings.push(asBinding); 17023 } 17024 17025 return bindings; 17026 } 17027 /** 17028 * Return the expression AST for the bound target of a directive keyword 17029 * binding. For example, 17030 * ``` 17031 * *ngIf="condition | pipe" 17032 * ^^^^^^^^^^^^^^^^ bound target for "ngIf" 17033 * *ngFor="let item of items" 17034 * ^^^^^ bound target for "ngForOf" 17035 * ``` 17036 */ 17037 17038 17039 getDirectiveBoundTarget() { 17040 if (this.next === EOF || this.peekKeywordAs() || this.peekKeywordLet()) { 17041 return null; 17042 } 17043 17044 const ast = this.parsePipe(); // example: "condition | async" 17045 17046 const { 17047 start, 17048 end 17049 } = ast.span; 17050 const value = this.input.substring(start, end); 17051 return new ASTWithSource(ast, value, this.location, this.absoluteOffset + start, this.errors); 17052 } 17053 /** 17054 * Return the binding for a variable declared using `as`. Note that the order 17055 * of the key-value pair in this declaration is reversed. For example, 17056 * ``` 17057 * *ngFor="let item of items; index as i" 17058 * ^^^^^ ^ 17059 * value key 17060 * ``` 17061 * 17062 * @param value name of the value in the declaration, "ngIf" in the example 17063 * above, along with its absolute span. 17064 */ 17065 17066 17067 parseAsBinding(value) { 17068 if (!this.peekKeywordAs()) { 17069 return null; 17070 } 17071 17072 this.advance(); // consume the 'as' keyword 17073 17074 const key = this.expectTemplateBindingKey(); 17075 this.consumeStatementTerminator(); 17076 const sourceSpan = new AbsoluteSourceSpan(value.span.start, this.currentAbsoluteOffset); 17077 return new VariableBinding(sourceSpan, key, value); 17078 } 17079 /** 17080 * Return the binding for a variable declared using `let`. For example, 17081 * ``` 17082 * *ngFor="let item of items; let i=index;" 17083 * ^^^^^^^^ ^^^^^^^^^^^ 17084 * ``` 17085 * In the first binding, `item` is bound to `NgForOfContext.$implicit`. 17086 * In the second binding, `i` is bound to `NgForOfContext.index`. 17087 */ 17088 17089 17090 parseLetBinding() { 17091 if (!this.peekKeywordLet()) { 17092 return null; 17093 } 17094 17095 const spanStart = this.currentAbsoluteOffset; 17096 this.advance(); // consume the 'let' keyword 17097 17098 const key = this.expectTemplateBindingKey(); 17099 let value = null; 17100 17101 if (this.consumeOptionalOperator('=')) { 17102 value = this.expectTemplateBindingKey(); 17103 } 17104 17105 this.consumeStatementTerminator(); 17106 const sourceSpan = new AbsoluteSourceSpan(spanStart, this.currentAbsoluteOffset); 17107 return new VariableBinding(sourceSpan, key, value); 17108 } 17109 /** 17110 * Consume the optional statement terminator: semicolon or comma. 17111 */ 17112 17113 17114 consumeStatementTerminator() { 17115 this.consumeOptionalCharacter($SEMICOLON) || this.consumeOptionalCharacter($COMMA); 17116 } 17117 /** 17118 * Records an error and skips over the token stream until reaching a recoverable point. See 17119 * `this.skip` for more details on token skipping. 17120 */ 17121 17122 17123 error(message, index = null) { 17124 this.errors.push(new ParserError(message, this.input, this.locationText(index), this.location)); 17125 this.skip(); 17126 } 17127 17128 locationText(index = null) { 17129 if (index == null) index = this.index; 17130 return index < this.tokens.length ? `at column ${this.tokens[index].index + 1} in` : `at the end of the expression`; 17131 } 17132 /** 17133 * Records an error for an unexpected private identifier being discovered. 17134 * @param token Token representing a private identifier. 17135 * @param extraMessage Optional additional message being appended to the error. 17136 */ 17137 17138 17139 _reportErrorForPrivateIdentifier(token, extraMessage) { 17140 let errorMessage = `Private identifiers are not supported. Unexpected private identifier: ${token}`; 17141 17142 if (extraMessage !== null) { 17143 errorMessage += `, ${extraMessage}`; 17144 } 17145 17146 this.error(errorMessage); 17147 } 17148 /** 17149 * Error recovery should skip tokens until it encounters a recovery point. 17150 * 17151 * The following are treated as unconditional recovery points: 17152 * - end of input 17153 * - ';' (parseChain() is always the root production, and it expects a ';') 17154 * - '|' (since pipes may be chained and each pipe expression may be treated independently) 17155 * 17156 * The following are conditional recovery points: 17157 * - ')', '}', ']' if one of calling productions is expecting one of these symbols 17158 * - This allows skip() to recover from errors such as '(a.) + 1' allowing more of the AST to 17159 * be retained (it doesn't skip any tokens as the ')' is retained because of the '(' begins 17160 * an '(' <expr> ')' production). 17161 * The recovery points of grouping symbols must be conditional as they must be skipped if 17162 * none of the calling productions are not expecting the closing token else we will never 17163 * make progress in the case of an extraneous group closing symbol (such as a stray ')'). 17164 * That is, we skip a closing symbol if we are not in a grouping production. 17165 * - '=' in a `Writable` context
17166 * - In this context, we are able to recover after seeing the `=` operator, which 17167 * signals the presence of an independent rvalue expression following the `=` operator. 17168 * 17169 * If a production expects one of these token it increments the corresponding nesting count, 17170 * and then decrements it just prior to checking if the token is in the input. 17171 */ 17172 17173 17174 skip() { 17175 let n = this.next; 17176 17177 while (this.index < this.tokens.length && !n.isCharacter($SEMICOLON) && !n.isOperator('|') && (this.rparensExpected <= 0 || !n.isCharacter($RPAREN)) && (this.rbracesExpected <= 0 || !n.isCharacter($RBRACE)) && (this.rbracketsExpected <= 0 || !n.isCharacter($RBRACKET)) && (!(this.context & ParseContextFlags.Writable) || !n.isOperator('='))) { 17178 if (this.next.isError()) { 17179 this.errors.push(new ParserError(this.next.toString(), this.input, this.locationText(), this.location)); 17180 } 17181 17182 this.advance(); 17183 n = this.next; 17184 } 17185 } 17186 17187} 17188 17189class SimpleExpressionChecker extends RecursiveAstVisitor { 17190 constructor() { 17191 super(...arguments); 17192 this.errors = []; 17193 } 17194 17195 visitPipe() { 17196 this.errors.push('pipes'); 17197 } 17198 17199} 17200/** 17201 * Computes the real offset in the original template for indexes in an interpolation. 17202 * 17203 * Because templates can have encoded HTML entities and the input passed to the parser at this stage 17204 * of the compiler is the _decoded_ value, we need to compute the real offset using the original 17205 * encoded values in the interpolated tokens. Note that this is only a special case handling for 17206 * `MlParserTokenType.ENCODED_ENTITY` token types. All other interpolated tokens are expected to 17207 * have parts which exactly match the input string for parsing the interpolation. 17208 * 17209 * @param interpolatedTokens The tokens for the interpolated value. 17210 * 17211 * @returns A map of index locations in the decoded template to indexes in the original template 17212 */ 17213 17214 17215function getIndexMapForOriginalTemplate(interpolatedTokens) { 17216 let offsetMap = new Map(); 17217 let consumedInOriginalTemplate = 0; 17218 let consumedInInput = 0; 17219 let tokenIndex = 0; 17220 17221 while (tokenIndex < interpolatedTokens.length) { 17222 const currentToken = interpolatedTokens[tokenIndex]; 17223 17224 if (currentToken.type === 9 17225 /* MlParserTokenType.ENCODED_ENTITY */ 17226 ) { 17227 const [decoded, encoded] = currentToken.parts; 17228 consumedInOriginalTemplate += encoded.length; 17229 consumedInInput += decoded.length; 17230 } else { 17231 const lengthOfParts = currentToken.parts.reduce((sum, current) => sum + current.length, 0); 17232 consumedInInput += lengthOfParts; 17233 consumedInOriginalTemplate += lengthOfParts; 17234 } 17235 17236 offsetMap.set(consumedInInput, consumedInOriginalTemplate); 17237 tokenIndex++; 17238 } 17239 17240 return offsetMap; 17241} 17242/** 17243 * @license 17244 * Copyright Google LLC All Rights Reserved. 17245 * 17246 * Use of this source code is governed by an MIT-style license that can be 17247 * found in the LICENSE file at https://angular.io/license 17248 */ 17249 17250 17251class NodeWithI18n { 17252 constructor(sourceSpan, i18n) { 17253 this.sourceSpan = sourceSpan; 17254 this.i18n = i18n; 17255 } 17256 17257} 17258 17259class Text extends NodeWithI18n { 17260 constructor(value, sourceSpan, tokens, i18n) { 17261 super(sourceSpan, i18n); 17262 this.value = value; 17263 this.tokens = tokens; 17264 } 17265 17266 visit(visitor, context) { 17267 return visitor.visitText(this, context); 17268 } 17269 17270} 17271 17272class Expansion extends NodeWithI18n { 17273 constructor(switchValue, type, cases, sourceSpan, switchValueSourceSpan, i18n) { 17274 super(sourceSpan, i18n); 17275 this.switchValue = switchValue; 17276 this.type = type; 17277 this.cases = cases; 17278 this.switchValueSourceSpan = switchValueSourceSpan; 17279 } 17280 17281 visit(visitor, context) { 17282 return visitor.visitExpansion(this, context); 17283 } 17284 17285} 17286 17287class ExpansionCase { 17288 constructor(value, expression, sourceSpan, valueSourceSpan, expSourceSpan) { 17289 this.value = value; 17290 this.expression = expression; 17291 this.sourceSpan = sourceSpan; 17292 this.valueSourceSpan = valueSourceSpan; 17293 this.expSourceSpan = expSourceSpan; 17294 } 17295 17296 visit(visitor, context) { 17297 return visitor.visitExpansionCase(this, context); 17298 } 17299 17300} 17301 17302class Attribute extends NodeWithI18n { 17303 constructor(name, value, sourceSpan, keySpan, valueSpan, valueTokens, i18n) { 17304 super(sourceSpan, i18n); 17305 this.name = name; 17306 this.value = value; 17307 this.keySpan = keySpan; 17308 this.valueSpan = valueSpan; 17309 this.valueTokens = valueTokens; 17310 } 17311 17312 visit(visitor, context) { 17313 return visitor.visitAttribute(this, context); 17314 } 17315 17316} 17317 17318class Element extends NodeWithI18n { 17319 constructor(name, attrs, children, sourceSpan, startSourceSpan, endSourceSpan = null, i18n) { 17320 super(sourceSpan, i18n); 17321 this.name = name; 17322 this.attrs = attrs; 17323 this.children = children; 17324 this.startSourceSpan = startSourceSpan; 17325 this.endSourceSpan = endSourceSpan; 17326 } 17327 17328 visit(visitor, context) { 17329 return visitor.visitElement(this, context); 17330 } 17331 17332} 17333 17334class Comment {
17335 constructor(value, sourceSpan) { 17336 this.value = value; 17337 this.sourceSpan = sourceSpan; 17338 } 17339 17340 visit(visitor, context) { 17341 return visitor.visitComment(this, context); 17342 } 17343 17344} 17345 17346function visitAll(visitor, nodes, context = null) { 17347 const result = []; 17348 const visit = visitor.visit ? ast => visitor.visit(ast, context) || ast.visit(visitor, context) : ast => ast.visit(visitor, context); 17349 nodes.forEach(ast => { 17350 const astResult = visit(ast); 17351 17352 if (astResult) { 17353 result.push(astResult); 17354 } 17355 }); 17356 return result; 17357} 17358 17359class RecursiveVisitor { 17360 constructor() {} 17361 17362 visitElement(ast, context) { 17363 this.visitChildren(context, visit => { 17364 visit(ast.attrs); 17365 visit(ast.children); 17366 }); 17367 } 17368 17369 visitAttribute(ast, context) {} 17370 17371 visitText(ast, context) {} 17372 17373 visitComment(ast, context) {} 17374 17375 visitExpansion(ast, context) { 17376 return this.visitChildren(context, visit => { 17377 visit(ast.cases); 17378 }); 17379 } 17380 17381 visitExpansionCase(ast, context) {} 17382 17383 visitChildren(context, cb) { 17384 let results = []; 17385 let t = this; 17386 17387 function visit(children) { 17388 if (children) results.push(visitAll(t, children, context)); 17389 } 17390 17391 cb(visit); 17392 return Array.prototype.concat.apply([], results); 17393 } 17394 17395} 17396/** 17397 * @license 17398 * Copyright Google LLC All Rights Reserved. 17399 * 17400 * Use of this source code is governed by an MIT-style license that can be 17401 * found in the LICENSE file at https://angular.io/license 17402 */ 17403// Mapping between all HTML entity names and their unicode representation. 17404// Generated from https://html.spec.whatwg.org/multipage/entities.json by stripping 17405// the `&` and `;` from the keys and removing the duplicates. 17406// see https://www.w3.org/TR/html51/syntax.html#named-character-references 17407 17408 17409const NAMED_ENTITIES = { 17410 'AElig': '\u00C6', 17411 'AMP': '\u0026', 17412 'amp': '\u0026', 17413 'Aacute': '\u00C1', 17414 'Abreve': '\u0102', 17415 'Acirc': '\u00C2', 17416 'Acy': '\u0410', 17417 'Afr': '\uD835\uDD04', 17418 'Agrave': '\u00C0', 17419 'Alpha': '\u0391', 17420 'Amacr': '\u0100', 17421 'And': '\u2A53', 17422 'Aogon': '\u0104', 17423 'Aopf': '\uD835\uDD38', 17424 'ApplyFunction': '\u2061', 17425 'af': '\u2061', 17426 'Aring': '\u00C5', 17427 'angst': '\u00C5', 17428 'Ascr': '\uD835\uDC9C', 17429 'Assign': '\u2254', 17430 'colone': '\u2254', 17431 'coloneq': '\u2254', 17432 'Atilde': '\u00C3', 17433 'Auml': '\u00C4', 17434 'Backslash': '\u2216', 17435 'setminus': '\u2216', 17436 'setmn': '\u2216', 17437 'smallsetminus': '\u2216', 17438 'ssetmn': '\u2216', 17439 'Barv': '\u2AE7', 17440 'Barwed': '\u2306', 17441 'doublebarwedge': '\u2306', 17442 'Bcy': '\u0411', 17443 'Because': '\u2235', 17444 'becaus': '\u2235', 17445 'because': '\u2235', 17446 'Bernoullis': '\u212C', 17447 'Bscr': '\u212C', 17448 'bernou': '\u212C', 17449 'Beta': '\u0392', 17450 'Bfr': '\uD835\uDD05', 17451 'Bopf': '\uD835\uDD39', 17452 'Breve': '\u02D8', 17453 'breve': '\u02D8', 17454 'Bumpeq': '\u224E', 17455 'HumpDownHump': '\u224E', 17456 'bump': '\u224E', 17457 'CHcy': '\u0427', 17458 'COPY': '\u00A9', 17459 'copy': '\u00A9', 17460 'Cacute': '\u0106', 17461 'Cap': '\u22D2', 17462 'CapitalDifferentialD': '\u2145', 17463 'DD': '\u2145', 17464 'Cayleys': '\u212D', 17465 'Cfr': '\u212D', 17466 'Ccaron': '\u010C', 17467 'Ccedil': '\u00C7', 17468 'Ccirc': '\u0108', 17469 'Cconint': '\u2230', 17470 'Cdot': '\u010A', 17471 'Cedilla': '\u00B8', 17472 'cedil': '\u00B8', 17473 'CenterDot': '\u00B7', 17474 'centerdot': '\u00B7', 17475 'middot': '\u00B7', 17476 'Chi': '\u03A7', 17477 'CircleDot': '\u2299', 17478 'odot': '\u2299', 17479 'CircleMinus': '\u2296', 17480 'ominus': '\u2296', 17481 'CirclePlus': '\u2295', 17482 'oplus': '\u2295', 17483 'CircleTimes': '\u2297', 17484 'otimes': '\u2297', 17485 'ClockwiseContourIntegral': '\u2232', 17486 'cwconint': '\u2232', 17487 'CloseCurlyDoubleQuote': '\u201D', 17488 'rdquo': '\u201D', 17489 'rdquor': '\u201D', 17490 'CloseCurlyQuote': '\u2019', 17491 'rsquo': '\u2019', 17492 'rsquor': '\u2019', 17493 'Colon': '\u2237', 17494 'Proportion': '\u2237', 17495 'Colone': '\u2A74', 17496 'Congruent': '\u2261', 17497 'equiv': '\u2261', 17498 'Conint': '\u222F', 17499 'DoubleContourIntegral': '\u222F', 17500 'ContourIntegral': '\u222E', 17501 'conint': '\u222E', 17502 'oint': '\u222E', 17503 'Copf': '\u2102', 17504 'complexes': '\u2102', 17505 'Coproduct': '\u2210', 17506 'coprod': '\u2210', 17507 'CounterClockwiseContourIntegral': '\u2233', 17508 'awconint': '\u2233', 17509 'Cross': '\u2A2F', 17510 'Cscr': '\uD835\uDC9E', 17511 'Cup': '\u22D3', 17512 'CupCap': '\u224D', 17513 'asympeq': '\u224D', 17514 'DDotrahd': '\u2911', 17515 'DJcy': '\u0402', 17516 'DScy': '\u0405', 17517 'DZcy': '\u040F', 17518 'Dagger': '\u2021', 17519 'ddagger': '\u2021', 17520 'Darr': '\u21A1', 17521 'Dashv': '\u2AE4', 17522 'DoubleLeftTee': '\u2AE4', 17523 'Dcaron': '\u010E', 17524 'Dcy': '\u0414', 17525 'Del': '\u2207', 17526 'nabla': '\u2207', 17527 'Delta': '\u0394', 17528 'Dfr': '\uD835\uDD07', 17529 'DiacriticalAcute': '\u00B4', 17530 'acute': '\u00B4', 17531 'DiacriticalDot': '\u02D9', 17532 'dot': '\u02D9', 17533 'DiacriticalDoubleAcute': '\u02DD', 17534 'dblac': '\u02DD', 17535 'DiacriticalGrave': '\u0060', 17536 'grave': '\u0060', 17537 'DiacriticalTilde': '\u02DC', 17538 'tilde': '\u02DC', 17539 'Diamond': '\u22C4', 17540 'diam': '\u22C4', 17541 'diamond': '\u22C4', 17542 'DifferentialD': '\u2146', 17543 'dd': '\u2146', 17544 'Dopf': '\uD835\uDD3B', 17545 'Dot': '\u00A8', 17546 'DoubleDot': '\u00A8', 17547 'die': '\u00A8', 17548 'uml': '\u00A8', 17549 'DotDot': '\u20DC', 17550 'DotEqual': '\u2250', 17551 'doteq': '\u2250', 17552 'esdot': '\u2250', 17553 'DoubleDownArrow': '\u21D3', 17554 'Downarrow': '\u21D3', 17555 'dArr': '\u21D3', 17556 'DoubleLeftArrow': '\u21D0', 17557 'Leftarrow': '\u21D0', 17558 'lArr': '\u21D0', 17559 'DoubleLeftRightArrow': '\u21D4', 17560 'Leftrightarrow': '\u21D4', 17561 'hArr': '\u21D4', 17562 'iff': '\u21D4', 17563 'DoubleLongLeftArrow': '\u27F8', 17564 'Longleftarrow': '\u27F8', 17565 'xlArr': '\u27F8', 17566 'DoubleLongLeftRightArrow': '\u27FA', 17567 'Longleftrightarrow': '\u27FA', 17568 'xhArr': '\u27FA', 17569 'DoubleLongRightArrow': '\u27F9', 17570 'Longrightarrow': '\u27F9', 17571 'xrArr': '\u27F9', 17572 'DoubleRightArrow': '\u21D2', 17573 'Implies': '\u21D2', 17574 'Rightarrow': '\u21D2', 17575 'rArr': '\u21D2', 17576 'DoubleRightTee': '\u22A8', 17577 'vDash': '\u22A8', 17578 'DoubleUpArrow': '\u21D1', 17579 'Uparrow': '\u21D1', 17580 'uArr': '\u21D1', 17581 'DoubleUpDownArrow': '\u21D5', 17582 'Updownarrow': '\u21D5', 17583 'vArr': '\u21D5', 17584 'DoubleVerticalBar': '\u2225', 17585 'par': '\u2225', 17586 'parallel': '\u2225', 17587 'shortparallel': '\u2225', 17588 'spar': '\u2225', 17589 'DownArrow': '\u2193', 17590 'ShortDownArrow': '\u2193', 17591 'darr': '\u2193', 17592 'downarrow': '\u2193', 17593 'DownArrowBar': '\u2913', 17594 'DownArrowUpArrow': '\u21F5', 17595 'duarr': '\u21F5', 17596 'DownBreve': '\u0311', 17597 'DownLeftRightVector': '\u2950', 17598 'DownLeftTeeVector': '\u295E', 17599 'DownLeftVector': '\u21BD', 17600 'leftharpoondown': '\u21BD', 17601 'lhard': '\u21BD', 17602 'DownLeftVectorBar': '\u2956', 17603 'DownRightTeeVector': '\u295F', 17604 'DownRightVector': '\u21C1', 17605 'rhard': '\u21C1', 17606 'rightharpoondown': '\u21C1', 17607 'DownRightVectorBar': '\u2957', 17608 'DownTee': '\u22A4', 17609 'top': '\u22A4', 17610 'DownTeeArrow': '\u21A7', 17611 'mapstodown': '\u21A7', 17612 'Dscr': '\uD835\uDC9F', 17613 'Dstrok': '\u0110', 17614 'ENG': '\u014A', 17615 'ETH': '\u00D0', 17616 'Eacute': '\u00C9', 17617 'Ecaron': '\u011A', 17618 'Ecirc': '\u00CA', 17619 'Ecy': '\u042D', 17620 'Edot': '\u0116', 17621 'Efr': '\uD835\uDD08', 17622 'Egrave': '\u00C8', 17623 'Element': '\u2208', 17624 'in': '\u2208', 17625 'isin': '\u2208', 17626 'isinv': '\u2208', 17627 'Emacr': '\u0112', 17628 'EmptySmallSquare': '\u25FB', 17629 'EmptyVerySmallSquare': '\u25AB', 17630 'Eogon': '\u0118', 17631 'Eopf': '\uD835\uDD3C', 17632 'Epsilon': '\u0395', 17633 'Equal': '\u2A75', 17634 'EqualTilde': '\u2242', 17635 'eqsim': '\u2242', 17636 'esim': '\u2242', 17637 'Equilibrium': '\u21CC', 17638 'rightleftharpoons': '\u21CC', 17639 'rlhar': '\u21CC', 17640 'Escr': '\u2130', 17641 'expectation': '\u2130', 17642 'Esim': '\u2A73', 17643 'Eta': '\u0397', 17644 'Euml': '\u00CB', 17645 'Exists': '\u2203', 17646 'exist': '\u2203', 17647 'ExponentialE': '\u2147', 17648 'ee': '\u2147', 17649 'exponentiale': '\u2147', 17650 'Fcy': '\u0424', 17651 'Ffr': '\uD835\uDD09', 17652 'FilledSmallSquare': '\u25FC', 17653 'FilledVerySmallSquare': '\u25AA', 17654 'blacksquare': '\u25AA', 17655 'squarf': '\u25AA', 17656 'squf': '\u25AA', 17657 'Fopf': '\uD835\uDD3D', 17658 'ForAll': '\u2200', 17659 'forall': '\u2200', 17660 'Fouriertrf': '\u2131', 17661 'Fscr': '\u2131', 17662 'GJcy': '\u0403', 17663 'GT': '\u003E', 17664 'gt': '\u003E', 17665 'Gamma': '\u0393', 17666 'Gammad': '\u03DC', 17667 'Gbreve': '\u011E', 17668 'Gcedil': '\u0122', 17669 'Gcirc': '\u011C', 17670 'Gcy': '\u0413', 17671 'Gdot': '\u0120', 17672 'Gfr': '\uD835\uDD0A', 17673 'Gg': '\u22D9', 17674 'ggg': '\u22D9', 17675 'Gopf': '\uD835\uDD3E', 17676 'GreaterEqual': '\u2265', 17677 'ge': '\u2265', 17678 'geq': '\u2265', 17679 'GreaterEqualLess': '\u22DB', 17680 'gel': '\u22DB', 17681 'gtreqless': '\u22DB', 17682 'GreaterFullEqual': '\u2267', 17683 'gE': '\u2267', 17684 'geqq': '\u2267', 17685 'GreaterGreater': '\u2AA2', 17686 'GreaterLess': '\u2277', 17687 'gl': '\u2277', 17688 'gtrless': '\u2277', 17689 'GreaterSlantEqual': '\u2A7E', 17690 'geqslant': '\u2A7E', 17691 'ges': '\u2A7E', 17692 'GreaterTilde': '\u2273', 17693 'gsim': '\u2273', 17694 'gtrsim': '\u2273', 17695 'Gscr': '\uD835\uDCA2', 17696 'Gt': '\u226B', 17697 'NestedGreaterGreater': '\u226B', 17698 'gg': '\u226B', 17699 'HARDcy': '\u042A', 17700 'Hacek': '\u02C7', 17701 'caron': '\u02C7', 17702 'Hat': '\u005E', 17703 'Hcirc': '\u0124', 17704 'Hfr': '\u210C', 17705 'Poincareplane': '\u210C', 17706 'HilbertSpace': '\u210B', 17707 'Hscr': '\u210B', 17708 'hamilt': '\u210B', 17709 'Hopf': '\u210D', 17710 'quaternions': '\u210D', 17711 'HorizontalLine': '\u2500', 17712 'boxh': '\u2500', 17713 'Hstrok': '\u0126', 17714 'HumpEqual': '\u224F', 17715 'bumpe': '\u224F', 17716 'bumpeq': '\u224F', 17717 'IEcy': '\u0415', 17718 'IJlig': '\u0132', 17719 'IOcy': '\u0401', 17720 'Iacute': '\u00CD', 17721 'Icirc': '\u00CE', 17722 'Icy': '\u0418', 17723 'Idot': '\u0130', 17724 'Ifr': '\u2111', 17725 'Im': '\u2111', 17726 'image': '\u2111', 17727 'imagpart': '\u2111', 17728 'Igrave': '\u00CC', 17729 'Imacr': '\u012A', 17730 'ImaginaryI': '\u2148', 17731 'ii': '\u2148', 17732 'Int': '\u222C', 17733 'Integral': '\u222B', 17734 'int': '\u222B', 17735 'Intersection': '\u22C2', 17736 'bigcap': '\u22C2', 17737 'xcap': '\u22C2', 17738 'InvisibleComma': '\u2063', 17739 'ic': '\u2063', 17740 'InvisibleTimes': '\u2062', 17741 'it': '\u2062', 17742 'Iogon': '\u012E', 17743 'Iopf': '\uD835\uDD40', 17744 'Iota': '\u0399', 17745 'Iscr': '\u2110', 17746 'imagline': '\u2110', 17747 'Itilde': '\u0128', 17748 'Iukcy': '\u0406', 17749 'Iuml': '\u00CF', 17750 'Jcirc': '\u0134', 17751 'Jcy': '\u0419', 17752 'Jfr': '\uD835\uDD0D', 17753 'Jopf': '\uD835\uDD41', 17754 'Jscr': '\uD835\uDCA5', 17755 'Jsercy': '\u0408', 17756 'Jukcy': '\u0404', 17757 'KHcy': '\u0425', 17758 'KJcy': '\u040C', 17759 'Kappa': '\u039A', 17760 'Kcedil': '\u0136', 17761 'Kcy': '\u041A', 17762 'Kfr': '\uD835\uDD0E', 17763 'Kopf': '\uD835\uDD42', 17764 'Kscr': '\uD835\uDCA6', 17765 'LJcy': '\u0409', 17766 'LT': '\u003C', 17767 'lt': '\u003C', 17768 'Lacute': '\u0139', 17769 'Lambda': '\u039B', 17770 'Lang': '\u27EA', 17771 'Laplacetrf': '\u2112', 17772 'Lscr': '\u2112', 17773 'lagran': '\u2112', 17774 'Larr': '\u219E', 17775 'twoheadleftarrow': '\u219E', 17776 'Lcaron': '\u013D', 17777 'Lcedil': '\u013B', 17778 'Lcy': '\u041B', 17779 'LeftAngleBracket': '\u27E8', 17780 'lang': '\u27E8', 17781 'langle': '\u27E8', 17782 'LeftArrow': '\u2190', 17783 'ShortLeftArrow': '\u2190', 17784 'larr': '\u2190', 17785 'leftarrow': '\u2190', 17786 'slarr': '\u2190', 17787 'LeftArrowBar': '\u21E4', 17788 'larrb': '\u21E4', 17789 'LeftArrowRightArrow': '\u21C6', 17790 'leftrightarrows': '\u21C6', 17791 'lrarr': '\u21C6', 17792 'LeftCeiling': '\u2308', 17793 'lceil': '\u2308', 17794 'LeftDoubleBracket': '\u27E6', 17795 'lobrk': '\u27E6', 17796 'LeftDownTeeVector': '\u2961', 17797 'LeftDownVector': '\u21C3', 17798 'dharl': '\u21C3', 17799 'downharpoonleft': '\u21C3', 17800 'LeftDownVectorBar': '\u2959', 17801 'LeftFloor': '\u230A', 17802 'lfloor': '\u230A', 17803 'LeftRightArrow': '\u2194', 17804 'harr': '\u2194', 17805 'leftrightarrow': '\u2194', 17806 'LeftRightVector': '\u294E', 17807 'LeftTee': '\u22A3', 17808 'dashv': '\u22A3', 17809 'LeftTeeArrow': '\u21A4', 17810 'mapstoleft': '\u21A4', 17811 'LeftTeeVector': '\u295A', 17812 'LeftTriangle': '\u22B2', 17813 'vartriangleleft': '\u22B2', 17814 'vltri': '\u22B2', 17815 'LeftTriangleBar': '\u29CF', 17816 'LeftTriangleEqual': '\u22B4', 17817 'ltrie': '\u22B4', 17818 'trianglelefteq': '\u22B4', 17819 'LeftUpDownVector': '\u2951', 17820 'LeftUpTeeVector': '\u2960', 17821 'LeftUpVector': '\u21BF', 17822 'uharl': '\u21BF', 17823 'upharpoonleft': '\u21BF', 17824 'LeftUpVectorBar': '\u2958', 17825 'LeftVector': '\u21BC', 17826 'leftharpoonup': '\u21BC', 17827 'lharu': '\u21BC', 17828 'LeftVectorBar': '\u2952', 17829 'LessEqualGreater': '\u22DA', 17830 'leg': '\u22DA', 17831 'lesseqgtr': '\u22DA', 17832 'LessFullEqual': '\u2266', 17833 'lE': '\u2266', 17834 'leqq': '\u2266', 17835 'LessGreater': '\u2276', 17836 'lessgtr': '\u2276', 17837 'lg': '\u2276', 17838 'LessLess': '\u2AA1', 17839 'LessSlantEqual': '\u2A7D', 17840 'leqslant': '\u2A7D', 17841 'les': '\u2A7D', 17842 'LessTilde': '\u2272', 17843 'lesssim': '\u2272', 17844 'lsim': '\u2272', 17845 'Lfr': '\uD835\uDD0F', 17846 'Ll': '\u22D8', 17847 'Lleftarrow': '\u21DA', 17848 'lAarr': '\u21DA', 17849 'Lmidot': '\u013F', 17850 'LongLeftArrow': '\u27F5', 17851 'longleftarrow': '\u27F5', 17852 'xlarr': '\u27F5', 17853 'LongLeftRightArrow': '\u27F7', 17854 'longleftrightarrow': '\u27F7', 17855 'xharr': '\u27F7', 17856 'LongRightArrow': '\u27F6', 17857 'longrightarrow': '\u27F6', 17858 'xrarr': '\u27F6', 17859 'Lopf': '\uD835\uDD43', 17860 'LowerLeftArrow': '\u2199', 17861 'swarr': '\u2199', 17862 'swarrow': '\u2199', 17863 'LowerRightArrow': '\u2198', 17864 'searr': '\u2198', 17865 'searrow': '\u2198', 17866 'Lsh': '\u21B0', 17867 'lsh': '\u21B0', 17868 'Lstrok': '\u0141', 17869 'Lt': '\u226A', 17870 'NestedLessLess': '\u226A', 17871 'll': '\u226A', 17872 'Map': '\u2905', 17873 'Mcy': '\u041C', 17874 'MediumSpace': '\u205F', 17875 'Mellintrf': '\u2133', 17876 'Mscr': '\u2133', 17877 'phmmat': '\u2133', 17878 'Mfr': '\uD835\uDD10', 17879 'MinusPlus': '\u2213', 17880 'mnplus': '\u2213', 17881 'mp': '\u2213', 17882 'Mopf': '\uD835\uDD44', 17883 'Mu': '\u039C', 17884 'NJcy': '\u040A', 17885 'Nacute': '\u0143', 17886 'Ncaron': '\u0147', 17887 'Ncedil': '\u0145', 17888 'Ncy': '\u041D', 17889 'NegativeMediumSpace': '\u200B', 17890 'NegativeThickSpace': '\u200B', 17891 'NegativeThinSpace': '\u200B', 17892 'NegativeVeryThinSpace': '\u200B', 17893 'ZeroWidthSpace': '\u200B', 17894 'NewLine': '\u000A', 17895 'Nfr': '\uD835\uDD11', 17896 'NoBreak': '\u2060', 17897 'NonBreakingSpace': '\u00A0', 17898 'nbsp': '\u00A0', 17899 'Nopf': '\u2115', 17900 'naturals': '\u2115', 17901 'Not': '\u2AEC', 17902 'NotCongruent': '\u2262', 17903 'nequiv': '\u2262', 17904 'NotCupCap': '\u226D', 17905 'NotDoubleVerticalBar': '\u2226', 17906 'npar': '\u2226', 17907 'nparallel': '\u2226', 17908 'nshortparallel': '\u2226', 17909 'nspar': '\u2226', 17910 'NotElement': '\u2209', 17911 'notin': '\u2209', 17912 'notinva': '\u2209', 17913 'NotEqual': '\u2260', 17914 'ne': '\u2260', 17915 'NotEqualTilde': '\u2242\u0338', 17916 'nesim': '\u2242\u0338', 17917 'NotExists': '\u2204', 17918 'nexist': '\u2204', 17919 'nexists': '\u2204', 17920 'NotGreater': '\u226F', 17921 'ngt': '\u226F', 17922 'ngtr': '\u226F', 17923 'NotGreaterEqual': '\u2271', 17924 'nge': '\u2271', 17925 'ngeq': '\u2271', 17926 'NotGreaterFullEqual': '\u2267\u0338', 17927 'ngE': '\u2267\u0338', 17928 'ngeqq': '\u2267\u0338', 17929 'NotGreaterGreater': '\u226B\u0338', 17930 'nGtv': '\u226B\u0338', 17931 'NotGreaterLess': '\u2279', 17932 'ntgl': '\u2279', 17933 'NotGreaterSlantEqual': '\u2A7E\u0338', 17934 'ngeqslant': '\u2A7E\u0338', 17935 'nges': '\u2A7E\u0338', 17936 'NotGreaterTilde': '\u2275', 17937 'ngsim': '\u2275', 17938 'NotHumpDownHump': '\u224E\u0338', 17939 'nbump': '\u224E\u0338', 17940 'NotHumpEqual': '\u224F\u0338', 17941 'nbumpe': '\u224F\u0338', 17942 'NotLeftTriangle': '\u22EA', 17943 'nltri': '\u22EA', 17944 'ntriangleleft': '\u22EA', 17945 'NotLeftTriangleBar': '\u29CF\u0338', 17946 'NotLeftTriangleEqual': '\u22EC',
17947 'nltrie': '\u22EC', 17948 'ntrianglelefteq': '\u22EC', 17949 'NotLess': '\u226E', 17950 'nless': '\u226E', 17951 'nlt': '\u226E', 17952 'NotLessEqual': '\u2270', 17953 'nle': '\u2270', 17954 'nleq': '\u2270', 17955 'NotLessGreater': '\u2278', 17956 'ntlg': '\u2278', 17957 'NotLessLess': '\u226A\u0338', 17958 'nLtv': '\u226A\u0338', 17959 'NotLessSlantEqual': '\u2A7D\u0338', 17960 'nleqslant': '\u2A7D\u0338', 17961 'nles': '\u2A7D\u0338', 17962 'NotLessTilde': '\u2274', 17963 'nlsim': '\u2274', 17964 'NotNestedGreaterGreater': '\u2AA2\u0338', 17965 'NotNestedLessLess': '\u2AA1\u0338', 17966 'NotPrecedes': '\u2280', 17967 'npr': '\u2280', 17968 'nprec': '\u2280', 17969 'NotPrecedesEqual': '\u2AAF\u0338', 17970 'npre': '\u2AAF\u0338', 17971 'npreceq': '\u2AAF\u0338', 17972 'NotPrecedesSlantEqual': '\u22E0', 17973 'nprcue': '\u22E0', 17974 'NotReverseElement': '\u220C', 17975 'notni': '\u220C', 17976 'notniva': '\u220C', 17977 'NotRightTriangle': '\u22EB', 17978 'nrtri': '\u22EB', 17979 'ntriangleright': '\u22EB', 17980 'NotRightTriangleBar': '\u29D0\u0338', 17981 'NotRightTriangleEqual': '\u22ED', 17982 'nrtrie': '\u22ED', 17983 'ntrianglerighteq': '\u22ED', 17984 'NotSquareSubset': '\u228F\u0338', 17985 'NotSquareSubsetEqual': '\u22E2', 17986 'nsqsube': '\u22E2', 17987 'NotSquareSuperset': '\u2290\u0338', 17988 'NotSquareSupersetEqual': '\u22E3', 17989 'nsqsupe': '\u22E3', 17990 'NotSubset': '\u2282\u20D2', 17991 'nsubset': '\u2282\u20D2', 17992 'vnsub': '\u2282\u20D2', 17993 'NotSubsetEqual': '\u2288', 17994 'nsube': '\u2288', 17995 'nsubseteq': '\u2288', 17996 'NotSucceeds': '\u2281', 17997 'nsc': '\u2281', 17998 'nsucc': '\u2281', 17999 'NotSucceedsEqual': '\u2AB0\u0338', 18000 'nsce': '\u2AB0\u0338', 18001 'nsucceq': '\u2AB0\u0338', 18002 'NotSucceedsSlantEqual': '\u22E1', 18003 'nsccue': '\u22E1', 18004 'NotSucceedsTilde': '\u227F\u0338', 18005 'NotSuperset': '\u2283\u20D2', 18006 'nsupset': '\u2283\u20D2', 18007 'vnsup': '\u2283\u20D2', 18008 'NotSupersetEqual': '\u2289', 18009 'nsupe': '\u2289', 18010 'nsupseteq': '\u2289', 18011 'NotTilde': '\u2241', 18012 'nsim': '\u2241', 18013 'NotTildeEqual': '\u2244', 18014 'nsime': '\u2244', 18015 'nsimeq': '\u2244', 18016 'NotTildeFullEqual': '\u2247', 18017 'ncong': '\u2247', 18018 'NotTildeTilde': '\u2249', 18019 'nap': '\u2249', 18020 'napprox': '\u2249', 18021 'NotVerticalBar': '\u2224', 18022 'nmid': '\u2224', 18023 'nshortmid': '\u2224', 18024 'nsmid': '\u2224', 18025 'Nscr': '\uD835\uDCA9', 18026 'Ntilde': '\u00D1', 18027 'Nu': '\u039D', 18028 'OElig': '\u0152', 18029 'Oacute': '\u00D3', 18030 'Ocirc': '\u00D4', 18031 'Ocy': '\u041E', 18032 'Odblac': '\u0150', 18033 'Ofr': '\uD835\uDD12', 18034 'Ograve': '\u00D2', 18035 'Omacr': '\u014C', 18036 'Omega': '\u03A9', 18037 'ohm': '\u03A9', 18038 'Omicron': '\u039F', 18039 'Oopf': '\uD835\uDD46', 18040 'OpenCurlyDoubleQuote': '\u201C', 18041 'ldquo': '\u201C', 18042 'OpenCurlyQuote': '\u2018', 18043 'lsquo': '\u2018', 18044 'Or': '\u2A54', 18045 'Oscr': '\uD835\uDCAA', 18046 'Oslash': '\u00D8', 18047 'Otilde': '\u00D5', 18048 'Otimes': '\u2A37', 18049 'Ouml': '\u00D6', 18050 'OverBar': '\u203E', 18051 'oline': '\u203E', 18052 'OverBrace': '\u23DE', 18053 'OverBracket': '\u23B4', 18054 'tbrk': '\u23B4', 18055 'OverParenthesis': '\u23DC', 18056 'PartialD': '\u2202', 18057 'part': '\u2202', 18058 'Pcy': '\u041F', 18059 'Pfr': '\uD835\uDD13', 18060 'Phi': '\u03A6', 18061 'Pi': '\u03A0', 18062 'PlusMinus': '\u00B1', 18063 'plusmn': '\u00B1', 18064 'pm': '\u00B1', 18065 'Popf': '\u2119', 18066 'primes': '\u2119', 18067 'Pr': '\u2ABB', 18068 'Precedes': '\u227A', 18069 'pr': '\u227A', 18070 'prec': '\u227A', 18071 'PrecedesEqual': '\u2AAF', 18072 'pre': '\u2AAF', 18073 'preceq': '\u2AAF', 18074 'PrecedesSlantEqual': '\u227C', 18075 'prcue': '\u227C', 18076 'preccurlyeq': '\u227C', 18077 'PrecedesTilde': '\u227E', 18078 'precsim': '\u227E', 18079 'prsim': '\u227E', 18080 'Prime': '\u2033', 18081 'Product': '\u220F', 18082 'prod': '\u220F', 18083 'Proportional': '\u221D', 18084 'prop': '\u221D', 18085 'propto': '\u221D', 18086 'varpropto': '\u221D', 18087 'vprop': '\u221D', 18088 'Pscr': '\uD835\uDCAB', 18089 'Psi': '\u03A8', 18090 'QUOT': '\u0022', 18091 'quot': '\u0022', 18092 'Qfr': '\uD835\uDD14', 18093 'Qopf': '\u211A', 18094 'rationals': '\u211A', 18095 'Qscr': '\uD835\uDCAC', 18096 'RBarr': '\u2910', 18097 'drbkarow': '\u2910', 18098 'REG': '\u00AE', 18099 'circledR': '\u00AE', 18100 'reg': '\u00AE', 18101 'Racute': '\u0154', 18102 'Rang': '\u27EB', 18103 'Rarr': '\u21A0', 18104 'twoheadrightarrow': '\u21A0', 18105 'Rarrtl': '\u2916', 18106 'Rcaron': '\u0158', 18107 'Rcedil': '\u0156', 18108 'Rcy': '\u0420', 18109 'Re': '\u211C', 18110 'Rfr': '\u211C', 18111 'real': '\u211C', 18112 'realpart': '\u211C', 18113 'ReverseElement': '\u220B', 18114 'SuchThat': '\u220B', 18115 'ni': '\u220B', 18116 'niv': '\u220B', 18117 'ReverseEquilibrium': '\u21CB', 18118 'leftrightharpoons': '\u21CB', 18119 'lrhar': '\u21CB', 18120 'ReverseUpEquilibrium': '\u296F', 18121 'duhar': '\u296F', 18122 'Rho': '\u03A1', 18123 'RightAngleBracket': '\u27E9', 18124 'rang': '\u27E9', 18125 'rangle': '\u27E9', 18126 'RightArrow': '\u2192', 18127 'ShortRightArrow': '\u2192', 18128 'rarr': '\u2192', 18129 'rightarrow': '\u2192', 18130 'srarr': '\u2192', 18131 'RightArrowBar': '\u21E5', 18132 'rarrb': '\u21E5', 18133 'RightArrowLeftArrow': '\u21C4', 18134 'rightleftarrows': '\u21C4', 18135 'rlarr': '\u21C4', 18136 'RightCeiling': '\u2309',
18137 'rceil': '\u2309', 18138 'RightDoubleBracket': '\u27E7', 18139 'robrk': '\u27E7', 18140 'RightDownTeeVector': '\u295D', 18141 'RightDownVector': '\u21C2', 18142 'dharr': '\u21C2', 18143 'downharpoonright': '\u21C2', 18144 'RightDownVectorBar': '\u2955', 18145 'RightFloor': '\u230B', 18146 'rfloor': '\u230B', 18147 'RightTee': '\u22A2', 18148 'vdash': '\u22A2', 18149 'RightTeeArrow': '\u21A6', 18150 'map': '\u21A6', 18151 'mapsto': '\u21A6', 18152 'RightTeeVector': '\u295B', 18153 'RightTriangle': '\u22B3', 18154 'vartriangleright': '\u22B3', 18155 'vrtri': '\u22B3', 18156 'RightTriangleBar': '\u29D0', 18157 'RightTriangleEqual': '\u22B5', 18158 'rtrie': '\u22B5', 18159 'trianglerighteq': '\u22B5', 18160 'RightUpDownVector': '\u294F', 18161 'RightUpTeeVector': '\u295C', 18162 'RightUpVector': '\u21BE', 18163 'uharr': '\u21BE', 18164 'upharpoonright': '\u21BE', 18165 'RightUpVectorBar': '\u2954', 18166 'RightVector': '\u21C0', 18167 'rharu': '\u21C0', 18168 'rightharpoonup': '\u21C0', 18169 'RightVectorBar': '\u2953', 18170 'Ropf': '\u211D', 18171 'reals': '\u211D', 18172 'RoundImplies': '\u2970', 18173 'Rrightarrow': '\u21DB', 18174 'rAarr': '\u21DB', 18175 'Rscr': '\u211B', 18176 'realine': '\u211B', 18177 'Rsh': '\u21B1', 18178 'rsh': '\u21B1', 18179 'RuleDelayed': '\u29F4', 18180 'SHCHcy': '\u0429', 18181 'SHcy': '\u0428', 18182 'SOFTcy': '\u042C', 18183 'Sacute': '\u015A', 18184 'Sc': '\u2ABC', 18185 'Scaron': '\u0160', 18186 'Scedil': '\u015E', 18187 'Scirc': '\u015C', 18188 'Scy': '\u0421', 18189 'Sfr': '\uD835\uDD16', 18190 'ShortUpArrow': '\u2191', 18191 'UpArrow': '\u2191', 18192 'uarr': '\u2191', 18193 'uparrow': '\u2191', 18194 'Sigma': '\u03A3', 18195 'SmallCircle': '\u2218', 18196 'compfn': '\u2218', 18197 'Sopf': '\uD835\uDD4A', 18198 'Sqrt': '\u221A', 18199 'radic': '\u221A', 18200 'Square': '\u25A1', 18201 'squ': '\u25A1', 18202 'square': '\u25A1', 18203 'SquareIntersection': '\u2293', 18204 'sqcap': '\u2293', 18205 'SquareSubset': '\u228F', 18206 'sqsub': '\u228F', 18207 'sqsubset': '\u228F', 18208 'SquareSubsetEqual': '\u2291', 18209 'sqsube': '\u2291', 18210 'sqsubseteq': '\u2291', 18211 'SquareSuperset': '\u2290', 18212 'sqsup': '\u2290', 18213 'sqsupset': '\u2290', 18214 'SquareSupersetEqual': '\u2292', 18215 'sqsupe': '\u2292', 18216 'sqsupseteq': '\u2292', 18217 'SquareUnion': '\u2294', 18218 'sqcup': '\u2294', 18219 'Sscr': '\uD835\uDCAE', 18220 'Star': '\u22C6', 18221 'sstarf': '\u22C6', 18222 'Sub': '\u22D0', 18223 'Subset': '\u22D0', 18224 'SubsetEqual': '\u2286', 18225 'sube': '\u2286', 18226 'subseteq': '\u2286', 18227 'Succeeds': '\u227B', 18228 'sc': '\u227B', 18229 'succ': '\u227B', 18230 'SucceedsEqual': '\u2AB0', 18231 'sce': '\u2AB0', 18232 'succeq': '\u2AB0', 18233 'SucceedsSlantEqual': '\u227D', 18234 'sccue': '\u227D', 18235 'succcurlyeq': '\u227D', 18236 'SucceedsTilde': '\u227F', 18237 'scsim': '\u227F', 18238 'succsim': '\u227F', 18239 'Sum': '\u2211', 18240 'sum': '\u2211', 18241 'Sup': '\u22D1', 18242 'Supset': '\u22D1', 18243 'Superset': '\u2283', 18244 'sup': '\u2283', 18245 'supset': '\u2283', 18246 'SupersetEqual': '\u2287', 18247 'supe': '\u2287', 18248 'supseteq': '\u2287', 18249 'THORN': '\u00DE', 18250 'TRADE': '\u2122', 18251 'trade': '\u2122', 18252 'TSHcy': '\u040B', 18253 'TScy': '\u0426', 18254 'Tab': '\u0009', 18255 'Tau': '\u03A4', 18256 'Tcaron': '\u0164', 18257 'Tcedil': '\u0162', 18258 'Tcy': '\u0422', 18259 'Tfr': '\uD835\uDD17', 18260 'Therefore': '\u2234', 18261 'there4': '\u2234', 18262 'therefore': '\u2234', 18263 'Theta': '\u0398', 18264 'ThickSpace': '\u205F\u200A', 18265 'ThinSpace': '\u2009', 18266 'thinsp': '\u2009', 18267 'Tilde': '\u223C', 18268 'sim': '\u223C', 18269 'thicksim': '\u223C', 18270 'thksim': '\u223C', 18271 'TildeEqual': '\u2243', 18272 'sime': '\u2243', 18273 'simeq': '\u2243', 18274 'TildeFullEqual': '\u2245', 18275 'cong': '\u2245', 18276 'TildeTilde': '\u2248', 18277 'ap': '\u2248', 18278 'approx': '\u2248', 18279 'asymp': '\u2248', 18280 'thickapprox': '\u2248', 18281 'thkap': '\u2248', 18282 'Topf': '\uD835\uDD4B', 18283 'TripleDot': '\u20DB', 18284 'tdot': '\u20DB', 18285 'Tscr': '\uD835\uDCAF', 18286 'Tstrok': '\u0166', 18287 'Uacute': '\u00DA', 18288 'Uarr': '\u219F', 18289 'Uarrocir': '\u2949', 18290 'Ubrcy': '\u040E', 18291 'Ubreve': '\u016C', 18292 'Ucirc': '\u00DB', 18293 'Ucy': '\u0423', 18294 'Udblac': '\u0170', 18295 'Ufr': '\uD835\uDD18', 18296 'Ugrave': '\u00D9', 18297 'Umacr': '\u016A', 18298 'UnderBar': '\u005F', 18299 'lowbar': '\u005F', 18300 'UnderBrace': '\u23DF', 18301 'UnderBracket': '\u23B5', 18302 'bbrk': '\u23B5', 18303 'UnderParenthesis': '\u23DD', 18304 'Union': '\u22C3', 18305 'bigcup': '\u22C3', 18306 'xcup': '\u22C3', 18307 'UnionPlus': '\u228E', 18308 'uplus': '\u228E', 18309 'Uogon': '\u0172', 18310 'Uopf': '\uD835\uDD4C', 18311 'UpArrowBar': '\u2912', 18312 'UpArrowDownArrow': '\u21C5', 18313 'udarr': '\u21C5', 18314 'UpDownArrow': '\u2195', 18315 'updownarrow': '\u2195', 18316 'varr': '\u2195', 18317 'UpEquilibrium': '\u296E', 18318 'udhar': '\u296E', 18319 'UpTee': '\u22A5', 18320 'bot': '\u22A5', 18321 'bottom': '\u22A5', 18322 'perp': '\u22A5', 18323 'UpTeeArrow': '\u21A5', 18324 'mapstoup': '\u21A5', 18325 'UpperLeftArrow': '\u2196', 18326 'nwarr': '\u2196', 18327 'nwarrow': '\u2196', 18328 'UpperRightArrow': '\u2197', 18329 'nearr': '\u2197', 18330 'nearrow': '\u2197', 18331 'Upsi': '\u03D2', 18332 'upsih': '\u03D2', 18333 'Upsilon': '\u03A5', 18334 'Uring': '\u016E', 18335 'Uscr': '\uD835\uDCB0', 18336 'Utilde': '\u0168', 18337 'Uuml': '\u00DC',
18338 'VDash': '\u22AB', 18339 'Vbar': '\u2AEB', 18340 'Vcy': '\u0412', 18341 'Vdash': '\u22A9', 18342 'Vdashl': '\u2AE6', 18343 'Vee': '\u22C1', 18344 'bigvee': '\u22C1', 18345 'xvee': '\u22C1', 18346 'Verbar': '\u2016', 18347 'Vert': '\u2016', 18348 'VerticalBar': '\u2223', 18349 'mid': '\u2223', 18350 'shortmid': '\u2223', 18351 'smid': '\u2223', 18352 'VerticalLine': '\u007C', 18353 'verbar': '\u007C', 18354 'vert': '\u007C', 18355 'VerticalSeparator': '\u2758', 18356 'VerticalTilde': '\u2240', 18357 'wr': '\u2240', 18358 'wreath': '\u2240', 18359 'VeryThinSpace': '\u200A', 18360 'hairsp': '\u200A', 18361 'Vfr': '\uD835\uDD19', 18362 'Vopf': '\uD835\uDD4D', 18363 'Vscr': '\uD835\uDCB1', 18364 'Vvdash': '\u22AA', 18365 'Wcirc': '\u0174', 18366 'Wedge': '\u22C0', 18367 'bigwedge': '\u22C0', 18368 'xwedge': '\u22C0', 18369 'Wfr': '\uD835\uDD1A', 18370 'Wopf': '\uD835\uDD4E', 18371 'Wscr': '\uD835\uDCB2', 18372 'Xfr': '\uD835\uDD1B', 18373 'Xi': '\u039E', 18374 'Xopf': '\uD835\uDD4F', 18375 'Xscr': '\uD835\uDCB3', 18376 'YAcy': '\u042F', 18377 'YIcy': '\u0407', 18378 'YUcy': '\u042E', 18379 'Yacute': '\u00DD', 18380 'Ycirc': '\u0176', 18381 'Ycy': '\u042B', 18382 'Yfr': '\uD835\uDD1C', 18383 'Yopf': '\uD835\uDD50', 18384 'Yscr': '\uD835\uDCB4', 18385 'Yuml': '\u0178', 18386 'ZHcy': '\u0416', 18387 'Zacute': '\u0179', 18388 'Zcaron': '\u017D', 18389 'Zcy': '\u0417', 18390 'Zdot': '\u017B', 18391 'Zeta': '\u0396', 18392 'Zfr': '\u2128', 18393 'zeetrf': '\u2128', 18394 'Zopf': '\u2124', 18395 'integers': '\u2124', 18396 'Zscr': '\uD835\uDCB5', 18397 'aacute': '\u00E1', 18398 'abreve': '\u0103', 18399 'ac': '\u223E', 18400 'mstpos': '\u223E', 18401 'acE': '\u223E\u0333', 18402 'acd': '\u223F', 18403 'acirc': '\u00E2', 18404 'acy': '\u0430', 18405 'aelig': '\u00E6', 18406 'afr': '\uD835\uDD1E', 18407 'agrave': '\u00E0', 18408 'alefsym': '\u2135', 18409 'aleph': '\u2135', 18410 'alpha': '\u03B1', 18411 'amacr': '\u0101', 18412 'amalg': '\u2A3F', 18413 'and': '\u2227', 18414 'wedge': '\u2227', 18415 'andand': '\u2A55', 18416 'andd': '\u2A5C', 18417 'andslope': '\u2A58', 18418 'andv': '\u2A5A', 18419 'ang': '\u2220', 18420 'angle': '\u2220', 18421 'ange': '\u29A4', 18422 'angmsd': '\u2221', 18423 'measuredangle': '\u2221', 18424 'angmsdaa': '\u29A8', 18425 'angmsdab': '\u29A9', 18426 'angmsdac': '\u29AA', 18427 'angmsdad': '\u29AB', 18428 'angmsdae': '\u29AC', 18429 'angmsdaf': '\u29AD', 18430 'angmsdag': '\u29AE', 18431 'angmsdah': '\u29AF', 18432 'angrt': '\u221F', 18433 'angrtvb': '\u22BE', 18434 'angrtvbd': '\u299D', 18435 'angsph': '\u2222', 18436 'angzarr': '\u237C', 18437 'aogon': '\u0105', 18438 'aopf': '\uD835\uDD52', 18439 'apE': '\u2A70', 18440 'apacir': '\u2A6F', 18441 'ape': '\u224A', 18442 'approxeq': '\u224A', 18443 'apid': '\u224B', 18444 'apos': '\u0027', 18445 'aring': '\u00E5', 18446 'ascr': '\uD835\uDCB6', 18447 'ast': '\u002A', 18448 'midast': '\u002A', 18449 'atilde': '\u00E3', 18450 'auml': '\u00E4', 18451 'awint': '\u2A11', 18452 'bNot': '\u2AED', 18453 'backcong': '\u224C', 18454 'bcong': '\u224C', 18455 'backepsilon': '\u03F6', 18456 'bepsi': '\u03F6', 18457 'backprime': '\u2035', 18458 'bprime': '\u2035', 18459 'backsim': '\u223D', 18460 'bsim': '\u223D', 18461 'backsimeq': '\u22CD', 18462 'bsime': '\u22CD', 18463 'barvee': '\u22BD', 18464 'barwed': '\u2305', 18465 'barwedge': '\u2305', 18466 'bbrktbrk': '\u23B6', 18467 'bcy': '\u0431', 18468 'bdquo': '\u201E', 18469 'ldquor': '\u201E', 18470 'bemptyv': '\u29B0', 18471 'beta': '\u03B2', 18472 'beth': '\u2136', 18473 'between': '\u226C', 18474 'twixt': '\u226C', 18475 'bfr': '\uD835\uDD1F', 18476 'bigcirc': '\u25EF', 18477 'xcirc': '\u25EF', 18478 'bigodot': '\u2A00', 18479 'xodot': '\u2A00', 18480 'bigoplus': '\u2A01', 18481 'xoplus': '\u2A01', 18482 'bigotimes': '\u2A02', 18483 'xotime': '\u2A02', 18484 'bigsqcup': '\u2A06', 18485 'xsqcup': '\u2A06', 18486 'bigstar': '\u2605', 18487 'starf': '\u2605', 18488 'bigtriangledown': '\u25BD', 18489 'xdtri': '\u25BD', 18490 'bigtriangleup': '\u25B3', 18491 'xutri': '\u25B3', 18492 'biguplus': '\u2A04', 18493 'xuplus': '\u2A04', 18494 'bkarow': '\u290D', 18495 'rbarr': '\u290D', 18496 'blacklozenge': '\u29EB', 18497 'lozf': '\u29EB', 18498 'blacktriangle': '\u25B4', 18499 'utrif': '\u25B4', 18500 'blacktriangledown': '\u25BE', 18501 'dtrif': '\u25BE', 18502 'blacktriangleleft': '\u25C2', 18503 'ltrif': '\u25C2', 18504 'blacktriangleright': '\u25B8', 18505 'rtrif': '\u25B8', 18506 'blank': '\u2423', 18507 'blk12': '\u2592', 18508 'blk14': '\u2591', 18509 'blk34': '\u2593', 18510 'block': '\u2588', 18511 'bne': '\u003D\u20E5', 18512 'bnequiv': '\u2261\u20E5', 18513 'bnot': '\u2310', 18514 'bopf': '\uD835\uDD53', 18515 'bowtie': '\u22C8', 18516 'boxDL': '\u2557', 18517 'boxDR': '\u2554', 18518 'boxDl': '\u2556', 18519 'boxDr': '\u2553', 18520 'boxH': '\u2550', 18521 'boxHD': '\u2566', 18522 'boxHU': '\u2569', 18523 'boxHd': '\u2564', 18524 'boxHu': '\u2567', 18525 'boxUL': '\u255D', 18526 'boxUR': '\u255A', 18527 'boxUl': '\u255C', 18528 'boxUr': '\u2559', 18529 'boxV': '\u2551', 18530 'boxVH': '\u256C', 18531 'boxVL': '\u2563', 18532 'boxVR': '\u2560', 18533 'boxVh': '\u256B', 18534 'boxVl': '\u2562', 18535 'boxVr': '\u255F', 18536 'boxbox': '\u29C9', 18537 'boxdL': '\u2555', 18538 'boxdR': '\u2552', 18539 'boxdl': '\u2510', 18540 'boxdr': '\u250C', 18541 'boxhD': '\u2565', 18542 'boxhU': '\u2568', 18543 'boxhd': '\u252C', 18544 'boxhu': '\u2534', 18545 'boxminus': '\u229F', 18546 'minusb': '\u229F', 18547 'boxplus': '\u229E', 18548 'plusb': '\u229E', 18549 'boxtimes': '\u22A0', 18550 'timesb': '\u22A0', 18551 'boxuL': '\u255B', 18552 'boxuR': '\u2558', 18553 'boxul': '\u2518', 18554 'boxur': '\u2514', 18555 'boxv': '\u2502', 18556 'boxvH': '\u256A', 18557 'boxvL': '\u2561', 18558 'boxvR': '\u255E', 18559 'boxvh': '\u253C', 18560 'boxvl': '\u2524', 18561 'boxvr': '\u251C', 18562 'brvbar': '\u00A6', 18563 'bscr': '\uD835\uDCB7', 18564 'bsemi': '\u204F', 18565 'bsol': '\u005C', 18566 'bsolb': '\u29C5', 18567 'bsolhsub': '\u27C8', 18568 'bull': '\u2022', 18569 'bullet': '\u2022', 18570 'bumpE': '\u2AAE', 18571 'cacute': '\u0107', 18572 'cap': '\u2229', 18573 'capand': '\u2A44', 18574 'capbrcup': '\u2A49', 18575 'capcap': '\u2A4B', 18576 'capcup': '\u2A47', 18577 'capdot': '\u2A40', 18578 'caps': '\u2229\uFE00', 18579 'caret': '\u2041', 18580 'ccaps': '\u2A4D', 18581 'ccaron': '\u010D', 18582 'ccedil': '\u00E7', 18583 'ccirc': '\u0109', 18584 'ccups': '\u2A4C', 18585 'ccupssm': '\u2A50', 18586 'cdot': '\u010B', 18587 'cemptyv': '\u29B2', 18588 'cent': '\u00A2', 18589 'cfr': '\uD835\uDD20', 18590 'chcy': '\u0447', 18591 'check': '\u2713', 18592 'checkmark': '\u2713', 18593 'chi': '\u03C7', 18594 'cir': '\u25CB', 18595 'cirE': '\u29C3', 18596 'circ': '\u02C6', 18597 'circeq': '\u2257', 18598 'cire': '\u2257', 18599 'circlearrowleft': '\u21BA', 18600 'olarr': '\u21BA', 18601 'circlearrowright': '\u21BB', 18602 'orarr': '\u21BB', 18603 'circledS': '\u24C8', 18604 'oS': '\u24C8', 18605 'circledast': '\u229B', 18606 'oast': '\u229B', 18607 'circledcirc': '\u229A', 18608 'ocir': '\u229A', 18609 'circleddash': '\u229D', 18610 'odash': '\u229D', 18611 'cirfnint': '\u2A10', 18612 'cirmid': '\u2AEF', 18613 'cirscir': '\u29C2', 18614 'clubs': '\u2663', 18615 'clubsuit': '\u2663', 18616 'colon': '\u003A', 18617 'comma': '\u002C', 18618 'commat': '\u0040', 18619 'comp': '\u2201', 18620 'complement': '\u2201', 18621 'congdot': '\u2A6D', 18622 'copf': '\uD835\uDD54', 18623 'copysr': '\u2117', 18624 'crarr': '\u21B5', 18625 'cross': '\u2717', 18626 'cscr': '\uD835\uDCB8', 18627 'csub': '\u2ACF', 18628 'csube': '\u2AD1', 18629 'csup': '\u2AD0', 18630 'csupe': '\u2AD2', 18631 'ctdot': '\u22EF', 18632 'cudarrl': '\u2938', 18633 'cudarrr': '\u2935', 18634 'cuepr': '\u22DE', 18635 'curlyeqprec': '\u22DE', 18636 'cuesc': '\u22DF', 18637 'curlyeqsucc': '\u22DF', 18638 'cularr': '\u21B6', 18639 'curvearrowleft': '\u21B6', 18640 'cularrp': '\u293D', 18641 'cup': '\u222A', 18642 'cupbrcap': '\u2A48', 18643 'cupcap': '\u2A46', 18644 'cupcup': '\u2A4A', 18645 'cupdot': '\u228D', 18646 'cupor': '\u2A45', 18647 'cups': '\u222A\uFE00', 18648 'curarr': '\u21B7', 18649 'curvearrowright': '\u21B7', 18650 'curarrm': '\u293C', 18651 'curlyvee': '\u22CE', 18652 'cuvee': '\u22CE', 18653 'curlywedge': '\u22CF', 18654 'cuwed': '\u22CF', 18655 'curren': '\u00A4', 18656 'cwint': '\u2231', 18657 'cylcty': '\u232D', 18658 'dHar': '\u2965', 18659 'dagger': '\u2020', 18660 'daleth': '\u2138', 18661 'dash': '\u2010', 18662 'hyphen': '\u2010', 18663 'dbkarow': '\u290F', 18664 'rBarr': '\u290F', 18665 'dcaron': '\u010F', 18666 'dcy': '\u0434', 18667 'ddarr': '\u21CA', 18668 'downdownarrows': '\u21CA', 18669 'ddotseq': '\u2A77', 18670 'eDDot': '\u2A77', 18671 'deg': '\u00B0', 18672 'delta': '\u03B4', 18673 'demptyv': '\u29B1', 18674 'dfisht': '\u297F', 18675 'dfr': '\uD835\uDD21', 18676 'diamondsuit': '\u2666', 18677 'diams': '\u2666', 18678 'digamma': '\u03DD', 18679 'gammad': '\u03DD', 18680 'disin': '\u22F2', 18681 'div': '\u00F7', 18682 'divide': '\u00F7', 18683 'divideontimes': '\u22C7', 18684 'divonx': '\u22C7', 18685 'djcy': '\u0452', 18686 'dlcorn': '\u231E', 18687 'llcorner': '\u231E', 18688 'dlcrop': '\u230D', 18689 'dollar': '\u0024', 18690 'dopf': '\uD835\uDD55', 18691 'doteqdot': '\u2251', 18692 'eDot': '\u2251', 18693 'dotminus': '\u2238', 18694 'minusd': '\u2238', 18695 'dotplus': '\u2214', 18696 'plusdo': '\u2214', 18697 'dotsquare': '\u22A1', 18698 'sdotb': '\u22A1', 18699 'drcorn': '\u231F', 18700 'lrcorner': '\u231F', 18701 'drcrop': '\u230C', 18702 'dscr': '\uD835\uDCB9', 18703 'dscy': '\u0455', 18704 'dsol': '\u29F6', 18705 'dstrok': '\u0111', 18706 'dtdot': '\u22F1', 18707 'dtri': '\u25BF', 18708 'triangledown': '\u25BF', 18709 'dwangle': '\u29A6', 18710 'dzcy': '\u045F', 18711 'dzigrarr': '\u27FF', 18712 'eacute': '\u00E9', 18713 'easter': '\u2A6E', 18714 'ecaron': '\u011B', 18715 'ecir': '\u2256', 18716 'eqcirc': '\u2256', 18717 'ecirc': '\u00EA', 18718 'ecolon': '\u2255', 18719 'eqcolon': '\u2255', 18720 'ecy': '\u044D', 18721 'edot': '\u0117', 18722 'efDot': '\u2252', 18723 'fallingdotseq': '\u2252', 18724 'efr': '\uD835\uDD22', 18725 'eg': '\u2A9A', 18726 'egrave': '\u00E8', 18727 'egs': '\u2A96', 18728 'eqslantgtr': '\u2A96', 18729 'egsdot': '\u2A98', 18730 'el': '\u2A99', 18731 'elinters': '\u23E7', 18732 'ell': '\u2113', 18733 'els': '\u2A95', 18734 'eqslantless': '\u2A95', 18735 'elsdot': '\u2A97', 18736 'emacr': '\u0113', 18737 'empty': '\u2205', 18738 'emptyset': '\u2205', 18739 'emptyv': '\u2205', 18740 'varnothing': '\u2205', 18741 'emsp13': '\u2004', 18742 'emsp14': '\u2005', 18743 'emsp': '\u2003', 18744 'eng': '\u014B', 18745 'ensp': '\u2002', 18746 'eogon': '\u0119', 18747 'eopf': '\uD835\uDD56', 18748 'epar': '\u22D5', 18749 'eparsl': '\u29E3', 18750 'eplus': '\u2A71', 18751 'epsi': '\u03B5', 18752 'epsilon': '\u03B5', 18753 'epsiv': '\u03F5', 18754 'straightepsilon': '\u03F5', 18755 'varepsilon': '\u03F5', 18756 'equals': '\u003D', 18757 'equest': '\u225F', 18758 'questeq': '\u225F', 18759 'equivDD': '\u2A78', 18760 'eqvparsl': '\u29E5', 18761 'erDot': '\u2253', 18762 'risingdotseq': '\u2253', 18763 'erarr': '\u2971', 18764 'escr': '\u212F', 18765 'eta': '\u03B7', 18766 'eth': '\u00F0', 18767 'euml': '\u00EB', 18768 'euro': '\u20AC', 18769 'excl': '\u0021', 18770 'fcy': '\u0444', 18771 'female': '\u2640', 18772 'ffilig': '\uFB03', 18773 'fflig': '\uFB00', 18774 'ffllig': '\uFB04', 18775 'ffr': '\uD835\uDD23', 18776 'filig': '\uFB01', 18777 'fjlig': '\u0066\u006A', 18778 'flat': '\u266D', 18779 'fllig': '\uFB02', 18780 'fltns': '\u25B1', 18781 'fnof': '\u0192', 18782 'fopf': '\uD835\uDD57', 18783 'fork': '\u22D4', 18784 'pitchfork': '\u22D4', 18785 'forkv': '\u2AD9', 18786 'fpartint': '\u2A0D', 18787 'frac12': '\u00BD', 18788 'half': '\u00BD', 18789 'frac13': '\u2153', 18790 'frac14': '\u00BC', 18791 'frac15': '\u2155', 18792 'frac16': '\u2159', 18793 'frac18': '\u215B', 18794 'frac23': '\u2154', 18795 'frac25': '\u2156', 18796 'frac34': '\u00BE', 18797 'frac35': '\u2157', 18798 'frac38': '\u215C', 18799 'frac45': '\u2158', 18800 'frac56': '\u215A',
18801 'frac58': '\u215D', 18802 'frac78': '\u215E', 18803 'frasl': '\u2044', 18804 'frown': '\u2322', 18805 'sfrown': '\u2322', 18806 'fscr': '\uD835\uDCBB', 18807 'gEl': '\u2A8C', 18808 'gtreqqless': '\u2A8C', 18809 'gacute': '\u01F5', 18810 'gamma': '\u03B3', 18811 'gap': '\u2A86', 18812 'gtrapprox': '\u2A86', 18813 'gbreve': '\u011F', 18814 'gcirc': '\u011D', 18815 'gcy': '\u0433', 18816 'gdot': '\u0121', 18817 'gescc': '\u2AA9', 18818 'gesdot': '\u2A80', 18819 'gesdoto': '\u2A82', 18820 'gesdotol': '\u2A84', 18821 'gesl': '\u22DB\uFE00', 18822 'gesles': '\u2A94', 18823 'gfr': '\uD835\uDD24', 18824 'gimel': '\u2137', 18825 'gjcy': '\u0453', 18826 'glE': '\u2A92', 18827 'gla': '\u2AA5', 18828 'glj': '\u2AA4', 18829 'gnE': '\u2269', 18830 'gneqq': '\u2269', 18831 'gnap': '\u2A8A', 18832 'gnapprox': '\u2A8A', 18833 'gne': '\u2A88', 18834 'gneq': '\u2A88', 18835 'gnsim': '\u22E7', 18836 'gopf': '\uD835\uDD58', 18837 'gscr': '\u210A', 18838 'gsime': '\u2A8E', 18839 'gsiml': '\u2A90', 18840 'gtcc': '\u2AA7', 18841 'gtcir': '\u2A7A', 18842 'gtdot': '\u22D7', 18843 'gtrdot': '\u22D7', 18844 'gtlPar': '\u2995', 18845 'gtquest': '\u2A7C', 18846 'gtrarr': '\u2978', 18847 'gvertneqq': '\u2269\uFE00', 18848 'gvnE': '\u2269\uFE00', 18849 'hardcy': '\u044A', 18850 'harrcir': '\u2948', 18851 'harrw': '\u21AD', 18852 'leftrightsquigarrow': '\u21AD', 18853 'hbar': '\u210F', 18854 'hslash': '\u210F', 18855 'planck': '\u210F', 18856 'plankv': '\u210F', 18857 'hcirc': '\u0125', 18858 'hearts': '\u2665', 18859 'heartsuit': '\u2665', 18860 'hellip': '\u2026', 18861 'mldr': '\u2026', 18862 'hercon': '\u22B9', 18863 'hfr': '\uD835\uDD25', 18864 'hksearow': '\u2925', 18865 'searhk': '\u2925', 18866 'hkswarow': '\u2926', 18867 'swarhk': '\u2926', 18868 'hoarr': '\u21FF', 18869 'homtht': '\u223B', 18870 'hookleftarrow': '\u21A9', 18871 'larrhk': '\u21A9', 18872 'hookrightarrow': '\u21AA', 18873 'rarrhk': '\u21AA', 18874 'hopf': '\uD835\uDD59', 18875 'horbar': '\u2015', 18876 'hscr': '\uD835\uDCBD', 18877 'hstrok': '\u0127', 18878 'hybull': '\u2043', 18879 'iacute': '\u00ED', 18880 'icirc': '\u00EE', 18881 'icy': '\u0438', 18882 'iecy': '\u0435', 18883 'iexcl': '\u00A1', 18884 'ifr': '\uD835\uDD26', 18885 'igrave': '\u00EC', 18886 'iiiint': '\u2A0C', 18887 'qint': '\u2A0C', 18888 'iiint': '\u222D', 18889 'tint': '\u222D', 18890 'iinfin': '\u29DC', 18891 'iiota': '\u2129', 18892 'ijlig': '\u0133', 18893 'imacr': '\u012B', 18894 'imath': '\u0131', 18895 'inodot': '\u0131', 18896 'imof': '\u22B7', 18897 'imped': '\u01B5', 18898 'incare': '\u2105', 18899 'infin': '\u221E', 18900 'infintie': '\u29DD', 18901 'intcal': '\u22BA', 18902 'intercal': '\u22BA', 18903 'intlarhk': '\u2A17', 18904 'intprod': '\u2A3C', 18905 'iprod': '\u2A3C', 18906 'iocy': '\u0451', 18907 'iogon': '\u012F', 18908 'iopf': '\uD835\uDD5A', 18909 'iota': '\u03B9', 18910 'iquest': '\u00BF', 18911 'iscr': '\uD835\uDCBE', 18912 'isinE': '\u22F9', 18913 'isindot': '\u22F5', 18914 'isins': '\u22F4', 18915 'isinsv': '\u22F3', 18916 'itilde': '\u0129', 18917 'iukcy': '\u0456', 18918 'iuml': '\u00EF', 18919 'jcirc': '\u0135', 18920 'jcy': '\u0439', 18921 'jfr': '\uD835\uDD27', 18922 'jmath': '\u0237', 18923 'jopf': '\uD835\uDD5B', 18924 'jscr': '\uD835\uDCBF', 18925 'jsercy': '\u0458', 18926 'jukcy': '\u0454', 18927 'kappa': '\u03BA', 18928 'kappav': '\u03F0', 18929 'varkappa': '\u03F0', 18930 'kcedil': '\u0137', 18931 'kcy': '\u043A', 18932 'kfr': '\uD835\uDD28', 18933 'kgreen': '\u0138', 18934 'khcy': '\u0445', 18935 'kjcy': '\u045C', 18936 'kopf': '\uD835\uDD5C', 18937 'kscr': '\uD835\uDCC0', 18938 'lAtail': '\u291B', 18939 'lBarr': '\u290E', 18940 'lEg': '\u2A8B', 18941 'lesseqqgtr': '\u2A8B', 18942 'lHar': '\u2962', 18943 'lacute': '\u013A', 18944 'laemptyv': '\u29B4', 18945 'lambda': '\u03BB', 18946 'langd': '\u2991', 18947 'lap': '\u2A85', 18948 'lessapprox': '\u2A85', 18949 'laquo': '\u00AB', 18950 'larrbfs': '\u291F', 18951 'larrfs': '\u291D', 18952 'larrlp': '\u21AB', 18953 'looparrowleft': '\u21AB', 18954 'larrpl': '\u2939', 18955 'larrsim': '\u2973', 18956 'larrtl': '\u21A2', 18957 'leftarrowtail': '\u21A2', 18958 'lat': '\u2AAB', 18959 'latail': '\u2919', 18960 'late': '\u2AAD', 18961 'lates': '\u2AAD\uFE00', 18962 'lbarr': '\u290C', 18963 'lbbrk': '\u2772', 18964 'lbrace': '\u007B', 18965 'lcub': '\u007B', 18966 'lbrack': '\u005B', 18967 'lsqb': '\u005B', 18968 'lbrke': '\u298B', 18969 'lbrksld': '\u298F', 18970 'lbrkslu': '\u298D', 18971 'lcaron': '\u013E', 18972 'lcedil': '\u013C', 18973 'lcy': '\u043B', 18974 'ldca': '\u2936', 18975 'ldrdhar': '\u2967', 18976 'ldrushar': '\u294B', 18977 'ldsh': '\u21B2', 18978 'le': '\u2264', 18979 'leq': '\u2264', 18980 'leftleftarrows': '\u21C7', 18981 'llarr': '\u21C7', 18982 'leftthreetimes': '\u22CB', 18983 'lthree': '\u22CB', 18984 'lescc': '\u2AA8', 18985 'lesdot': '\u2A7F', 18986 'lesdoto': '\u2A81', 18987 'lesdotor': '\u2A83', 18988 'lesg': '\u22DA\uFE00', 18989 'lesges': '\u2A93', 18990 'lessdot': '\u22D6', 18991 'ltdot': '\u22D6', 18992 'lfisht': '\u297C', 18993 'lfr': '\uD835\uDD29', 18994 'lgE': '\u2A91', 18995 'lharul': '\u296A', 18996 'lhblk': '\u2584', 18997 'ljcy': '\u0459', 18998 'llhard': '\u296B', 18999 'lltri': '\u25FA', 19000 'lmidot': '\u0140', 19001 'lmoust': '\u23B0', 19002 'lmoustache': '\u23B0', 19003 'lnE': '\u2268', 19004 'lneqq': '\u2268', 19005 'lnap': '\u2A89', 19006 'lnapprox': '\u2A89', 19007 'lne': '\u2A87', 19008 'lneq': '\u2A87', 19009 'lnsim': '\u22E6', 19010 'loang': '\u27EC', 19011 'loarr': '\u21FD', 19012 'longmapsto': '\u27FC', 19013 'xmap': '\u27FC', 19014 'looparrowright': '\u21AC', 19015 'rarrlp': '\u21AC', 19016 'lopar': '\u2985', 19017 'lopf': '\uD835\uDD5D', 19018 'loplus': '\u2A2D', 19019 'lotimes': '\u2A34', 19020 'lowast': '\u2217', 19021 'loz': '\u25CA', 19022 'lozenge': '\u25CA', 19023 'lpar': '\u0028', 19024 'lparlt': '\u2993', 19025 'lrhard': '\u296D', 19026 'lrm': '\u200E', 19027 'lrtri': '\u22BF', 19028 'lsaquo': '\u2039', 19029 'lscr': '\uD835\uDCC1', 19030 'lsime': '\u2A8D', 19031 'lsimg': '\u2A8F', 19032 'lsquor': '\u201A', 19033 'sbquo': '\u201A', 19034 'lstrok': '\u0142', 19035 'ltcc': '\u2AA6', 19036 'ltcir': '\u2A79', 19037 'ltimes': '\u22C9', 19038 'ltlarr': '\u2976', 19039 'ltquest': '\u2A7B', 19040 'ltrPar': '\u2996', 19041 'ltri': '\u25C3', 19042 'triangleleft': '\u25C3', 19043 'lurdshar': '\u294A', 19044 'luruhar': '\u2966', 19045 'lvertneqq': '\u2268\uFE00', 19046 'lvnE': '\u2268\uFE00', 19047 'mDDot': '\u223A', 19048 'macr': '\u00AF', 19049 'strns': '\u00AF', 19050 'male': '\u2642', 19051 'malt': '\u2720', 19052 'maltese': '\u2720', 19053 'marker': '\u25AE', 19054 'mcomma': '\u2A29', 19055 'mcy': '\u043C', 19056 'mdash': '\u2014', 19057 'mfr': '\uD835\uDD2A', 19058 'mho': '\u2127', 19059 'micro': '\u00B5', 19060 'midcir': '\u2AF0', 19061 'minus': '\u2212', 19062 'minusdu': '\u2A2A', 19063 'mlcp': '\u2ADB', 19064 'models': '\u22A7', 19065 'mopf': '\uD835\uDD5E', 19066 'mscr': '\uD835\uDCC2', 19067 'mu': '\u03BC', 19068 'multimap': '\u22B8', 19069 'mumap': '\u22B8', 19070 'nGg': '\u22D9\u0338', 19071 'nGt': '\u226B\u20D2', 19072 'nLeftarrow': '\u21CD', 19073 'nlArr': '\u21CD', 19074 'nLeftrightarrow': '\u21CE', 19075 'nhArr': '\u21CE', 19076 'nLl': '\u22D8\u0338', 19077 'nLt': '\u226A\u20D2', 19078 'nRightarrow': '\u21CF', 19079 'nrArr': '\u21CF', 19080 'nVDash': '\u22AF', 19081 'nVdash': '\u22AE', 19082 'nacute': '\u0144', 19083 'nang': '\u2220\u20D2', 19084 'napE': '\u2A70\u0338', 19085 'napid': '\u224B\u0338', 19086 'napos': '\u0149', 19087 'natur': '\u266E', 19088 'natural': '\u266E', 19089 'ncap': '\u2A43', 19090 'ncaron': '\u0148', 19091 'ncedil': '\u0146', 19092 'ncongdot': '\u2A6D\u0338', 19093 'ncup': '\u2A42', 19094 'ncy': '\u043D', 19095 'ndash': '\u2013', 19096 'neArr': '\u21D7', 19097 'nearhk': '\u2924', 19098 'nedot': '\u2250\u0338', 19099 'nesear': '\u2928', 19100 'toea': '\u2928', 19101 'nfr': '\uD835\uDD2B', 19102 'nharr': '\u21AE', 19103 'nleftrightarrow': '\u21AE', 19104 'nhpar': '\u2AF2', 19105 'nis': '\u22FC', 19106 'nisd': '\u22FA', 19107 'njcy': '\u045A', 19108 'nlE': '\u2266\u0338', 19109 'nleqq': '\u2266\u0338', 19110 'nlarr': '\u219A', 19111 'nleftarrow': '\u219A', 19112 'nldr': '\u2025', 19113 'nopf': '\uD835\uDD5F', 19114 'not': '\u00AC', 19115 'notinE': '\u22F9\u0338', 19116 'notindot': '\u22F5\u0338', 19117 'notinvb': '\u22F7', 19118 'notinvc': '\u22F6', 19119 'notnivb': '\u22FE', 19120 'notnivc': '\u22FD', 19121 'nparsl': '\u2AFD\u20E5',
19122 'npart': '\u2202\u0338', 19123 'npolint': '\u2A14', 19124 'nrarr': '\u219B', 19125 'nrightarrow': '\u219B', 19126 'nrarrc': '\u2933\u0338', 19127 'nrarrw': '\u219D\u0338', 19128 'nscr': '\uD835\uDCC3', 19129 'nsub': '\u2284', 19130 'nsubE': '\u2AC5\u0338', 19131 'nsubseteqq': '\u2AC5\u0338', 19132 'nsup': '\u2285', 19133 'nsupE': '\u2AC6\u0338', 19134 'nsupseteqq': '\u2AC6\u0338', 19135 'ntilde': '\u00F1', 19136 'nu': '\u03BD', 19137 'num': '\u0023', 19138 'numero': '\u2116', 19139 'numsp': '\u2007', 19140 'nvDash': '\u22AD', 19141 'nvHarr': '\u2904', 19142 'nvap': '\u224D\u20D2', 19143 'nvdash': '\u22AC', 19144 'nvge': '\u2265\u20D2', 19145 'nvgt': '\u003E\u20D2', 19146 'nvinfin': '\u29DE', 19147 'nvlArr': '\u2902', 19148 'nvle': '\u2264\u20D2', 19149 'nvlt': '\u003C\u20D2', 19150 'nvltrie': '\u22B4\u20D2', 19151 'nvrArr': '\u2903', 19152 'nvrtrie': '\u22B5\u20D2', 19153 'nvsim': '\u223C\u20D2', 19154 'nwArr': '\u21D6', 19155 'nwarhk': '\u2923', 19156 'nwnear': '\u2927', 19157 'oacute': '\u00F3', 19158 'ocirc': '\u00F4', 19159 'ocy': '\u043E', 19160 'odblac': '\u0151', 19161 'odiv': '\u2A38', 19162 'odsold': '\u29BC', 19163 'oelig': '\u0153', 19164 'ofcir': '\u29BF', 19165 'ofr': '\uD835\uDD2C', 19166 'ogon': '\u02DB', 19167 'ograve': '\u00F2', 19168 'ogt': '\u29C1', 19169 'ohbar': '\u29B5', 19170 'olcir': '\u29BE', 19171 'olcross': '\u29BB', 19172 'olt': '\u29C0', 19173 'omacr': '\u014D', 19174 'omega': '\u03C9', 19175 'omicron': '\u03BF', 19176 'omid': '\u29B6', 19177 'oopf': '\uD835\uDD60', 19178 'opar': '\u29B7', 19179 'operp': '\u29B9', 19180 'or': '\u2228', 19181 'vee': '\u2228', 19182 'ord': '\u2A5D', 19183 'order': '\u2134', 19184 'orderof': '\u2134', 19185 'oscr': '\u2134', 19186 'ordf': '\u00AA', 19187 'ordm': '\u00BA', 19188 'origof': '\u22B6', 19189 'oror': '\u2A56', 19190 'orslope': '\u2A57', 19191 'orv': '\u2A5B', 19192 'oslash': '\u00F8', 19193 'osol': '\u2298', 19194 'otilde': '\u00F5', 19195 'otimesas': '\u2A36', 19196 'ouml': '\u00F6', 19197 'ovbar': '\u233D', 19198 'para': '\u00B6', 19199 'parsim': '\u2AF3', 19200 'parsl': '\u2AFD', 19201 'pcy': '\u043F', 19202 'percnt': '\u0025', 19203 'period': '\u002E', 19204 'permil': '\u2030', 19205 'pertenk': '\u2031', 19206 'pfr': '\uD835\uDD2D', 19207 'phi': '\u03C6', 19208 'phiv': '\u03D5', 19209 'straightphi': '\u03D5', 19210 'varphi': '\u03D5', 19211 'phone': '\u260E', 19212 'pi': '\u03C0', 19213 'piv': '\u03D6', 19214 'varpi': '\u03D6', 19215 'planckh': '\u210E', 19216 'plus': '\u002B', 19217 'plusacir': '\u2A23', 19218 'pluscir': '\u2A22', 19219 'plusdu': '\u2A25', 19220 'pluse': '\u2A72', 19221 'plussim': '\u2A26', 19222 'plustwo': '\u2A27', 19223 'pointint': '\u2A15', 19224 'popf': '\uD835\uDD61', 19225 'pound': '\u00A3', 19226 'prE': '\u2AB3', 19227 'prap': '\u2AB7', 19228 'precapprox': '\u2AB7', 19229 'precnapprox': '\u2AB9', 19230 'prnap': '\u2AB9', 19231 'precneqq': '\u2AB5', 19232 'prnE': '\u2AB5', 19233 'precnsim': '\u22E8', 19234 'prnsim': '\u22E8', 19235 'prime': '\u2032', 19236 'profalar': '\u232E', 19237 'profline': '\u2312', 19238 'profsurf': '\u2313', 19239 'prurel': '\u22B0', 19240 'pscr': '\uD835\uDCC5', 19241 'psi': '\u03C8', 19242 'puncsp': '\u2008', 19243 'qfr': '\uD835\uDD2E', 19244 'qopf': '\uD835\uDD62', 19245 'qprime': '\u2057', 19246 'qscr': '\uD835\uDCC6', 19247 'quatint': '\u2A16', 19248 'quest': '\u003F', 19249 'rAtail': '\u291C', 19250 'rHar': '\u2964', 19251 'race': '\u223D\u0331', 19252 'racute': '\u0155', 19253 'raemptyv': '\u29B3', 19254 'rangd': '\u2992', 19255 'range': '\u29A5', 19256 'raquo': '\u00BB', 19257 'rarrap': '\u2975', 19258 'rarrbfs': '\u2920', 19259 'rarrc': '\u2933', 19260 'rarrfs': '\u291E', 19261 'rarrpl': '\u2945', 19262 'rarrsim': '\u2974', 19263 'rarrtl': '\u21A3', 19264 'rightarrowtail': '\u21A3', 19265 'rarrw': '\u219D', 19266 'rightsquigarrow': '\u219D', 19267 'ratail': '\u291A', 19268 'ratio': '\u2236', 19269 'rbbrk': '\u2773', 19270 'rbrace': '\u007D', 19271 'rcub': '\u007D', 19272 'rbrack': '\u005D', 19273 'rsqb': '\u005D', 19274 'rbrke': '\u298C', 19275 'rbrksld': '\u298E', 19276 'rbrkslu': '\u2990', 19277 'rcaron': '\u0159', 19278 'rcedil': '\u0157', 19279 'rcy': '\u0440', 19280 'rdca': '\u2937', 19281 'rdldhar': '\u2969', 19282 'rdsh': '\u21B3', 19283 'rect': '\u25AD', 19284 'rfisht': '\u297D', 19285 'rfr': '\uD835\uDD2F', 19286 'rharul': '\u296C', 19287 'rho': '\u03C1', 19288 'rhov': '\u03F1', 19289 'varrho': '\u03F1', 19290 'rightrightarrows': '\u21C9', 19291 'rrarr': '\u21C9', 19292 'rightthreetimes': '\u22CC', 19293 'rthree': '\u22CC', 19294 'ring': '\u02DA', 19295 'rlm': '\u200F', 19296 'rmoust': '\u23B1', 19297 'rmoustache': '\u23B1', 19298 'rnmid': '\u2AEE', 19299 'roang': '\u27ED', 19300 'roarr': '\u21FE', 19301 'ropar': '\u2986', 19302 'ropf': '\uD835\uDD63', 19303 'roplus': '\u2A2E', 19304 'rotimes': '\u2A35', 19305 'rpar': '\u0029', 19306 'rpargt': '\u2994', 19307 'rppolint': '\u2A12', 19308 'rsaquo': '\u203A', 19309 'rscr': '\uD835\uDCC7', 19310 'rtimes': '\u22CA', 19311 'rtri': '\u25B9', 19312 'triangleright': '\u25B9', 19313 'rtriltri': '\u29CE', 19314 'ruluhar': '\u2968', 19315 'rx': '\u211E', 19316 'sacute': '\u015B', 19317 'scE': '\u2AB4', 19318 'scap': '\u2AB8', 19319 'succapprox': '\u2AB8', 19320 'scaron': '\u0161', 19321 'scedil': '\u015F', 19322 'scirc': '\u015D', 19323 'scnE': '\u2AB6', 19324 'succneqq': '\u2AB6', 19325 'scnap': '\u2ABA', 19326 'succnapprox': '\u2ABA', 19327 'scnsim': '\u22E9', 19328 'succnsim': '\u22E9', 19329 'scpolint': '\u2A13', 19330 'scy': '\u0441', 19331 'sdot': '\u22C5', 19332 'sdote': '\u2A66', 19333 'seArr': '\u21D8', 19334 'sect': '\u00A7', 19335 'semi': '\u003B', 19336 'seswar': '\u2929', 19337 'tosa': '\u2929', 19338 'sext': '\u2736', 19339 'sfr': '\uD835\uDD30', 19340 'sharp': '\u266F', 19341 'shchcy': '\u0449', 19342 'shcy': '\u0448', 19343 'shy': '\u00AD', 19344 'sigma': '\u03C3', 19345 'sigmaf': '\u03C2', 19346 'sigmav': '\u03C2', 19347 'varsigma': '\u03C2', 19348 'simdot': '\u2A6A', 19349 'simg': '\u2A9E', 19350 'simgE': '\u2AA0', 19351 'siml': '\u2A9D', 19352 'simlE': '\u2A9F', 19353 'simne': '\u2246', 19354 'simplus': '\u2A24', 19355 'simrarr': '\u2972', 19356 'smashp': '\u2A33', 19357 'smeparsl': '\u29E4', 19358 'smile': '\u2323', 19359 'ssmile': '\u2323', 19360 'smt': '\u2AAA', 19361 'smte': '\u2AAC', 19362 'smtes': '\u2AAC\uFE00', 19363 'softcy': '\u044C', 19364 'sol': '\u002F', 19365 'solb': '\u29C4', 19366 'solbar': '\u233F', 19367 'sopf': '\uD835\uDD64', 19368 'spades': '\u2660', 19369 'spadesuit': '\u2660', 19370 'sqcaps': '\u2293\uFE00', 19371 'sqcups': '\u2294\uFE00', 19372 'sscr': '\uD835\uDCC8', 19373 'star': '\u2606', 19374 'sub': '\u2282', 19375 'subset': '\u2282', 19376 'subE': '\u2AC5', 19377 'subseteqq': '\u2AC5', 19378 'subdot': '\u2ABD', 19379 'subedot': '\u2AC3', 19380 'submult': '\u2AC1', 19381 'subnE': '\u2ACB', 19382 'subsetneqq': '\u2ACB', 19383 'subne': '\u228A', 19384 'subsetneq': '\u228A', 19385 'subplus': '\u2ABF', 19386 'subrarr': '\u2979', 19387 'subsim': '\u2AC7', 19388 'subsub': '\u2AD5', 19389 'subsup': '\u2AD3', 19390 'sung': '\u266A', 19391 'sup1': '\u00B9', 19392 'sup2': '\u00B2', 19393 'sup3': '\u00B3', 19394 'supE': '\u2AC6', 19395 'supseteqq': '\u2AC6', 19396 'supdot': '\u2ABE', 19397 'supdsub': '\u2AD8', 19398 'supedot': '\u2AC4', 19399 'suphsol': '\u27C9', 19400 'suphsub': '\u2AD7', 19401 'suplarr': '\u297B',
19402 'supmult': '\u2AC2', 19403 'supnE': '\u2ACC', 19404 'supsetneqq': '\u2ACC', 19405 'supne': '\u228B', 19406 'supsetneq': '\u228B', 19407 'supplus': '\u2AC0', 19408 'supsim': '\u2AC8', 19409 'supsub': '\u2AD4', 19410 'supsup': '\u2AD6', 19411 'swArr': '\u21D9', 19412 'swnwar': '\u292A', 19413 'szlig': '\u00DF', 19414 'target': '\u2316', 19415 'tau': '\u03C4', 19416 'tcaron': '\u0165', 19417 'tcedil': '\u0163', 19418 'tcy': '\u0442', 19419 'telrec': '\u2315', 19420 'tfr': '\uD835\uDD31', 19421 'theta': '\u03B8', 19422 'thetasym': '\u03D1', 19423 'thetav': '\u03D1', 19424 'vartheta': '\u03D1', 19425 'thorn': '\u00FE', 19426 'times': '\u00D7', 19427 'timesbar': '\u2A31', 19428 'timesd': '\u2A30', 19429 'topbot': '\u2336', 19430 'topcir': '\u2AF1', 19431 'topf': '\uD835\uDD65', 19432 'topfork': '\u2ADA', 19433 'tprime': '\u2034', 19434 'triangle': '\u25B5', 19435 'utri': '\u25B5', 19436 'triangleq': '\u225C', 19437 'trie': '\u225C', 19438 'tridot': '\u25EC', 19439 'triminus': '\u2A3A', 19440 'triplus': '\u2A39', 19441 'trisb': '\u29CD', 19442 'tritime': '\u2A3B', 19443 'trpezium': '\u23E2', 19444 'tscr': '\uD835\uDCC9', 19445 'tscy': '\u0446', 19446 'tshcy': '\u045B', 19447 'tstrok': '\u0167', 19448 'uHar': '\u2963', 19449 'uacute': '\u00FA', 19450 'ubrcy': '\u045E', 19451 'ubreve': '\u016D', 19452 'ucirc': '\u00FB', 19453 'ucy': '\u0443', 19454 'udblac': '\u0171', 19455 'ufisht': '\u297E', 19456 'ufr': '\uD835\uDD32', 19457 'ugrave': '\u00F9', 19458 'uhblk': '\u2580', 19459 'ulcorn': '\u231C', 19460 'ulcorner': '\u231C', 19461 'ulcrop': '\u230F', 19462 'ultri': '\u25F8', 19463 'umacr': '\u016B', 19464 'uogon': '\u0173', 19465 'uopf': '\uD835\uDD66', 19466 'upsi': '\u03C5', 19467 'upsilon': '\u03C5', 19468 'upuparrows': '\u21C8', 19469 'uuarr': '\u21C8', 19470 'urcorn': '\u231D', 19471 'urcorner': '\u231D', 19472 'urcrop': '\u230E', 19473 'uring': '\u016F', 19474 'urtri': '\u25F9', 19475 'uscr': '\uD835\uDCCA', 19476 'utdot': '\u22F0', 19477 'utilde': '\u0169', 19478 'uuml': '\u00FC', 19479 'uwangle': '\u29A7', 19480 'vBar': '\u2AE8', 19481 'vBarv': '\u2AE9', 19482 'vangrt': '\u299C', 19483 'varsubsetneq': '\u228A\uFE00', 19484 'vsubne': '\u228A\uFE00', 19485 'varsubsetneqq': '\u2ACB\uFE00', 19486 'vsubnE': '\u2ACB\uFE00', 19487 'varsupsetneq': '\u228B\uFE00', 19488 'vsupne': '\u228B\uFE00', 19489 'varsupsetneqq': '\u2ACC\uFE00', 19490 'vsupnE': '\u2ACC\uFE00', 19491 'vcy': '\u0432', 19492 'veebar': '\u22BB', 19493 'veeeq': '\u225A', 19494 'vellip': '\u22EE', 19495 'vfr': '\uD835\uDD33', 19496 'vopf': '\uD835\uDD67', 19497 'vscr': '\uD835\uDCCB', 19498 'vzigzag': '\u299A', 19499 'wcirc': '\u0175', 19500 'wedbar': '\u2A5F', 19501 'wedgeq': '\u2259', 19502 'weierp': '\u2118', 19503 'wp': '\u2118', 19504 'wfr': '\uD835\uDD34', 19505 'wopf': '\uD835\uDD68', 19506 'wscr': '\uD835\uDCCC', 19507 'xfr': '\uD835\uDD35', 19508 'xi': '\u03BE', 19509 'xnis': '\u22FB', 19510 'xopf': '\uD835\uDD69', 19511 'xscr': '\uD835\uDCCD', 19512 'yacute': '\u00FD', 19513 'yacy': '\u044F', 19514 'ycirc': '\u0177', 19515 'ycy': '\u044B', 19516 'yen': '\u00A5', 19517 'yfr': '\uD835\uDD36', 19518 'yicy': '\u0457', 19519 'yopf': '\uD835\uDD6A', 19520 'yscr': '\uD835\uDCCE', 19521 'yucy': '\u044E', 19522 'yuml': '\u00FF', 19523 'zacute': '\u017A', 19524 'zcaron': '\u017E', 19525 'zcy': '\u0437', 19526 'zdot': '\u017C', 19527 'zeta': '\u03B6', 19528 'zfr': '\uD835\uDD37', 19529 'zhcy': '\u0436', 19530 'zigrarr': '\u21DD', 19531 'zopf': '\uD835\uDD6B', 19532 'zscr': '\uD835\uDCCF', 19533 'zwj': '\u200D', 19534 'zwnj': '\u200C' 19535}; // The &ngsp; pseudo-entity is denoting a space. see: 19536// https://github.com/dart-lang/angular/blob/0bb611387d29d65b5af7f9d2515ab571fd3fbee4/_tests/test/compiler/preserve_whitespace_test.dart 19537 19538const NGSP_UNICODE = '\uE500'; 19539NAMED_ENTITIES['ngsp'] = NGSP_UNICODE; 19540/** 19541 * @license 19542 * Copyright Google LLC All Rights Reserved. 19543 * 19544 * Use of this source code is governed by an MIT-style license that can be 19545 * found in the LICENSE file at https://angular.io/license 19546 */ 19547 19548class TokenError extends ParseError { 19549 constructor(errorMsg, tokenType, span) { 19550 super(span, errorMsg); 19551 this.tokenType = tokenType; 19552 } 19553 19554} 19555 19556class TokenizeResult { 19557 constructor(tokens, errors, nonNormalizedIcuExpressions) { 19558 this.tokens = tokens; 19559 this.errors = errors; 19560 this.nonNormalizedIcuExpressions = nonNormalizedIcuExpressions; 19561 } 19562 19563} 19564 19565function tokenize(source, url, getTagDefinition, options = {}) { 19566 const tokenizer = new _Tokenizer(new ParseSourceFile(source, url), getTagDefinition, options); 19567 tokenizer.tokenize(); 19568 return new TokenizeResult(mergeTextTokens(tokenizer.tokens), tokenizer.errors, tokenizer.nonNormalizedIcuExpressions); 19569} 19570 19571const _CR_OR_CRLF_REGEXP = /\r\n?/g; 19572 19573function _unexpectedCharacterErrorMsg(charCode) { 19574 const char = charCode === $EOF ? 'EOF' : String.fromCharCode(charCode); 19575 return `Unexpected character "${char}"`; 19576} 19577 19578function _unknownEntityErrorMsg(entitySrc) { 19579 return `Unknown entity "${entitySrc}" - use the "&#<decimal>;" or "&#x<hex>;" syntax`; 19580} 19581 19582function _unparsableEntityErrorMsg(type, entityStr) { 19583 return `Unable to parse entity "${entityStr}" - ${type} character reference entities must end with ";"`; 19584} 19585 19586var CharacterReferenceType; 19587 19588(function (CharacterReferenceType) { 19589 CharacterReferenceType["HEX"] = "hexadecimal"; 19590 CharacterReferenceType["DEC"] = "decimal"; 19591})(CharacterReferenceType || (CharacterReferenceType = {})); 19592 19593class _ControlFlowError { 19594 constructor(error) { 19595 this.error = error; 19596 } 19597 19598} // See https://www.w3.org/TR/html51/syntax.html#writing-html-documents 19599 19600 19601class _Tokenizer { 19602 /** 19603 * @param _file The html source file being tokenized. 19604 * @param _getTagDefinition A function that will retrieve a tag definition for a given tag name. 19605 * @param options Configuration of the tokenization. 19606 */ 19607 constructor(_file, _getTagDefinition, options) { 19608 this._getTagDefinition = _getTagDefinition; 19609 this._currentTokenStart = null; 19610 this._currentTokenType = null; 19611 this._expansionCaseStack = []; 19612 this._inInterpolation = false;
19613 this.tokens = []; 19614 this.errors = []; 19615 this.nonNormalizedIcuExpressions = []; 19616 this._tokenizeIcu = options.tokenizeExpansionForms || false; 19617 this._interpolationConfig = options.interpolationConfig || DEFAULT_INTERPOLATION_CONFIG; 19618 this._leadingTriviaCodePoints = options.leadingTriviaChars && options.leadingTriviaChars.map(c => c.codePointAt(0) || 0); 19619 const range = options.range || { 19620 endPos: _file.content.length, 19621 startPos: 0, 19622 startLine: 0, 19623 startCol: 0 19624 }; 19625 this._cursor = options.escapedString ? new EscapedCharacterCursor(_file, range) : new PlainCharacterCursor(_file, range); 19626 this._preserveLineEndings = options.preserveLineEndings || false; 19627 this._escapedString = options.escapedString || false; 19628 this._i18nNormalizeLineEndingsInICUs = options.i18nNormalizeLineEndingsInICUs || false; 19629 19630 try { 19631 this._cursor.init(); 19632 } catch (e) { 19633 this.handleError(e); 19634 } 19635 } 19636 19637 _processCarriageReturns(content) { 19638 if (this._preserveLineEndings) { 19639 return content; 19640 } // https://www.w3.org/TR/html51/syntax.html#preprocessing-the-input-stream 19641 // In order to keep the original position in the source, we can not 19642 // pre-process it. 19643 // Instead CRs are processed right before instantiating the tokens. 19644 19645 19646 return content.replace(_CR_OR_CRLF_REGEXP, '\n'); 19647 } 19648 19649 tokenize() { 19650 while (this._cursor.peek() !== $EOF) { 19651 const start = this._cursor.clone(); 19652 19653 try { 19654 if (this._attemptCharCode($LT)) { 19655 if (this._attemptCharCode($BANG)) { 19656 if (this._attemptCharCode($LBRACKET)) { 19657 this._consumeCdata(start); 19658 } else if (this._attemptCharCode($MINUS)) { 19659 this._consumeComment(start); 19660 } else { 19661 this._consumeDocType(start); 19662 } 19663 } else if (this._attemptCharCode($SLASH)) { 19664 this._consumeTagClose(start); 19665 } else { 19666 this._consumeTagOpen(start); 19667 } 19668 } else if (!(this._tokenizeIcu && this._tokenizeExpansionForm())) { 19669 // In (possibly interpolated) text the end of the text is given by `isTextEnd()`, while 19670 // the premature end of an interpolation is given by the start of a new HTML element. 19671 this._consumeWithInterpolation(5 19672 /* TokenType.TEXT */ 19673 , 8 19674 /* TokenType.INTERPOLATION */ 19675 , () => this._isTextEnd(), () => this._isTagStart()); 19676 } 19677 } catch (e) { 19678 this.handleError(e); 19679 } 19680 } 19681 19682 this._beginToken(24 19683 /* TokenType.EOF */ 19684 ); 19685 19686 this._endToken([]); 19687 } 19688 /** 19689 * @returns whether an ICU token has been created 19690 * @internal 19691 */ 19692 19693 19694 _tokenizeExpansionForm() { 19695 if (this.isExpansionFormStart()) { 19696 this._consumeExpansionFormStart(); 19697 19698 return true; 19699 } 19700 19701 if (isExpansionCaseStart(this._cursor.peek()) && this._isInExpansionForm()) { 19702 this._consumeExpansionCaseStart(); 19703 19704 return true; 19705 } 19706 19707 if (this._cursor.peek() === $RBRACE) { 19708 if (this._isInExpansionCase()) { 19709 this._consumeExpansionCaseEnd(); 19710 19711 return true; 19712 } 19713 19714 if (this._isInExpansionForm()) { 19715 this._consumeExpansionFormEnd(); 19716 19717 return true; 19718 } 19719 } 19720 19721 return false; 19722 } 19723 19724 _beginToken(type, start = this._cursor.clone()) { 19725 this._currentTokenStart = start; 19726 this._currentTokenType = type; 19727 } 19728 19729 _endToken(parts, end) { 19730 if (this._currentTokenStart === null) { 19731 throw new TokenError('Programming error - attempted to end a token when there was no start to the token', this._currentTokenType, this._cursor.getSpan(end)); 19732 } 19733 19734 if (this._currentTokenType === null) { 19735 throw new TokenError('Programming error - attempted to end a token which has no token type', null, this._cursor.getSpan(this._currentTokenStart)); 19736 } 19737 19738 const token = { 19739 type: this._currentTokenType, 19740 parts, 19741 sourceSpan: (end ?? this._cursor).getSpan(this._currentTokenStart, this._leadingTriviaCodePoints) 19742 }; 19743 this.tokens.push(token); 19744 this._currentTokenStart = null; 19745 this._currentTokenType = null; 19746 return token; 19747 } 19748 19749 _createError(msg, span) { 19750 if (this._isInExpansionForm()) { 19751 msg += ` (Do you have an unescaped "{" in your template? Use "{{ '{' }}") to escape it.)`; 19752 } 19753 19754 const error = new TokenError(msg, this._currentTokenType, span); 19755 this._currentTokenStart = null; 19756 this._currentTokenType = null; 19757 return new _ControlFlowError(error); 19758 } 19759 19760 handleError(e) { 19761 if (e instanceof CursorError) { 19762 e = this._createError(e.msg, this._cursor.getSpan(e.cursor)); 19763 } 19764 19765 if (e instanceof _ControlFlowError) { 19766 this.errors.push(e.error); 19767 } else { 19768 throw e; 19769 } 19770 } 19771 19772 _attemptCharCode(charCode) { 19773 if (this._cursor.peek() === charCode) { 19774 this._cursor.advance(); 19775 19776 return true; 19777 } 19778 19779 return false;
19780 } 19781 19782 _attemptCharCodeCaseInsensitive(charCode) { 19783 if (compareCharCodeCaseInsensitive(this._cursor.peek(), charCode)) { 19784 this._cursor.advance(); 19785 19786 return true; 19787 } 19788 19789 return false; 19790 } 19791 19792 _requireCharCode(charCode) { 19793 const location = this._cursor.clone(); 19794 19795 if (!this._attemptCharCode(charCode)) { 19796 throw this._createError(_unexpectedCharacterErrorMsg(this._cursor.peek()), this._cursor.getSpan(location)); 19797 } 19798 } 19799 19800 _attemptStr(chars) { 19801 const len = chars.length; 19802 19803 if (this._cursor.charsLeft() < len) { 19804 return false; 19805 } 19806 19807 const initialPosition = this._cursor.clone(); 19808 19809 for (let i = 0; i < len; i++) { 19810 if (!this._attemptCharCode(chars.charCodeAt(i))) { 19811 // If attempting to parse the string fails, we want to reset the parser 19812 // to where it was before the attempt 19813 this._cursor = initialPosition; 19814 return false; 19815 } 19816 } 19817 19818 return true; 19819 } 19820 19821 _attemptStrCaseInsensitive(chars) { 19822 for (let i = 0; i < chars.length; i++) { 19823 if (!this._attemptCharCodeCaseInsensitive(chars.charCodeAt(i))) { 19824 return false; 19825 } 19826 } 19827 19828 return true; 19829 } 19830 19831 _requireStr(chars) { 19832 const location = this._cursor.clone(); 19833 19834 if (!this._attemptStr(chars)) { 19835 throw this._createError(_unexpectedCharacterErrorMsg(this._cursor.peek()), this._cursor.getSpan(location)); 19836 } 19837 } 19838 19839 _attemptCharCodeUntilFn(predicate) { 19840 while (!predicate(this._cursor.peek())) { 19841 this._cursor.advance(); 19842 } 19843 } 19844 19845 _requireCharCodeUntilFn(predicate, len) { 19846 const start = this._cursor.clone(); 19847 19848 this._attemptCharCodeUntilFn(predicate); 19849 19850 if (this._cursor.diff(start) < len) { 19851 throw this._createError(_unexpectedCharacterErrorMsg(this._cursor.peek()), this._cursor.getSpan(start)); 19852 } 19853 } 19854 19855 _attemptUntilChar(char) { 19856 while (this._cursor.peek() !== char) { 19857 this._cursor.advance(); 19858 } 19859 } 19860 19861 _readChar() { 19862 // Don't rely upon reading directly from `_input` as the actual char value 19863 // may have been generated from an escape sequence. 19864 const char = String.fromCodePoint(this._cursor.peek()); 19865 19866 this._cursor.advance(); 19867 19868 return char; 19869 } 19870 19871 _consumeEntity(textTokenType) { 19872 this._beginToken(9 19873 /* TokenType.ENCODED_ENTITY */ 19874 ); 19875 19876 const start = this._cursor.clone(); 19877 19878 this._cursor.advance(); 19879 19880 if (this._attemptCharCode($HASH)) { 19881 const isHex = this._attemptCharCode($x) || this._attemptCharCode($X); 19882 19883 const codeStart = this._cursor.clone(); 19884 19885 this._attemptCharCodeUntilFn(isDigitEntityEnd); 19886 19887 if (this._cursor.peek() != $SEMICOLON) { 19888 // Advance cursor to include the peeked character in the string provided to the error 19889 // message. 19890 this._cursor.advance(); 19891 19892 const entityType = isHex ? CharacterReferenceType.HEX : CharacterReferenceType.DEC; 19893 throw this._createError(_unparsableEntityErrorMsg(entityType, this._cursor.getChars(start)), this._cursor.getSpan()); 19894 } 19895 19896 const strNum = this._cursor.getChars(codeStart); 19897 19898 this._cursor.advance(); 19899 19900 try { 19901 const charCode = parseInt(strNum, isHex ? 16 : 10); 19902 19903 this._endToken([String.fromCharCode(charCode), this._cursor.getChars(start)]); 19904 } catch { 19905 throw this._createError(_unknownEntityErrorMsg(this._cursor.getChars(start)), this._cursor.getSpan()); 19906 } 19907 } else { 19908 const nameStart = this._cursor.clone(); 19909 19910 this._attemptCharCodeUntilFn(isNamedEntityEnd); 19911 19912 if (this._cursor.peek() != $SEMICOLON) { 19913 // No semicolon was found so abort the encoded entity token that was in progress, and treat 19914 // this as a text token 19915 this._beginToken(textTokenType, start); 19916 19917 this._cursor = nameStart; 19918 19919 this._endToken(['&']); 19920 } else { 19921 const name = this._cursor.getChars(nameStart); 19922 19923 this._cursor.advance(); 19924 19925 const char = NAMED_ENTITIES[name]; 19926 19927 if (!char) { 19928 throw this._createError(_unknownEntityErrorMsg(name), this._cursor.getSpan(start)); 19929 } 19930 19931 this._endToken([char, `&${name};`]); 19932 } 19933 } 19934 } 19935 19936 _consumeRawText(consumeEntities, endMarkerPredicate) { 19937 this._beginToken(consumeEntities ? 6 19938 /* TokenType.ESCAPABLE_RAW_TEXT */ 19939 : 7 19940 /* TokenType.RAW_TEXT */ 19941 ); 19942 19943 const parts = []; 19944 19945 while (true) { 19946 const tagCloseStart = this._cursor.clone(); 19947 19948 const foundEndMarker = endMarkerPredicate(); 19949 this._cursor = tagCloseStart; 19950 19951 if (foundEndMarker) { 19952 break; 19953 } 19954 19955 if (consumeEntities && this._cursor.peek() === $AMPERSAND) { 19956 this._endToken([this._processCarriageReturns(parts.join(''))]); 19957 19958 parts.length = 0; 19959 19960 this._consumeEntity(6 19961 /* TokenType.ESCAPABLE_RAW_TEXT */ 19962 ); 19963 19964 this._beginToken(6 19965 /* TokenType.ESCAPABLE_RAW_TEXT */ 19966 ); 19967 } else { 19968 parts.push(this._readChar()); 19969 } 19970 } 19971 19972 this._endToken([this._processCarriageReturns(parts.join(''))]); 19973 } 19974 19975 _consumeComment(start) { 19976 this._beginToken(10 19977 /* TokenType.COMMENT_START */ 19978 , start); 19979 19980 this._requireCharCode($MINUS); 19981 19982 this._endToken([]); 19983 19984 this._consumeRawText(false, () => this._attemptStr('-->')); 19985 19986 this._beginToken(11 19987 /* TokenType.COMMENT_END */ 19988 ); 19989 19990 this._requireStr('-->'); 19991 19992 this._endToken([]); 19993 } 19994 19995 _consumeCdata(start) { 19996 this._beginToken(12 19997 /* TokenType.CDATA_START */ 19998 , start); 19999 20000 this._requireStr('CDATA['); 20001 20002 this._endToken([]); 20003 20004 this._consumeRawText(false, () => this._attemptStr(']]>')); 20005 20006 this._beginToken(13 20007 /* TokenType.CDATA_END */ 20008 ); 20009 20010 this._requireStr(']]>'); 20011 20012 this._endToken([]); 20013 } 20014 20015 _consumeDocType(start) { 20016 this._beginToken(18 20017 /* TokenType.DOC_TYPE */ 20018 , start); 20019 20020 const contentStart = this._cursor.clone(); 20021 20022 this._attemptUntilChar($GT); 20023 20024 const content = this._cursor.getChars(contentStart); 20025 20026 this._cursor.advance(); 20027 20028 this._endToken([content]); 20029 } 20030 20031 _consumePrefixAndName() { 20032 const nameOrPrefixStart = this._cursor.clone(); 20033 20034 let prefix = ''; 20035 20036 while (this._cursor.peek() !== $COLON && !isPrefixEnd(this._cursor.peek())) { 20037 this._cursor.advance(); 20038 } 20039 20040 let nameStart; 20041 20042 if (this._cursor.peek() === $COLON) { 20043 prefix = this._cursor.getChars(nameOrPrefixStart); 20044 20045 this._cursor.advance(); 20046 20047 nameStart = this._cursor.clone(); 20048 } else { 20049 nameStart = nameOrPrefixStart; 20050 } 20051 20052 this._requireCharCodeUntilFn(isNameEnd, prefix === '' ? 0 : 1); 20053 20054 const name = this._cursor.getChars(nameStart); 20055 20056 return [prefix, name]; 20057 } 20058 20059 _consumeTagOpen(start) { 20060 let tagName; 20061 let prefix; 20062 let openTagToken; 20063 20064 try { 20065 if (!isAsciiLetter(this._cursor.peek())) { 20066 throw this._createError(_unexpectedCharacterErrorMsg(this._cursor.peek()), this._cursor.getSpan(start)); 20067 } 20068 20069 openTagToken = this._consumeTagOpenStart(start); 20070 prefix = openTagToken.parts[0]; 20071 tagName = openTagToken.parts[1]; 20072 20073 this._attemptCharCodeUntilFn(isNotWhitespace); 20074 20075 while (this._cursor.peek() !== $SLASH && this._cursor.peek() !== $GT && this._cursor.peek() !== $LT && this._cursor.peek() !== $EOF) { 20076 this._consumeAttributeName(); 20077 20078 this._attemptCharCodeUntilFn(isNotWhitespace); 20079 20080 if (this._attemptCharCode($EQ)) { 20081 this._attemptCharCodeUntilFn(isNotWhitespace); 20082 20083 this._consumeAttributeValue(); 20084 } 20085 20086 this._attemptCharCodeUntilFn(isNotWhitespace); 20087 } 20088 20089 this._consumeTagOpenEnd(); 20090 } catch (e) { 20091 if (e instanceof _ControlFlowError) { 20092 if (openTagToken) { 20093 // We errored before we could close the opening tag, so it is incomplete. 20094 openTagToken.type = 4 20095 /* TokenType.INCOMPLETE_TAG_OPEN */ 20096 ; 20097 } else {
20098 // When the start tag is invalid, assume we want a "<" as text. 20099 // Back to back text tokens are merged at the end. 20100 this._beginToken(5 20101 /* TokenType.TEXT */ 20102 , start); 20103 20104 this._endToken(['<']); 20105 } 20106 20107 return; 20108 } 20109 20110 throw e; 20111 } 20112 20113 const contentTokenType = this._getTagDefinition(tagName).getContentType(prefix); 20114 20115 if (contentTokenType === TagContentType.RAW_TEXT) { 20116 this._consumeRawTextWithTagClose(prefix, tagName, false); 20117 } else if (contentTokenType === TagContentType.ESCAPABLE_RAW_TEXT) { 20118 this._consumeRawTextWithTagClose(prefix, tagName, true); 20119 } 20120 } 20121 20122 _consumeRawTextWithTagClose(prefix, tagName, consumeEntities) { 20123 this._consumeRawText(consumeEntities, () => { 20124 if (!this._attemptCharCode($LT)) return false; 20125 if (!this._attemptCharCode($SLASH)) return false; 20126 20127 this._attemptCharCodeUntilFn(isNotWhitespace); 20128 20129 if (!this._attemptStrCaseInsensitive(tagName)) return false; 20130 20131 this._attemptCharCodeUntilFn(isNotWhitespace); 20132 20133 return this._attemptCharCode($GT); 20134 }); 20135 20136 this._beginToken(3 20137 /* TokenType.TAG_CLOSE */ 20138 ); 20139 20140 this._requireCharCodeUntilFn(code => code === $GT, 3); 20141 20142 this._cursor.advance(); // Consume the `>` 20143 20144 20145 this._endToken([prefix, tagName]); 20146 } 20147 20148 _consumeTagOpenStart(start) { 20149 this._beginToken(0 20150 /* TokenType.TAG_OPEN_START */ 20151 , start); 20152 20153 const parts = this._consumePrefixAndName(); 20154 20155 return this._endToken(parts); 20156 } 20157 20158 _consumeAttributeName() { 20159 const attrNameStart = this._cursor.peek(); 20160 20161 if (attrNameStart === $SQ || attrNameStart === $DQ) { 20162 throw this._createError(_unexpectedCharacterErrorMsg(attrNameStart), this._cursor.getSpan()); 20163 } 20164 20165 this._beginToken(14 20166 /* TokenType.ATTR_NAME */ 20167 ); 20168 20169 const prefixAndName = this._consumePrefixAndName(); 20170 20171 this._endToken(prefixAndName); 20172 } 20173 20174 _consumeAttributeValue() { 20175 let value; 20176 20177 if (this._cursor.peek() === $SQ || this._cursor.peek() === $DQ) { 20178 const quoteChar = this._cursor.peek(); 20179 20180 this._consumeQuote(quoteChar); // In an attribute then end of the attribute value and the premature end to an interpolation 20181 // are both triggered by the `quoteChar`. 20182 20183 20184 const endPredicate = () => this._cursor.peek() === quoteChar; 20185 20186 this._consumeWithInterpolation(16 20187 /* TokenType.ATTR_VALUE_TEXT */ 20188 , 17 20189 /* TokenType.ATTR_VALUE_INTERPOLATION */ 20190 , endPredicate, endPredicate); 20191 20192 this._consumeQuote(quoteChar); 20193 } else { 20194 const endPredicate = () => isNameEnd(this._cursor.peek()); 20195 20196 this._consumeWithInterpolation(16 20197 /* TokenType.ATTR_VALUE_TEXT */ 20198 , 17 20199 /* TokenType.ATTR_VALUE_INTERPOLATION */ 20200 , endPredicate, endPredicate); 20201 } 20202 } 20203 20204 _consumeQuote(quoteChar) { 20205 this._beginToken(15 20206 /* TokenType.ATTR_QUOTE */ 20207 ); 20208 20209 this._requireCharCode(quoteChar); 20210 20211 this._endToken([String.fromCodePoint(quoteChar)]); 20212 } 20213 20214 _consumeTagOpenEnd() { 20215 const tokenType = this._attemptCharCode($SLASH) ? 2 20216 /* TokenType.TAG_OPEN_END_VOID */ 20217 : 1 20218 /* TokenType.TAG_OPEN_END */ 20219 ; 20220 20221 this._beginToken(tokenType); 20222 20223 this._requireCharCode($GT); 20224 20225 this._endToken([]); 20226 } 20227 20228 _consumeTagClose(start) { 20229 this._beginToken(3 20230 /* TokenType.TAG_CLOSE */ 20231 , start); 20232 20233 this._attemptCharCodeUntilFn(isNotWhitespace); 20234 20235 const prefixAndName = this._consumePrefixAndName(); 20236 20237 this._attemptCharCodeUntilFn(isNotWhitespace); 20238 20239 this._requireCharCode($GT); 20240 20241 this._endToken(prefixAndName); 20242 } 20243 20244 _consumeExpansionFormStart() { 20245 this._beginToken(19 20246 /* TokenType.EXPANSION_FORM_START */ 20247 ); 20248 20249 this._requireCharCode($LBRACE); 20250 20251 this._endToken([]); 20252 20253 this._expansionCaseStack.push(19 20254 /* TokenType.EXPANSION_FORM_START */ 20255 ); 20256 20257 this._beginToken(7 20258 /* TokenType.RAW_TEXT */ 20259 ); 20260 20261 const condition = this._readUntil($COMMA); 20262 20263 const normalizedCondition = this._processCarriageReturns(condition); 20264 20265 if (this._i18nNormalizeLineEndingsInICUs) { 20266 // We explicitly want to normalize line endings for this text. 20267 this._endToken([normalizedCondition]); 20268 } else { 20269 // We are not normalizing line endings. 20270 const conditionToken = this._endToken([condition]); 20271 20272 if (normalizedCondition !== condition) { 20273 this.nonNormalizedIcuExpressions.push(conditionToken); 20274 } 20275 } 20276 20277 this._requireCharCode($COMMA); 20278 20279 this._attemptCharCodeUntilFn(isNotWhitespace); 20280 20281 this._beginToken(7 20282 /* TokenType.RAW_TEXT */ 20283 ); 20284 20285 const type = this._readUntil($COMMA); 20286 20287 this._endToken([type]); 20288 20289 this._requireCharCode($COMMA); 20290 20291 this._attemptCharCodeUntilFn(isNotWhitespace); 20292 } 20293 20294 _consumeExpansionCaseStart() { 20295 this._beginToken(20 20296 /* TokenType.EXPANSION_CASE_VALUE */ 20297 ); 20298 20299 const value = this._readUntil($LBRACE).trim(); 20300 20301 this._endToken([value]); 20302 20303 this._attemptCharCodeUntilFn(isNotWhitespace); 20304 20305 this._beginToken(21 20306 /* TokenType.EXPANSION_CASE_EXP_START */ 20307 ); 20308 20309 this._requireCharCode($LBRACE); 20310 20311 this._endToken([]); 20312 20313 this._attemptCharCodeUntilFn(isNotWhitespace); 20314 20315 this._expansionCaseStack.push(21 20316 /* TokenType.EXPANSION_CASE_EXP_START */ 20317 ); 20318 } 20319 20320 _consumeExpansionCaseEnd() { 20321 this._beginToken(22 20322 /* TokenType.EXPANSION_CASE_EXP_END */ 20323 ); 20324 20325 this._requireCharCode($RBRACE); 20326 20327 this._endToken([]); 20328 20329 this._attemptCharCodeUntilFn(isNotWhitespace); 20330 20331 this._expansionCaseStack.pop(); 20332 } 20333 20334 _consumeExpansionFormEnd() { 20335 this._beginToken(23 20336 /* TokenType.EXPANSION_FORM_END */ 20337 ); 20338 20339 this._requireCharCode($RBRACE); 20340 20341 this._endToken([]); 20342 20343 this._expansionCaseStack.pop(); 20344 } 20345 /** 20346 * Consume a string that may contain interpolation expressions. 20347 * 20348 * The first token consumed will be of `tokenType` and then there will be alternating 20349 * `interpolationTokenType` and `tokenType` tokens until the `endPredicate()` returns true. 20350 * 20351 * If an interpolation token ends prematurely it will have no end marker in its `parts` array. 20352 * 20353 * @param textTokenType the kind of tokens to interleave around interpolation tokens. 20354 * @param interpolationTokenType the kind of tokens that contain interpolation. 20355 * @param endPredicate a function that should return true when we should stop consuming. 20356 * @param endInterpolation a function that should return true if there is a premature end to an 20357 * interpolation expression - i.e. before we get to the normal interpolation closing marker. 20358 */ 20359 20360 20361 _consumeWithInterpolation(textTokenType, interpolationTokenType, endPredicate, endInterpolation) { 20362 this._beginToken(textTokenType); 20363 20364 const parts = []; 20365
20366 while (!endPredicate()) { 20367 const current = this._cursor.clone(); 20368 20369 if (this._interpolationConfig && this._attemptStr(this._interpolationConfig.start)) { 20370 this._endToken([this._processCarriageReturns(parts.join(''))], current); 20371 20372 parts.length = 0; 20373 20374 this._consumeInterpolation(interpolationTokenType, current, endInterpolation); 20375 20376 this._beginToken(textTokenType); 20377 } else if (this._cursor.peek() === $AMPERSAND) { 20378 this._endToken([this._processCarriageReturns(parts.join(''))]); 20379 20380 parts.length = 0; 20381 20382 this._consumeEntity(textTokenType); 20383 20384 this._beginToken(textTokenType); 20385 } else { 20386 parts.push(this._readChar()); 20387 } 20388 } // It is possible that an interpolation was started but not ended inside this text token. 20389 // Make sure that we reset the state of the lexer correctly. 20390 20391 20392 this._inInterpolation = false; 20393 20394 this._endToken([this._processCarriageReturns(parts.join(''))]); 20395 } 20396 /** 20397 * Consume a block of text that has been interpreted as an Angular interpolation. 20398 * 20399 * @param interpolationTokenType the type of the interpolation token to generate. 20400 * @param interpolationStart a cursor that points to the start of this interpolation. 20401 * @param prematureEndPredicate a function that should return true if the next characters indicate 20402 * an end to the interpolation before its normal closing marker. 20403 */ 20404 20405 20406 _consumeInterpolation(interpolationTokenType, interpolationStart, prematureEndPredicate) { 20407 const parts = []; 20408 20409 this._beginToken(interpolationTokenType, interpolationStart); 20410 20411 parts.push(this._interpolationConfig.start); // Find the end of the interpolation, ignoring content inside quotes. 20412 20413 const expressionStart = this._cursor.clone(); 20414 20415 let inQuote = null; 20416 let inComment = false; 20417 20418 while (this._cursor.peek() !== $EOF && (prematureEndPredicate === null || !prematureEndPredicate())) { 20419 const current = this._cursor.clone(); 20420 20421 if (this._isTagStart()) { 20422 // We are starting what looks like an HTML element in the middle of this interpolation. 20423 // Reset the cursor to before the `<` character and end the interpolation token. 20424 // (This is actually wrong but here for backward compatibility). 20425 this._cursor = current; 20426 parts.push(this._getProcessedChars(expressionStart, current)); 20427 20428 this._endToken(parts); 20429 20430 return; 20431 } 20432 20433 if (inQuote === null) { 20434 if (this._attemptStr(this._interpolationConfig.end)) { 20435 // We are not in a string, and we hit the end interpolation marker 20436 parts.push(this._getProcessedChars(expressionStart, current)); 20437 parts.push(this._interpolationConfig.end); 20438 20439 this._endToken(parts); 20440 20441 return; 20442 } else if (this._attemptStr('//')) { 20443 // Once we are in a comment we ignore any quotes 20444 inComment = true; 20445 } 20446 } 20447 20448 const char = this._cursor.peek(); 20449 20450 this._cursor.advance(); 20451 20452 if (char === $BACKSLASH) { 20453 // Skip the next character because it was escaped. 20454 this._cursor.advance(); 20455 } else if (char === inQuote) { 20456 // Exiting the current quoted string 20457 inQuote = null; 20458 } else if (!inComment && inQuote === null && isQuote(char)) { 20459 // Entering a new quoted string 20460 inQuote = char; 20461 } 20462 } // We hit EOF without finding a closing interpolation marker 20463 20464 20465 parts.push(this._getProcessedChars(expressionStart, this._cursor)); 20466 20467 this._endToken(parts); 20468 } 20469 20470 _getProcessedChars(start, end) { 20471 return this._processCarriageReturns(end.getChars(start)); 20472 } 20473 20474 _isTextEnd() { 20475 if (this._isTagStart() || this._cursor.peek() === $EOF) { 20476 return true; 20477 } 20478 20479 if (this._tokenizeIcu && !this._inInterpolation) { 20480 if (this.isExpansionFormStart()) { 20481 // start of an expansion form 20482 return true; 20483 } 20484 20485 if (this._cursor.peek() === $RBRACE && this._isInExpansionCase()) { 20486 // end of and expansion case 20487 return true; 20488 } 20489 } 20490 20491 return false; 20492 } 20493 /** 20494 * Returns true if the current cursor is pointing to the start of a tag 20495 * (opening/closing/comments/cdata/etc). 20496 */ 20497 20498 20499 _isTagStart() { 20500 if (this._cursor.peek() === $LT) { 20501 // We assume that `<` followed by whitespace is not the start of an HTML element. 20502 const tmp = this._cursor.clone(); 20503 20504 tmp.advance(); // If the next character is alphabetic, ! nor / then it is a tag start 20505 20506 const code = tmp.peek(); 20507 20508 if ($a <= code && code <= $z || $A <= code && code <= $Z || code === $SLASH || code === $BANG) { 20509 return true; 20510 } 20511 } 20512 20513 return false;
20514 } 20515 20516 _readUntil(char) { 20517 const start = this._cursor.clone(); 20518 20519 this._attemptUntilChar(char); 20520 20521 return this._cursor.getChars(start); 20522 } 20523 20524 _isInExpansionCase() { 20525 return this._expansionCaseStack.length > 0 && this._expansionCaseStack[this._expansionCaseStack.length - 1] === 21 20526 /* TokenType.EXPANSION_CASE_EXP_START */ 20527 ; 20528 } 20529 20530 _isInExpansionForm() { 20531 return this._expansionCaseStack.length > 0 && this._expansionCaseStack[this._expansionCaseStack.length - 1] === 19 20532 /* TokenType.EXPANSION_FORM_START */ 20533 ; 20534 } 20535 20536 isExpansionFormStart() { 20537 if (this._cursor.peek() !== $LBRACE) { 20538 return false; 20539 } 20540 20541 if (this._interpolationConfig) { 20542 const start = this._cursor.clone(); 20543 20544 const isInterpolation = this._attemptStr(this._interpolationConfig.start); 20545 20546 this._cursor = start; 20547 return !isInterpolation; 20548 } 20549 20550 return true; 20551 } 20552 20553} 20554 20555function isNotWhitespace(code) { 20556 return !isWhitespace(code) || code === $EOF; 20557} 20558 20559function isNameEnd(code) { 20560 return isWhitespace(code) || code === $GT || code === $LT || code === $SLASH || code === $SQ || code === $DQ || code === $EQ || code === $EOF; 20561} 20562 20563function isPrefixEnd(code) { 20564 return (code < $a || $z < code) && (code < $A || $Z < code) && (code < $0 || code > $9); 20565} 20566 20567function isDigitEntityEnd(code) { 20568 return code === $SEMICOLON || code === $EOF || !isAsciiHexDigit(code); 20569} 20570 20571function isNamedEntityEnd(code) { 20572 return code === $SEMICOLON || code === $EOF || !isAsciiLetter(code); 20573} 20574 20575function isExpansionCaseStart(peek) { 20576 return peek !== $RBRACE; 20577} 20578 20579function compareCharCodeCaseInsensitive(code1, code2) { 20580 return toUpperCaseCharCode(code1) === toUpperCaseCharCode(code2); 20581} 20582 20583function toUpperCaseCharCode(code) { 20584 return code >= $a && code <= $z ? code - $a + $A : code; 20585} 20586 20587function mergeTextTokens(srcTokens) { 20588 const dstTokens = []; 20589 let lastDstToken = undefined; 20590 20591 for (let i = 0; i < srcTokens.length; i++) { 20592 const token = srcTokens[i]; 20593 20594 if (lastDstToken && lastDstToken.type === 5 20595 /* TokenType.TEXT */ 20596 && token.type === 5 20597 /* TokenType.TEXT */ 20598 || lastDstToken && lastDstToken.type === 16 20599 /* TokenType.ATTR_VALUE_TEXT */ 20600 && token.type === 16 20601 /* TokenType.ATTR_VALUE_TEXT */ 20602 ) { 20603 lastDstToken.parts[0] += token.parts[0]; 20604 lastDstToken.sourceSpan.end = token.sourceSpan.end; 20605 } else { 20606 lastDstToken = token; 20607 dstTokens.push(lastDstToken); 20608 } 20609 } 20610 20611 return dstTokens; 20612} 20613 20614class PlainCharacterCursor { 20615 constructor(fileOrCursor, range) { 20616 if (fileOrCursor instanceof PlainCharacterCursor) { 20617 this.file = fileOrCursor.file; 20618 this.input = fileOrCursor.input; 20619 this.end = fileOrCursor.end; 20620 const state = fileOrCursor.state; // Note: avoid using `{...fileOrCursor.state}` here as that has a severe performance penalty. 20621 // In ES5 bundles the object spread operator is translated into the `__assign` helper, which 20622 // is not optimized by VMs as efficiently as a raw object literal. Since this constructor is 20623 // called in tight loops, this difference matters. 20624 20625 this.state = { 20626 peek: state.peek, 20627 offset: state.offset, 20628 line: state.line, 20629 column: state.column 20630 }; 20631 } else { 20632 if (!range) { 20633 throw new Error('Programming error: the range argument must be provided with a file argument.'); 20634 } 20635 20636 this.file = fileOrCursor; 20637 this.input = fileOrCursor.content; 20638 this.end = range.endPos; 20639 this.state = { 20640 peek: -1, 20641 offset: range.startPos, 20642 line: range.startLine, 20643 column: range.startCol 20644 }; 20645 } 20646 } 20647 20648 clone() { 20649 return new PlainCharacterCursor(this); 20650 } 20651 20652 peek() { 20653 return this.state.peek; 20654 } 20655 20656 charsLeft() { 20657 return this.end - this.state.offset; 20658 } 20659 20660 diff(other) { 20661 return this.state.offset - other.state.offset; 20662 } 20663 20664 advance() { 20665 this.advanceState(this.state); 20666 } 20667 20668 init() { 20669 this.updatePeek(this.state); 20670 } 20671 20672 getSpan(start, leadingTriviaCodePoints) { 20673 start = start || this; 20674 let fullStart = start; 20675 20676 if (leadingTriviaCodePoints) { 20677 while (this.diff(start) > 0 && leadingTriviaCodePoints.indexOf(start.peek()) !== -1) { 20678 if (fullStart === start) { 20679 start = start.clone(); 20680 } 20681 20682 start.advance(); 20683 } 20684 } 20685 20686 const startLocation = this.locationFromCursor(start); 20687 const endLocation = this.locationFromCursor(this); 20688 const fullStartLocation = fullStart !== start ? this.locationFromCursor(fullStart) : startLocation; 20689 return new ParseSourceSpan(startLocation, endLocation, fullStartLocation); 20690 } 20691 20692 getChars(start) { 20693 return this.input.substring(start.state.offset, this.state.offset); 20694 } 20695 20696 charAt(pos) { 20697 return this.input.charCodeAt(pos); 20698 } 20699 20700 advanceState(state) { 20701 if (state.offset >= this.end) { 20702 this.state = state; 20703 throw new CursorError('Unexpected character "EOF"', this); 20704 } 20705 20706 const currentChar = this.charAt(state.offset); 20707 20708 if (currentChar === $LF) { 20709 state.line++; 20710 state.column = 0; 20711 } else if (!isNewLine(currentChar)) { 20712 state.column++; 20713 } 20714 20715 state.offset++; 20716 this.updatePeek(state); 20717 } 20718 20719 updatePeek(state) { 20720 state.peek = state.offset >= this.end ? $EOF : this.charAt(state.offset); 20721 } 20722 20723 locationFromCursor(cursor) { 20724 return new ParseLocation(cursor.file, cursor.state.offset, cursor.state.line, cursor.state.column); 20725 } 20726 20727} 20728 20729class EscapedCharacterCursor extends PlainCharacterCursor { 20730 constructor(fileOrCursor, range) { 20731 if (fileOrCursor instanceof EscapedCharacterCursor) { 20732 super(fileOrCursor); 20733 this.internalState = { ...fileOrCursor.internalState 20734 }; 20735 } else { 20736 super(fileOrCursor, range); 20737 this.internalState = this.state; 20738 } 20739 } 20740 20741 advance() { 20742 this.state = this.internalState; 20743 super.advance(); 20744 this.processEscapeSequence(); 20745 } 20746 20747 init() { 20748 super.init(); 20749 this.processEscapeSequence(); 20750 } 20751 20752 clone() { 20753 return new EscapedCharacterCursor(this); 20754 } 20755 20756 getChars(start) { 20757 const cursor = start.clone();
20758 let chars = ''; 20759 20760 while (cursor.internalState.offset < this.internalState.offset) { 20761 chars += String.fromCodePoint(cursor.peek()); 20762 cursor.advance(); 20763 } 20764 20765 return chars; 20766 } 20767 /** 20768 * Process the escape sequence that starts at the current position in the text. 20769 * 20770 * This method is called to ensure that `peek` has the unescaped value of escape sequences. 20771 */ 20772 20773 20774 processEscapeSequence() { 20775 const peek = () => this.internalState.peek; 20776 20777 if (peek() === $BACKSLASH) { 20778 // We have hit an escape sequence so we need the internal state to become independent 20779 // of the external state. 20780 this.internalState = { ...this.state 20781 }; // Move past the backslash 20782 20783 this.advanceState(this.internalState); // First check for standard control char sequences 20784 20785 if (peek() === $n) { 20786 this.state.peek = $LF; 20787 } else if (peek() === $r) { 20788 this.state.peek = $CR; 20789 } else if (peek() === $v) { 20790 this.state.peek = $VTAB; 20791 } else if (peek() === $t) { 20792 this.state.peek = $TAB; 20793 } else if (peek() === $b) { 20794 this.state.peek = $BSPACE; 20795 } else if (peek() === $f) { 20796 this.state.peek = $FF; 20797 } // Now consider more complex sequences 20798 else if (peek() === $u) { 20799 // Unicode code-point sequence 20800 this.advanceState(this.internalState); // advance past the `u` char 20801 20802 if (peek() === $LBRACE) { 20803 // Variable length Unicode, e.g. `\x{123}` 20804 this.advanceState(this.internalState); // advance past the `{` char 20805 // Advance past the variable number of hex digits until we hit a `}` char 20806 20807 const digitStart = this.clone(); 20808 let length = 0; 20809 20810 while (peek() !== $RBRACE) { 20811 this.advanceState(this.internalState); 20812 length++; 20813 } 20814 20815 this.state.peek = this.decodeHexDigits(digitStart, length); 20816 } else { 20817 // Fixed length Unicode, e.g. `\u1234` 20818 const digitStart = this.clone(); 20819 this.advanceState(this.internalState); 20820 this.advanceState(this.internalState); 20821 this.advanceState(this.internalState); 20822 this.state.peek = this.decodeHexDigits(digitStart, 4); 20823 } 20824 } else if (peek() === $x) { 20825 // Hex char code, e.g. `\x2F` 20826 this.advanceState(this.internalState); // advance past the `x` char 20827 20828 const digitStart = this.clone(); 20829 this.advanceState(this.internalState); 20830 this.state.peek = this.decodeHexDigits(digitStart, 2); 20831 } else if (isOctalDigit(peek())) { 20832 // Octal char code, e.g. `\012`, 20833 let octal = ''; 20834 let length = 0; 20835 let previous = this.clone(); 20836 20837 while (isOctalDigit(peek()) && length < 3) { 20838 previous = this.clone(); 20839 octal += String.fromCodePoint(peek()); 20840 this.advanceState(this.internalState); 20841 length++; 20842 } 20843 20844 this.state.peek = parseInt(octal, 8); // Backup one char 20845 20846 this.internalState = previous.internalState; 20847 } else if (isNewLine(this.internalState.peek)) { 20848 // Line continuation `\` followed by a new line 20849 this.advanceState(this.internalState); // advance over the newline 20850 20851 this.state = this.internalState; 20852 } else { 20853 // If none of the `if` blocks were executed then we just have an escaped normal character. 20854 // In that case we just, effectively, skip the backslash from the character. 20855 this.state.peek = this.internalState.peek; 20856 } 20857 } 20858 } 20859 20860 decodeHexDigits(start, length) { 20861 const hex = this.input.slice(start.internalState.offset, start.internalState.offset + length); 20862 const charCode = parseInt(hex, 16); 20863 20864 if (!isNaN(charCode)) { 20865 return charCode; 20866 } else { 20867 start.state = start.internalState; 20868 throw new CursorError('Invalid hexadecimal escape sequence', start); 20869 } 20870 } 20871 20872} 20873 20874class CursorError { 20875 constructor(msg, cursor) { 20876 this.msg = msg; 20877 this.cursor = cursor; 20878 } 20879 20880} 20881/** 20882 * @license 20883 * Copyright Google LLC All Rights Reserved. 20884 * 20885 * Use of this source code is governed by an MIT-style license that can be 20886 * found in the LICENSE file at https://angular.io/license 20887 */ 20888 20889 20890class TreeError extends ParseError { 20891 constructor(elementName, span, msg) { 20892 super(span, msg); 20893 this.elementName = elementName; 20894 } 20895 20896 static create(elementName, span, msg) { 20897 return new TreeError(elementName, span, msg); 20898 } 20899 20900} 20901 20902class ParseTreeResult { 20903 constructor(rootNodes, errors) { 20904 this.rootNodes = rootNodes; 20905 this.errors = errors; 20906 } 20907 20908} 20909 20910class Parser { 20911 constructor(getTagDefinition) { 20912 this.getTagDefinition = getTagDefinition; 20913 } 20914 20915 parse(source, url, options) { 20916 const tokenizeResult = tokenize(source, url, this.getTagDefinition, options); 20917 const parser = new _TreeBuilder(tokenizeResult.tokens, this.getTagDefinition); 20918 parser.build(); 20919 return new ParseTreeResult(parser.rootNodes, tokenizeResult.errors.concat(parser.errors)); 20920 } 20921 20922} 20923 20924class _TreeBuilder { 20925 constructor(tokens, getTagDefinition) { 20926 this.tokens = tokens; 20927 this.getTagDefinition = getTagDefinition; 20928 this._index = -1; 20929 this._elementStack = []; 20930 this.rootNodes = []; 20931 this.errors = []; 20932 20933 this._advance(); 20934 } 20935 20936 build() { 20937 while (this._peek.type !== 24 20938 /* TokenType.EOF */ 20939 ) { 20940 if (this._peek.type === 0 20941 /* TokenType.TAG_OPEN_START */ 20942 || this._peek.type === 4 20943 /* TokenType.INCOMPLETE_TAG_OPEN */ 20944 ) { 20945 this._consumeStartTag(this._advance()); 20946 } else if (this._peek.type === 3 20947 /* TokenType.TAG_CLOSE */ 20948 ) { 20949 this._consumeEndTag(this._advance()); 20950 } else if (this._peek.type === 12 20951 /* TokenType.CDATA_START */ 20952 ) { 20953 this._closeVoidElement(); 20954 20955 this._consumeCdata(this._advance()); 20956 } else if (this._peek.type === 10 20957 /* TokenType.COMMENT_START */ 20958 ) { 20959 this._closeVoidElement(); 20960 20961 this._consumeComment(this._advance()); 20962 } else if (this._peek.type === 5 20963 /* TokenType.TEXT */ 20964 || this._peek.type === 7 20965 /* TokenType.RAW_TEXT */ 20966 || this._peek.type === 6 20967 /* TokenType.ESCAPABLE_RAW_TEXT */ 20968 ) { 20969 this._closeVoidElement(); 20970 20971 this._consumeText(this._advance()); 20972 } else if (this._peek.type === 19 20973 /* TokenType.EXPANSION_FORM_START */ 20974 ) { 20975 this._consumeExpansion(this._advance()); 20976 } else { 20977 // Skip all other tokens... 20978 this._advance(); 20979 } 20980 } 20981 } 20982 20983 _advance() { 20984 const prev = this._peek; 20985 20986 if (this._index < this.tokens.length - 1) { 20987 // Note: there is always an EOF token at the end 20988 this._index++; 20989 } 20990 20991 this._peek = this.tokens[this._index]; 20992 return prev; 20993 } 20994 20995 _advanceIf(type) { 20996 if (this._peek.type === type) { 20997 return this._advance(); 20998 } 20999 21000 return null; 21001 } 21002 21003 _consumeCdata(_startToken) { 21004 this._consumeText(this._advance()); 21005 21006 this._advanceIf(13 21007 /* TokenType.CDATA_END */ 21008 ); 21009 } 21010 21011 _consumeComment(token) { 21012 const text = this._advanceIf(7 21013 /* TokenType.RAW_TEXT */ 21014 ); 21015 21016 this._advanceIf(11 21017 /* TokenType.COMMENT_END */ 21018 ); 21019 21020 const value = text != null ? text.parts[0].trim() : null; 21021 21022 this._addToParent(new Comment(value, token.sourceSpan)); 21023 } 21024 21025 _consumeExpansion(token) { 21026 const switchValue = this._advance(); 21027 21028 const type = this._advance(); 21029 21030 const cases = []; // read = 21031 21032 while (this._peek.type === 20 21033 /* TokenType.EXPANSION_CASE_VALUE */ 21034 ) { 21035 const expCase = this._parseExpansionCase(); 21036 21037 if (!expCase) return; // error 21038 21039 cases.push(expCase); 21040 } // read the final } 21041 21042 21043 if (this._peek.type !== 23 21044 /* TokenType.EXPANSION_FORM_END */ 21045 ) { 21046 this.errors.push(TreeError.create(null, this._peek.sourceSpan, `Invalid ICU message. Missing '}'.`)); 21047 return; 21048 } 21049 21050 const sourceSpan = new ParseSourceSpan(token.sourceSpan.start, this._peek.sourceSpan.end, token.sourceSpan.fullStart); 21051 21052 this._addToParent(new Expansion(switchValue.parts[0], type.parts[0], cases, sourceSpan, switchValue.sourceSpan)); 21053 21054 this._advance(); 21055 } 21056 21057 _parseExpansionCase() { 21058 const value = this._advance(); // read { 21059 21060 21061 if (this._peek.type !== 21 21062 /* TokenType.EXPANSION_CASE_EXP_START */ 21063 ) { 21064 this.errors.push(TreeError.create(null, this._peek.sourceSpan, `Invalid ICU message. Missing '{'.`)); 21065 return null; 21066 } // read until } 21067 21068 21069 const start = this._advance(); 21070 21071 const exp = this._collectExpansionExpTokens(start); 21072 21073 if (!exp) return null; 21074 21075 const end = this._advance(); 21076 21077 exp.push({ 21078 type: 24 21079 /* TokenType.EOF */ 21080 , 21081 parts: [], 21082 sourceSpan: end.sourceSpan 21083 }); // parse everything in between { and } 21084 21085 const expansionCaseParser = new _TreeBuilder(exp, this.getTagDefinition); 21086 expansionCaseParser.build(); 21087 21088 if (expansionCaseParser.errors.length > 0) { 21089 this.errors = this.errors.concat(expansionCaseParser.errors); 21090 return null; 21091 } 21092 21093 const sourceSpan = new ParseSourceSpan(value.sourceSpan.start, end.sourceSpan.end, value.sourceSpan.fullStart); 21094 const expSourceSpan = new ParseSourceSpan(start.sourceSpan.start, end.sourceSpan.end, start.sourceSpan.fullStart); 21095 return new ExpansionCase(value.parts[0], expansionCaseParser.rootNodes, sourceSpan, value.sourceSpan, expSourceSpan); 21096 } 21097 21098 _collectExpansionExpTokens(start) { 21099 const exp = []; 21100 const expansionFormStack = [21 21101 /* TokenType.EXPANSION_CASE_EXP_START */ 21102 ]; 21103 21104 while (true) { 21105 if (this._peek.type === 19 21106 /* TokenType.EXPANSION_FORM_START */ 21107 || this._peek.type === 21 21108 /* TokenType.EXPANSION_CASE_EXP_START */ 21109 ) { 21110 expansionFormStack.push(this._peek.type); 21111 } 21112 21113 if (this._peek.type === 22 21114 /* TokenType.EXPANSION_CASE_EXP_END */ 21115 ) { 21116 if (lastOnStack(expansionFormStack, 21 21117 /* TokenType.EXPANSION_CASE_EXP_START */ 21118 )) { 21119 expansionFormStack.pop(); 21120 if (expansionFormStack.length === 0) return exp; 21121 } else { 21122 this.errors.push(TreeError.create(null, start.sourceSpan, `Invalid ICU message. Missing '}'.`)); 21123 return null; 21124 } 21125 } 21126 21127 if (this._peek.type === 23 21128 /* TokenType.EXPANSION_FORM_END */ 21129 ) { 21130 if (lastOnStack(expansionFormStack, 19 21131 /* TokenType.EXPANSION_FORM_START */ 21132 )) { 21133 expansionFormStack.pop(); 21134 } else { 21135 this.errors.push(TreeError.create(null, start.sourceSpan, `Invalid ICU message. Missing '}'.`)); 21136 return null; 21137 } 21138 } 21139 21140 if (this._peek.type === 24 21141 /* TokenType.EOF */ 21142 ) { 21143 this.errors.push(TreeError.create(null, start.sourceSpan, `Invalid ICU message. Missing '}'.`)); 21144 return null; 21145 } 21146 21147 exp.push(this._advance()); 21148 } 21149 } 21150 21151 _consumeText(token) { 21152 const tokens = [token]; 21153 const startSpan = token.sourceSpan; 21154 let text = token.parts[0]; 21155 21156 if (text.length > 0 && text[0] === '\n') { 21157 const parent = this._getParentElement(); 21158 21159 if (parent != null && parent.children.length === 0 && this.getTagDefinition(parent.name).ignoreFirstLf) { 21160 text = text.substring(1); 21161 tokens[0] = { 21162 type: token.type, 21163 sourceSpan: token.sourceSpan, 21164 parts: [text] 21165 }; 21166 } 21167 } 21168 21169 while (this._peek.type === 8 21170 /* TokenType.INTERPOLATION */ 21171 || this._peek.type === 5 21172 /* TokenType.TEXT */ 21173 || this._peek.type === 9 21174 /* TokenType.ENCODED_ENTITY */ 21175 ) { 21176 token = this._advance(); 21177 tokens.push(token); 21178 21179 if (token.type === 8 21180 /* TokenType.INTERPOLATION */ 21181 ) { 21182 // For backward compatibility we decode HTML entities that appear in interpolation 21183 // expressions. This is arguably a bug, but it could be a considerable breaking change to 21184 // fix it. It should be addressed in a larger project to refactor the entire parser/lexer 21185 // chain after View Engine has been removed. 21186 text += token.parts.join('').replace(/&([^;]+);/g, decodeEntity); 21187 } else if (token.type === 9 21188 /* TokenType.ENCODED_ENTITY */ 21189 ) { 21190 text += token.parts[0]; 21191 } else { 21192 text += token.parts.join(''); 21193 } 21194 } 21195 21196 if (text.length > 0) { 21197 const endSpan = token.sourceSpan; 21198 21199 this._addToParent(new Text(text, new ParseSourceSpan(start
21199Span.start, endSpan.end, startSpan.fullStart, startSpan.details), tokens)); 21200 } 21201 } 21202 21203 _closeVoidElement() { 21204 const el = this._getParentElement(); 21205 21206 if (el && this.getTagDefinition(el.name).isVoid) { 21207 this._elementStack.pop(); 21208 } 21209 } 21210 21211 _consumeStartTag(startTagToken) { 21212 const [prefix, name] = startTagToken.parts; 21213 const attrs = []; 21214 21215 while (this._peek.type === 14 21216 /* TokenType.ATTR_NAME */ 21217 ) { 21218 attrs.push(this._consumeAttr(this._advance())); 21219 } 21220 21221 const fullName = this._getElementFullName(prefix, name, this._getParentElement()); 21222 21223 let selfClosing = false; // Note: There could have been a tokenizer error 21224 // so that we don't get a token for the end tag... 21225 21226 if (this._peek.type === 2 21227 /* TokenType.TAG_OPEN_END_VOID */ 21228 ) { 21229 this._advance(); 21230 21231 selfClosing = true; 21232 const tagDef = this.getTagDefinition(fullName); 21233 21234 if (!(tagDef.canSelfClose || getNsPrefix(fullName) !== null || tagDef.isVoid)) { 21235 this.errors.push(TreeError.create(fullName, startTagToken.sourceSpan, `Only void and foreign elements can be self closed "${startTagToken.parts[1]}"`)); 21236 } 21237 } else if (this._peek.type === 1 21238 /* TokenType.TAG_OPEN_END */ 21239 ) { 21240 this._advance(); 21241 21242 selfClosing = false; 21243 } 21244 21245 const end = this._peek.sourceSpan.fullStart; 21246 const span = new ParseSourceSpan(startTagToken.sourceSpan.start, end, startTagToken.sourceSpan.fullStart); // Create a separate `startSpan` because `span` will be modified when there is an `end` span. 21247 21248 const startSpan = new ParseSourceSpan(startTagToken.sourceSpan.start, end, startTagToken.sourceSpan.fullStart); 21249 const el = new Element(fullName, attrs, [], span, startSpan, undefined); 21250 21251 this._pushElement(el); 21252 21253 if (selfClosing) { 21254 // Elements that are self-closed have their `endSourceSpan` set to the full span, as the 21255 // element start tag also represents the end tag. 21256 this._popElement(fullName, span); 21257 } else if (startTagToken.type === 4 21258 /* TokenType.INCOMPLETE_TAG_OPEN */ 21259 ) { 21260 // We already know the opening tag is not complete, so it is unlikely it has a corresponding 21261 // close tag. Let's optimistically parse it as a full element and emit an error. 21262 this._popElement(fullName, null); 21263 21264 this.errors.push(TreeError.create(fullName, span, `Opening tag "${fullName}" not terminated.`)); 21265 } 21266 } 21267 21268 _pushElement(el) { 21269 const parentEl = this._getParentElement(); 21270 21271 if (parentEl && this.getTagDefinition(parentEl.name).isClosedByChild(el.name)) { 21272 this._elementStack.pop(); 21273 } 21274 21275 this._addToParent(el); 21276 21277 this._elementStack.push(el); 21278 } 21279 21280 _consumeEndTag(endTagToken) { 21281 const fullName = this._getElementFullName(endTagToken.parts[0], endTagToken.parts[1], this._getParentElement()); 21282 21283 if (this.getTagDefinition(fullName).isVoid) { 21284 this.errors.push(TreeError.create(fullName, endTagToken.sourceSpan, `Void elements do not have end tags "${endTagToken.parts[1]}"`)); 21285 } else if (!this._popElement(fullName, endTagToken.sourceSpan)) { 21286 const errMsg = `Unexpected closing tag "${fullName}". It may happen when the tag has already been closed by another tag. For more info see https://www.w3.org/TR/html5/syntax.html#closing-elements-that-have-implied-end-tags`; 21287 this.errors.push(TreeError.create(fullName, endTagToken.sourceSpan, errMsg)); 21288 } 21289 } 21290 /** 21291 * Closes the nearest element with the tag name `fullName` in the parse tree. 21292 * `endSourceSpan` is the span of the closing tag, or null if the element does 21293 * not have a closing tag (for example, this happens when an incomplete 21294 * opening tag is recovered). 21295 */ 21296 21297 21298 _popElement(fullName, endSourceSpan) { 21299 let unexpectedCloseTagDetected = false; 21300 21301 for (let stackIndex = this._elementStack.length - 1; stackIndex >= 0; stackIndex--) { 21302 const el = this._elementStack[stackIndex]; 21303 21304 if (el.name === fullName) { 21305 // Record the parse span with the element that is being closed. Any elements that are 21306 // removed from the element stack at this point are closed implicitly, so they won't get 21307 // an end source span (as there is no explicit closing element). 21308 el.endSourceSpan = endSourceSpan; 21309 el.sourceSpan.end = endSourceSpan !== null ? endSourceSpan.end : el.sourceSpan.end; 21310 21311 this._elementStack.splice(stackIndex, this._elementStack.length - stackIndex); 21312 21313 return !unexpectedCloseTagDetected; 21314 } 21315 21316 if (!this.getTagDefinition(el.name).closedByParent) { 21317 // Note that we encountered an unexpected close tag but continue processing the element 21318 // stack so we can assign an `endSourceSpan` if there is a corresponding start tag for this 21319 // end tag in the stack. 21320 unexpectedCloseTagDetected = true; 21321 } 21322 } 21323 21324 return false;
21325 } 21326 21327 _consumeAttr(attrName) { 21328 const fullName = mergeNsAndName(attrName.parts[0], attrName.parts[1]); 21329 let attrEnd = attrName.sourceSpan.end; // Consume any quote 21330 21331 if (this._peek.type === 15 21332 /* TokenType.ATTR_QUOTE */ 21333 ) { 21334 this._advance(); 21335 } // Consume the attribute value 21336 21337 21338 let value = ''; 21339 const valueTokens = []; 21340 let valueStartSpan = undefined; 21341 let valueEnd = undefined; // NOTE: We need to use a new variable `nextTokenType` here to hide the actual type of 21342 // `_peek.type` from TS. Otherwise TS will narrow the type of `_peek.type` preventing it from 21343 // being able to consider `ATTR_VALUE_INTERPOLATION` as an option. This is because TS is not 21344 // able to see that `_advance()` will actually mutate `_peek`. 21345 21346 const nextTokenType = this._peek.type; 21347 21348 if (nextTokenType === 16 21349 /* TokenType.ATTR_VALUE_TEXT */ 21350 ) { 21351 valueStartSpan = this._peek.sourceSpan; 21352 valueEnd = this._peek.sourceSpan.end; 21353 21354 while (this._peek.type === 16 21355 /* TokenType.ATTR_VALUE_TEXT */ 21356 || this._peek.type === 17 21357 /* TokenType.ATTR_VALUE_INTERPOLATION */ 21358 || this._peek.type === 9 21359 /* TokenType.ENCODED_ENTITY */ 21360 ) { 21361 const valueToken = this._advance(); 21362 21363 valueTokens.push(valueToken); 21364 21365 if (valueToken.type === 17 21366 /* TokenType.ATTR_VALUE_INTERPOLATION */ 21367 ) { 21368 // For backward compatibility we decode HTML entities that appear in interpolation 21369 // expressions. This is arguably a bug, but it could be a considerable breaking change to 21370 // fix it. It should be addressed in a larger project to refactor the entire parser/lexer 21371 // chain after View Engine has been removed. 21372 value += valueToken.parts.join('').replace(/&([^;]+);/g, decodeEntity); 21373 } else if (valueToken.type === 9 21374 /* TokenType.ENCODED_ENTITY */ 21375 ) { 21376 value += valueToken.parts[0]; 21377 } else { 21378 value += valueToken.parts.join(''); 21379 } 21380 21381 valueEnd = attrEnd = valueToken.sourceSpan.end; 21382 } 21383 } // Consume any quote 21384 21385 21386 if (this._peek.type === 15 21387 /* TokenType.ATTR_QUOTE */ 21388 ) { 21389 const quoteToken = this._advance(); 21390 21391 attrEnd = quoteToken.sourceSpan.end; 21392 } 21393 21394 const valueSpan = valueStartSpan && valueEnd && new ParseSourceSpan(valueStartSpan.start, valueEnd, valueStartSpan.fullStart); 21395 return new Attribute(fullName, value, new ParseSourceSpan(attrName.sourceSpan.start, attrEnd, attrName.sourceSpan.fullStart), attrName.sourceSpan, valueSpan, valueTokens.length > 0 ? valueTokens : undefined, undefined); 21396 } 21397 21398 _getParentElement() { 21399 return this._elementStack.length > 0 ? this._elementStack[this._elementStack.length - 1] : null; 21400 } 21401 21402 _addToParent(node) { 21403 const parent = this._getParentElement(); 21404 21405 if (parent != null) { 21406 parent.children.push(node); 21407 } else { 21408 this.rootNodes.push(node); 21409 } 21410 } 21411 21412 _getElementFullName(prefix, localName, parentElement) { 21413 if (prefix === '') { 21414 prefix = this.getTagDefinition(localName).implicitNamespacePrefix || ''; 21415 21416 if (prefix === '' && parentElement != null) { 21417 const parentTagName = splitNsName(parentElement.name)[1]; 21418 const parentTagDefinition = this.getTagDefinition(parentTagName); 21419 21420 if (!parentTagDefinition.preventNamespaceInheritance) { 21421 prefix = getNsPrefix(parentElement.name); 21422 } 21423 } 21424 } 21425 21426 return mergeNsAndName(prefix, localName); 21427 } 21428 21429} 21430 21431function lastOnStack(stack, element) { 21432 return stack.length > 0 && stack[stack.length - 1] === element; 21433} 21434/** 21435 * Decode the `entity` string, which we believe is the contents of an HTML entity. 21436 * 21437 * If the string is not actually a valid/known entity then just return the original `match` string. 21438 */ 21439 21440 21441function decodeEntity(match, entity) { 21442 if (NAMED_ENTITIES[entity] !== undefined) { 21443 return NAMED_ENTITIES[entity] || match; 21444 } 21445 21446 if (/^#x[a-f0-9]+$/i.test(entity)) { 21447 return String.fromCodePoint(parseInt(entity.slice(2), 16)); 21448 } 21449 21450 if (/^#\d+$/.test(entity)) { 21451 return String.fromCodePoint(parseInt(entity.slice(1), 10)); 21452 } 21453 21454 return match; 21455} 21456/** 21457 * @license 21458 * Copyright Google LLC All Rights Reserved. 21459 * 21460 * Use of this source code is governed by an MIT-style license that can be 21461 * found in the LICENSE file at https://angular.io/license 21462 */ 21463 21464 21465class HtmlParser extends Parser { 21466 constructor() { 21467 super(getHtmlTagDefinition); 21468 } 21469 21470 parse(source, url, options) { 21471 return super.parse(source, url, options); 21472 } 21473 21474} 21475/** 21476 * @license 21477 * Copyright Google LLC All Rights Reserved. 21478 * 21479 * Use of this source code is governed by an MIT-style license that can be 21480 * found in the LICENSE file at https://angular.io/license 21481 */ 21482 21483
21484const PRESERVE_WS_ATTR_NAME = 'ngPreserveWhitespaces'; 21485const SKIP_WS_TRIM_TAGS = new Set(['pre', 'template', 'textarea', 'script', 'style']); // Equivalent to \s with \u00a0 (non-breaking space) excluded. 21486// Based on https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/RegExp 21487 21488const WS_CHARS = ' \f\n\r\t\v\u1680\u180e\u2000-\u200a\u2028\u2029\u202f\u205f\u3000\ufeff'; 21489const NO_WS_REGEXP = new RegExp(`[^${WS_CHARS}]`); 21490const WS_REPLACE_REGEXP = new RegExp(`[${WS_CHARS}]{2,}`, 'g'); 21491 21492function hasPreserveWhitespacesAttr(attrs) { 21493 return attrs.some(attr => attr.name === PRESERVE_WS_ATTR_NAME); 21494} 21495/** 21496 * Angular Dart introduced &ngsp; as a placeholder for non-removable space, see: 21497 * https://github.com/dart-lang/angular/blob/0bb611387d29d65b5af7f9d2515ab571fd3fbee4/_tests/test/compiler/preserve_whitespace_test.dart#L25-L32 21498 * In Angular Dart &ngsp; is converted to the 0xE500 PUA (Private Use Areas) unicode character 21499 * and later on replaced by a space. We are re-implementing the same idea here. 21500 */ 21501 21502 21503function replaceNgsp(value) { 21504 // lexer is replacing the &ngsp; pseudo-entity with NGSP_UNICODE 21505 return value.replace(new RegExp(NGSP_UNICODE, 'g'), ' '); 21506} 21507/** 21508 * This visitor can walk HTML parse tree and remove / trim text nodes using the following rules: 21509 * - consider spaces, tabs and new lines as whitespace characters; 21510 * - drop text nodes consisting of whitespace characters only; 21511 * - for all other text nodes replace consecutive whitespace characters with one space; 21512 * - convert &ngsp; pseudo-entity to a single space; 21513 * 21514 * Removal and trimming of whitespaces have positive performance impact (less code to generate 21515 * while compiling templates, faster view creation). At the same time it can be "destructive" 21516 * in some cases (whitespaces can influence layout). Because of the potential of breaking layout 21517 * this visitor is not activated by default in Angular 5 and people need to explicitly opt-in for 21518 * whitespace removal. The default option for whitespace removal will be revisited in Angular 6 21519 * and might be changed to "on" by default. 21520 */ 21521 21522 21523class WhitespaceVisitor { 21524 visitElement(element, context) { 21525 if (SKIP_WS_TRIM_TAGS.has(element.name) || hasPreserveWhitespacesAttr(element.attrs)) { 21526 // don't descent into elements where we need to preserve whitespaces 21527 // but still visit all attributes to eliminate one used as a market to preserve WS 21528 return new Element(element.name, visitAll(this, element.attrs), element.children, element.sourceSpan, element.startSourceSpan, element.endSourceSpan, element.i18n); 21529 } 21530 21531 return new Element(element.name, element.attrs, visitAllWithSiblings(this, element.children), element.sourceSpan, element.startSourceSpan, element.endSourceSpan, element.i18n); 21532 } 21533 21534 visitAttribute(attribute, context) { 21535 return attribute.name !== PRESERVE_WS_ATTR_NAME ? attribute : null; 21536 } 21537 21538 visitText(text, context) { 21539 const isNotBlank = text.value.match(NO_WS_REGEXP); 21540 const hasExpansionSibling = context && (context.prev instanceof Expansion || context.next instanceof Expansion); 21541 21542 if (isNotBlank || hasExpansionSibling) { 21543 // Process the whitespace in the tokens of this Text node 21544 const tokens = text.tokens.map(token => token.type === 5 21545 /* TokenType.TEXT */ 21546 ? createWhitespaceProcessedTextToken(token) : token); // Process the whitespace of the value of this Text node 21547 21548 const value = processWhitespace(text.value); 21549 return new Text(value, text.sourceSpan, tokens, text.i18n); 21550 } 21551 21552 return null; 21553 } 21554 21555 visitComment(comment, context) { 21556 return comment; 21557 } 21558 21559 visitExpansion(expansion, context) { 21560 return expansion; 21561 } 21562 21563 visitExpansionCase(expansionCase, context) { 21564 return expansionCase; 21565 } 21566 21567} 21568 21569function createWhitespaceProcessedTextToken({ 21570 type, 21571 parts, 21572 sourceSpan 21573}) { 21574 return { 21575 type, 21576 parts: [processWhitespace(parts[0])], 21577 sourceSpan 21578 }; 21579} 21580 21581function processWhitespace(text) { 21582 return replaceNgsp(text).replace(WS_REPLACE_REGEXP, ' '); 21583} 21584 21585function removeWhitespaces(htmlAstWithErrors) { 21586 return new ParseTreeResult(visitAll(new WhitespaceVisitor(), htmlAstWithErrors.rootNodes), htmlAstWithErrors.errors); 21587} 21588 21589function visitAllWithSiblings(visitor, nodes) { 21590 const result = [];
21591 nodes.forEach((ast, i) => { 21592 const context = { 21593 prev: nodes[i - 1], 21594 next: nodes[i + 1] 21595 }; 21596 const astResult = ast.visit(visitor, context); 21597 21598 if (astResult) { 21599 result.push(astResult); 21600 } 21601 }); 21602 return result; 21603} 21604/** 21605 * @license 21606 * Copyright Google LLC All Rights Reserved. 21607 * 21608 * Use of this source code is governed by an MIT-style license that can be 21609 * found in the LICENSE file at https://angular.io/license 21610 */ 21611 21612 21613function mapEntry(key, value) { 21614 return { 21615 key, 21616 value, 21617 quoted: false 21618 }; 21619} 21620 21621function mapLiteral(obj, quoted = false) { 21622 return literalMap(Object.keys(obj).map(key => ({ 21623 key, 21624 quoted, 21625 value: obj[key] 21626 }))); 21627} 21628/** 21629 * @license 21630 * Copyright Google LLC All Rights Reserved. 21631 * 21632 * Use of this source code is governed by an MIT-style license that can be 21633 * found in the LICENSE file at https://angular.io/license 21634 */ 21635 21636 21637class ElementSchemaRegistry {} 21638/** 21639 * @license 21640 * Copyright Google LLC All Rights Reserved. 21641 * 21642 * Use of this source code is governed by an MIT-style license that can be 21643 * found in the LICENSE file at https://angular.io/license 21644 */ 21645 21646 21647const EVENT = 'event'; 21648const BOOLEAN = 'boolean'; 21649const NUMBER = 'number'; 21650const STRING = 'string'; 21651const OBJECT = 'object'; 21652/** 21653 * This array represents the DOM schema. It encodes inheritance, properties, and events. 21654 * 21655 * ## Overview 21656 * 21657 * Each line represents one kind of element. The `element_inheritance` and properties are joined 21658 * using `element_inheritance|properties` syntax. 21659 * 21660 * ## Element Inheritance 21661 * 21662 * The `element_inheritance` can be further subdivided as `element1,element2,...^parentElement`. 21663 * Here the individual elements are separated by `,` (commas). Every element in the list 21664 * has identical properties. 21665 * 21666 * An `element` may inherit additional properties from `parentElement` If no `^parentElement` is 21667 * specified then `""` (blank) element is assumed. 21668 * 21669 * NOTE: The blank element inherits from root `[Element]` element, the super element of all 21670 * elements. 21671 * 21672 * NOTE an element prefix such as `:svg:` has no special meaning to the schema. 21673 * 21674 * ## Properties 21675 * 21676 * Each element has a set of properties separated by `,` (commas). Each property can be prefixed 21677 * by a special character designating its type: 21678 * 21679 * - (no prefix): property is a string. 21680 * - `*`: property represents an event. 21681 * - `!`: property is a boolean. 21682 * - `#`: property is a number. 21683 * - `%`: property is an object. 21684 * 21685 * ## Query 21686 * 21687 * The class creates an internal squas representation which allows to easily answer the query of 21688 * if a given property exist on a given element. 21689 * 21690 * NOTE: We don't yet support querying for types or events. 21691 * NOTE: This schema is auto extracted from `schema_extractor.ts` located in the test folder, 21692 * see dom_element_schema_registry_spec.ts 21693 */ 21694// ================================================================================================= 21695// ================================================================================================= 21696// =========== S T O P - S T O P - S T O P - S T O P - S T O P - S T O P =========== 21697// ================================================================================================= 21698// ================================================================================================= 21699// 21700// DO NOT EDIT THIS DOM SCHEMA WITHOUT A SECURITY REVIEW! 21701// 21702// Newly added properties must be security reviewed and assigned an appropriate SecurityContext in 21703// dom_security_schema.ts. Reach out to mprobst & rjamet for details. 21704// 21705// ================================================================================================= 21706 21707const SCHEMA = ['[Element]|textContent,%classList,className,id,innerHTML,*beforecopy,*beforecut,*beforepaste,*copy,*cut,*paste,*search,*selectstart,*webkitfullscreenchange,*webkitfullscreenerror,*w
21707heel,outerHTML,#scrollLeft,#scrollTop,slot' + 21708/* added manually to avoid breaking changes */ 21709',*message,*mozfullscreenchange,*mozfullscreenerror,*mozpointerlockchange,*mozpointerlockerror,*webglcontextcreationerror,*webglcontextlost,*webglcontextrestored', '[HTMLElement]^[Element]|accessKey,contentEditable,dir,!draggable,!hidden,innerText,lang,*abort,*auxclick,*blur,*cancel,*canplay,*canplaythrough,*change,*click,*close,*contextmenu,*cuechange,*dblclick,*drag,*dragend,*dragenter,*dragleave,*dragover,*dragstart,*drop,*durationchange,*emptied,*ended,*error,*focus,*gotpointercapture,*input,*invalid,*keydown,*keypress,*keyup,*load,*loadeddata,*loadedmetadata,*loadstart,*lostpointercapture,*mousedown,*mouseenter,*mouseleave,*mousemove,*mouseout,*mouseover,*mouseup,*mousewheel,*pause,*play,*playing,*pointercancel,*pointerdown,*pointerenter,*pointerleave,*pointermove,*pointerout,*pointerover,*pointerup,*progress,*ratechange,*reset,*resize,*scroll,*seeked,*seeking,*select,*show,*stalled,*submit,*suspend,*timeupdate,*toggle,*volumechange,*waiting,outerText,!spellcheck,%style,#tabIndex,title,!translate', 'abbr,address,article,aside,b,bdi,bdo,cite,code,dd,dfn,dt,em,figcaption,figure,footer,header,i,kbd,main,mark,nav,noscript,rb,rp,rt,rtc,ruby,s,samp,section,small,strong,sub,sup,u,var,wbr^[HTMLElement]|accessKey,contentEditable,dir,!draggable,!hidden,innerText,lang,*abort,*auxclick,*blur,*cancel,*canplay,*canplaythrough,*change,*click,*close,*contextmenu,*cuechange,*dblclick,*drag,*dragend,*dragenter,*dragleave,*dragover,*dragstart,*drop,*durationchange,*emptied,*ended,*error,*focus,*gotpointercapture,*input,*invalid,*keydown,*keypress,*keyup,*load,*loadeddata,*loadedmetadata,*loadstart,*lostpointercapture,*mousedown,*mouseenter,*mouseleave,*mousemove,*mouseout,*mouseover,*mouseup,*mousewheel,*pause,*play,*playing,*pointercancel,*pointerdown,*pointerenter,*pointerleave,*pointermove,*pointerout,*pointerover,*pointerup,*progress,*ratechange,*reset,*resize,*scroll,*seeked,*seeking,*select,*show,*stalled,*submit,*suspend,*timeupdate,*toggle,*volumechange,*waiting,outerText,!spellcheck,%style,#tabIndex,title,!translate', 'media^[HTMLElement]|!autoplay,!controls,%controlsList,%crossOrigin,#currentTime,!defaultMuted,#defaultPlaybackRate,!disableRemotePlayback,!loop,!muted,*encrypted,*waitingforkey,#playbackRate,preload,src,%srcObject,#volume', ':svg:^[HTMLElement]|*abort,*auxclick,*blur,*cancel,*canplay,*canplaythrough,*change,*click,*close,*contextmenu,*cuechange,*dblclick,*drag,*dragend,*dragenter,*dragleave,*dragover,*dragstart,*drop,*durationchange,*emptied,*ended,*error,*focus,*gotpointercapture,*input,*invalid,*keydown,*keypress,*keyup,*load,*loadeddata,*loadedmetadata,*loadstart,*lostpointercapture,*mousedown,*mouseenter,*mouseleave,*mousemove,*mouseout,*mouseover,*mouseup,*mousewheel,*pause,*play,*playing,*pointercancel,*pointerdown,*pointerenter,*pointerleave,*pointermove,*pointerout,*pointerover,*pointerup,*progress,*ratechange,*reset,*resize,*scroll,*seeked,*seeking,*select,*show,*stalled,*submit,*suspend,*timeupdate,*toggle,*volumechange,*waiting,%style,#tabIndex', ':svg:graphics^:svg:|', ':svg:animation^:svg:|*begin,*end,*repeat', ':svg:geometry^:svg:|', ':svg:componentTransferFunction^:svg:|', ':svg:gradient^:svg:|', ':svg:textContent^:svg:graphics|', ':svg:textPositioning^:svg:textContent|', 'a^[HTMLElement]|charset,coords,download,hash,host,hostname,href,hreflang,name,password,pathname,ping,port,protocol,referrerPolicy,rel,rev,search,shape,target,text,type,username', 'area^[HTMLElement]|alt,coords,download,hash,host,hostname,href,!noHref,password,pathname,ping,port,protocol,referrerPolicy,rel,search,shape,target,username', 'audio^media|', 'br^[HTMLElement]|clear', 'base^[HTMLElement]|href,target', 'body^[HTMLElement]|aLink,background,bgColor,link,*beforeunload,*blur,*error,*focus,*hashchange,*languagechange,*load,*message,*offline,*online,*pagehide,*pageshow,*popstate,*rejectionhandled,*resize,*scroll,*storage,*unhandledrejection,*unload,text,vLink', 'button^[HTMLElement]|!autofocus,!disabled,formAction,formEnctype,formMethod,!formNoValidate,formTarget,name,type,value', 'canvas^[HTMLElement]|#height,#width', 'content^[HTMLElement]|select', 'dl^[HTMLElement]|!compact', 'datalist^[HTMLElement]|', 'details^[HTMLElement]|!open', 'dialog^[HTMLElement]|!open,returnValue', 'dir^[HTMLElement]|!compact', 'div^[HTMLElement]|align', 'embed^[HTMLElement]|align,height,name,src,type,width', 'fieldset^[HTMLElement]|!disabled,name', 'font^[HTMLElement]|color,face,size', 'form^[HTMLElement]|acceptCharset,action,autocomplete,encoding,enctype,method,name,!noValidate,target', 'frame^[HTMLElement]|frameBorder,longDesc,marginHeight,marginWidth,name,!noResize,scrolling,src', 'frameset^[HTMLElement]|cols,*beforeunload,*blur,*error,*focus,*hashchange,*languagechange,*load,*message,*offline,*online,*pagehide,*pageshow,*popstate,*rejectionhandled,*resize,*scroll,*storage,*unhandledrejection,*unload,rows', 'hr^[HTMLElement]|align,color,!noShade,size,width', 'head^[HTMLElement]|', 'h1,h2,h3,h4,h5,h6^[HTMLElement]|align', 'html^[HTMLElement]|version', 'iframe^[HTMLElement]|align,!allowFullscreen,frameBorder,height,longDesc,marginHeight,marginWidth,name,referrerPolicy,%sandbox,scrolling,src,srcdoc,width', 'img^[HTMLElement]|align,alt,border,%crossOrigin,#height,#hspace,!isMap,longDesc,lowsrc,name,referrerPolicy,sizes,src,srcset,useMap,#vspace,#width', 'input^[HTMLElement]|accept,align,alt,autocapitalize,autocomplete,!autofocus,!checked,!defaultChecked,defaultValue,dirName,!disabled,%files,formAction,formEnctype,formMethod,!formNoValidate,formTarget,#height,!incremental,!indeterminate,max,#maxLength,min,#minLength,!multiple,name,pattern,placeholder,!readOnly,!required,selectionDirection,#selectionEnd,#selectionStart,#size,src,step,type,useMap,value,%valueAsDate,#valueAsNumber,#width', 'li^[HTMLElement]|type,#value', 'label^[HTMLElement]|htmlFor', 'legend^[HTMLElement]|align', 'link^[HTMLElement]|as,charset,%crossOrigin,!disabled,href,hreflang,integrity,media,referrerPolicy,rel,%relList,rev,%sizes,target,type', 'map^[HTMLElement]|name', 'marquee^[HTMLElement]|behavior,bgColor,direction,height,#hspace,#loop,#scrollAmount,#scrollDelay,!trueSpeed,#vspace,width', 'menu^[HTMLElement]|!compact', 'meta^[HTMLElement]|content,httpEquiv,name,scheme', 'meter^[HTMLElement]|#high,#low,#max,#min,#optimum,#value', 'ins,del^[HTMLElement]|cite,dateTime', 'ol^[HTMLElement]|!compact,!reversed,#start,type', 'object^[HTMLElement]|align,archive,border,code,codeBase,codeType,data,!declare,height,#hspace,name,standby,type,useMap,#vspace,width', 'optgroup^[HTMLElement]|!disabled,label', 'option^[HTMLElement]|!defaultSelected,!disabled,label,!selected,text,value', 'output^[HTMLElement]|defaultValue,%htmlFor,name,value', 'p^[HTMLElement]|align', 'param^[HTMLElement]|name,type,value,valueType', 'picture^[HTMLElement]|', 'pre^[HTMLElement]|#width', 'progress^[HTMLElement]|#max,#value', 'q,blockquote,cite^[HTMLElement]|', 'script^[HTMLElement]|!async,charset,%crossOrigin,!defer,event,htmlFor,integrity,src,text,type', 'select^[HTMLElement]|autocomplete,!autofocus,!disabled,#length,!multiple,name,!required,#selectedIndex,#size,value', 'shadow^[HTMLElement]|', 'slot^[HTMLElement]|name', 'source^[HTMLElement]|media,sizes,src,srcset,type', 'span^[HTMLElement]|', 'style^[HTMLElement]|!disabled,media,type', 'caption^[HTMLElement]|align', 'th,td^[HTMLElement]|abbr,align,axis,bgColor,ch,chOff,#colSpan,headers,height,!noWrap,#rowSpan,scope,vAlign,width', 'col,colgroup^[HTMLElement]|align,ch,chOff,#span,vAlign,width', 'table^[HTMLElement]|align,bgColor,border,%caption,cellPadding,cellSpacing,frame,rules,summary,%tFoot,%tHead,width', 'tr^[HTMLElement]|align,bgColor,ch,chOff,vAlign', 'tfoot,thead,tbody^[HTMLElement]|align,ch,chOff,vAlign', 'template^[HTMLElement]|', 'textarea^[HTMLElement]|autocapitalize,autocomplete,!autofocus,#cols,defaultValue,dirName,!disabled,#maxLength,#minLength,name,placeholder,!readOnly,!required,#rows,selectionDirection,#selectionEnd,#selectionStart,value,wrap', 'title^[HTMLElement]|text', 'track^[HTMLElement]|!default,kind,label,src,srclang', 'ul^[HTMLElement]|!compact,type', 'unknown^[HTMLElement]|', 'video^media|#height,poster,#width', ':svg:a^:svg:graphics|', ':svg:animate^:svg:animation|', ':svg:animateMotion^:svg:animation|', ':svg:animateTransform^:svg:animation|', ':svg:circle^:svg:geometry|', ':svg:clipPath^:svg:graphics|', ':svg:defs^:svg:graphics|', ':svg:desc^:svg:|', ':svg:discard^:svg:|', ':svg:ellipse^:svg:geometry|', ':svg:feBlend^:svg:|', ':svg:feColorMatrix^:svg:|', ':svg:feComponentTransfer^:svg:|', ':svg:feComposite^:svg:|', ':svg:feConvolveMatrix^:svg:|', ':svg:feDiffuseLighting^:svg:|', ':svg:feDisplacementMap^:svg:|', ':svg:feDistantLight^:svg:|', ':svg:feDropShadow^:svg:|', ':svg:feFlood^:svg:|', ':svg:feFuncA^:svg:componentTransferFunction|', ':svg:feFuncB^:svg:componentTransferFunction|', ':svg:feFuncG^:svg:componentTransferFunction|', ':svg:feFuncR^:svg:componentTransferFunction|', ':svg:feGaussianBlur^:svg:|', ':svg:feImage^:svg:|', ':svg:feMerge^:svg:|', ':svg:feMergeNode^:svg:|', ':svg:feMorphology^:svg:|', ':svg:feOffset^:svg:|', ':svg:fePointLight^:svg:|', ':svg:feSpecularLighting^:svg:|', ':svg:feSpotLight^:svg:|', ':svg:feTile^:svg:|', ':svg:feTurbulence^:svg:|', ':svg:filter^:svg:|', ':svg:foreignObject^:svg:graphics|', ':svg:g^:svg:graphics|', ':svg:image^:svg:graphics|', ':svg:line^:svg:geometry|', ':svg:linearGradient^:svg:gradient|', ':svg:mpath^:svg:|', ':svg:marker^:svg:|', ':svg:mask^:svg:|', ':svg:metadata^:svg:|', ':svg:path^:svg:geometry|', ':svg:pattern^:svg:|', ':svg:polygon^:svg:geometry|', ':svg:polyline^:svg:geometry|', ':svg:radialGradient^:svg:gradient|', ':svg:rect^:svg:geometry|', ':svg:svg^:svg:graphics|#currentScale,#zoomAndPan', ':svg:script^:svg:|type', ':svg:set^:svg:animation|', ':svg:stop^:svg:|', ':svg:style^:svg:|!disabled,media,title,type', ':svg:switch^:svg:graphics|', ':svg:symbol^:svg:|', ':svg:tspan^:svg:textPositioning|', ':svg:text^:svg:textPositioning|', ':svg:textPath^:svg:textContent|', ':svg:title^:svg:|', ':svg:use^:svg:graphics|', ':svg:view^:svg:|#zoomAndPan', 'data^[HTMLElement]|value', 'keygen^[HTMLElement]|!autofocus,challenge,!disabled,form,keytype,name', 'menuitem^[HTMLElement]|type,label,icon,!disabled,!checked,radiogroup,!default', 'summary^[HTMLElement]|', 'time^[HTMLElement]|dateTime', ':svg:cursor^:svg:|']; 21710 21711const _ATTR_TO_PROP = new Map(Object.entries({ 21712 'class': 'className', 21713 'for': 'htmlFor', 21714 'formaction': 'formAction', 21715 'innerHtml': 'innerHTML', 21716 'readonly': 'readOnly', 21717 'tabindex': 'tabIndex' 21718})); // Invert _ATTR_TO_PROP. 21719 21720 21721const _PROP_TO_ATTR = Array.from(_ATTR_TO_PROP).reduce((inverted, [propertyName, attributeName]) => { 21722 inverted.set(propertyName, attributeName); 21723 return inverted; 21724}, new Map()); 21725
21726class DomElementSchemaRegistry extends ElementSchemaRegistry { 21727 constructor() { 21728 super(); 21729 this._schema = new Map(); // We don't allow binding to events for security reasons. Allowing event bindings would almost 21730 // certainly introduce bad XSS vulnerabilities. Instead, we store events in a separate schema. 21731 21732 this._eventSchema = new Map(); 21733 SCHEMA.forEach(encodedType => { 21734 const type = new Map(); 21735 const events = new Set(); 21736 const [strType, strProperties] = encodedType.split('|'); 21737 const properties = strProperties.split(','); 21738 const [typeNames, superName] = strType.split('^'); 21739 typeNames.split(',').forEach(tag => { 21740 this._schema.set(tag.toLowerCase(), type); 21741 21742 this._eventSchema.set(tag.toLowerCase(), events); 21743 }); 21744 21745 const superType = superName && this._schema.get(superName.toLowerCase()); 21746 21747 if (superType) { 21748 for (const [prop, value] of superType) { 21749 type.set(prop, value); 21750 } 21751 21752 for (const superEvent of this._eventSchema.get(superName.toLowerCase())) { 21753 events.add(superEvent); 21754 } 21755 } 21756 21757 properties.forEach(property => { 21758 if (property.length > 0) { 21759 switch (property[0]) { 21760 case '*': 21761 events.add(property.substring(1)); 21762 break; 21763 21764 case '!': 21765 type.set(property.substring(1), BOOLEAN); 21766 break; 21767 21768 case '#': 21769 type.set(property.substring(1), NUMBER); 21770 break; 21771 21772 case '%': 21773 type.set(property.substring(1), OBJECT); 21774 break; 21775 21776 default: 21777 type.set(property, STRING); 21778 } 21779 } 21780 }); 21781 }); 21782 } 21783 21784 hasProperty(tagName, propName, schemaMetas) { 21785 if (schemaMetas.some(schema => schema.name === NO_ERRORS_SCHEMA.name)) { 21786 return true; 21787 } 21788 21789 if (tagName.indexOf('-') > -1) { 21790 if (isNgContainer(tagName) || isNgContent(tagName)) { 21791 return false; 21792 } 21793 21794 if (schemaMetas.some(schema => schema.name === CUSTOM_ELEMENTS_SCHEMA.name)) { 21795 // Can't tell now as we don't know which properties a custom element will get 21796 // once it is instantiated 21797 return true; 21798 } 21799 } 21800 21801 const elementProperties = this._schema.get(tagName.toLowerCase()) || this._schema.get('unknown'); 21802 21803 return elementProperties.has(propName); 21804 } 21805 21806 hasElement(tagName, schemaMetas) { 21807 if (schemaMetas.some(schema => schema.name === NO_ERRORS_SCHEMA.name)) { 21808 return true; 21809 } 21810 21811 if (tagName.indexOf('-') > -1) { 21812 if (isNgContainer(tagName) || isNgContent(tagName)) { 21813 return true; 21814 } 21815 21816 if (schemaMetas.some(schema => schema.name === CUSTOM_ELEMENTS_SCHEMA.name)) { 21817 // Allow any custom elements 21818 return true; 21819 } 21820 } 21821 21822 return this._schema.has(tagName.toLowerCase()); 21823 } 21824 /** 21825 * securityContext returns the security context for the given property on the given DOM tag. 21826 * 21827 * Tag and property name are statically known and cannot change at runtime, i.e. it is not 21828 * possible to bind a value into a changing attribute or tag name. 21829 * 21830 * The filtering is based on a list of allowed tags|attributes. All attributes in the schema 21831 * above are assumed to have the 'NONE' security context, i.e. that they are safe inert 21832 * string values. Only specific well known attack vectors are assigned their appropriate context. 21833 */ 21834 21835 21836 securityContext(tagName, propName, isAttribute) { 21837 if (isAttribute) { 21838 // NB: For security purposes, use the mapped property name, not the attribute name. 21839 propName = this.getMappedPropName(propName); 21840 } // Make sure comparisons are case insensitive, so that case differences between attribute and 21841 // property names do not have a security impact. 21842 21843 21844 tagName = tagName.toLowerCase(); 21845 propName = propName.toLowerCase(); 21846 let ctx = SECURITY_SCHEMA()[tagName + '|' + propName]; 21847 21848 if (ctx) { 21849 return ctx; 21850 } 21851 21852 ctx = SECURITY_SCHEMA()['*|' + propName]; 21853 return ctx ? ctx : SecurityContext.NONE; 21854 } 21855 21856 getMappedPropName(propName) { 21857 return _ATTR_TO_PROP.get(propName) ?? propName; 21858 } 21859 21860 getDefaultComponentElementName() { 21861 return 'ng-component'; 21862 } 21863 21864 validateProperty(name) { 21865 if (name.toLowerCase().startsWith('on')) { 21866 const msg = `Binding to event property '${name}' is disallowed for security reasons, ` + `please use (${name.slice(2)})=...` + `\nIf '${name}' is a directive input, make sure the directive is imported by the` + ` current module.`; 21867 return { 21868 error: true, 21869 msg: msg 21870 }; 21871 } else { 21872 return { 21873 error: false 21874 }; 21875 } 21876 } 21877 21878 validateAttribute(name) { 21879 if (name.toLowerCase().startsWith('on')) { 21880 const msg = `Binding to event attribute '${name}' is disallowed for security reasons, ` + `please use (${name.slice(2)})=...`; 21881 return { 21882 error: true, 21883 msg: msg 21884 }; 21885 } else { 21886 return { 21887 error: false 21888 }; 21889 } 21890 } 21891 21892 allKnownElementNames() { 21893 return Array.from(this._schema.keys()); 21894 } 21895 21896 allKnownAttributesOfElement(tagName) { 21897 const elementProperties = this._schema.get(tagName.toLowerCase()) || this._schema.get('unknown'); // Convert properties to attributes. 21898 21899 21900 return Array.from(elementProperties.keys()).map(prop => _PROP_TO_ATTR.get(prop) ?? prop); 21901 } 21902 21903 allKnownEventsOfElement(tagName) { 21904 return Array.from(this._eventSchema.get(tagName.toLowerCase()) ?? []); 21905 } 21906 21907 normalizeAnimationStyleProperty(propName) { 21908 return dashCaseToCamelCase(propName); 21909 } 21910 21911 normalizeAnimationStyleValue(camelCaseProp, userProvidedProp, val) { 21912 let unit = ''; 21913 const strVal = val.toString().trim(); 21914 let errorMsg = null; 21915 21916 if (_isPixelDimensionStyle(camelCaseProp) && val !== 0 && val !== '0') { 21917 if (typeof val === 'number') { 21918 unit = 'px'; 21919 } else { 21920 const valAndSuffixMatch = val.match(/^[+-]?[\d\.]+([a-z]*)$/); 21921 21922 if (valAndSuffixMatch && valAndSuffixMatch[1].length == 0) { 21923 errorMsg = `Please provide a CSS unit value for ${userProvidedProp}:${val}`; 21924 } 21925 } 21926 } 21927 21928 return { 21929 error: errorMsg, 21930 value: strVal + unit 21931 }; 21932 } 21933 21934} 21935 21936function _isPixelDimensionStyle(prop) { 21937 switch (prop) { 21938 case 'width': 21939 case 'height': 21940 case 'minWidth': 21941 case 'minHeight': 21942 case 'maxWidth': 21943 case 'maxHeight': 21944 case 'left': 21945 case 'top': 21946 case 'bottom': 21947 case 'right': 21948 case 'fontSize': 21949 case 'outlineWidth': 21950 case 'outlineOffset': 21951 case 'paddingTop': 21952 case 'paddingLeft': 21953 case 'paddingBottom': 21954 case 'paddingRight': 21955 case 'marginTop': 21956 case 'marginLeft': 21957 case 'marginBottom': 21958 case 'marginRight': 21959 case 'borderRadius': 21960 case 'borderWidth': 21961 case 'borderTopWidth': 21962 case 'borderLeftWidth': 21963 case 'borderRightWidth': 21964 case 'borderBottomWidth': 21965 case 'textIndent': 21966 return true; 21967 21968 default: 21969 return false;
21970 } 21971} 21972/** 21973 * @license 21974 * Copyright Google LLC All Rights Reserved. 21975 * 21976 * Use of this source code is governed by an MIT-style license that can be 21977 * found in the LICENSE file at https://angular.io/license 21978 */ 21979 21980/** 21981 * Set of tagName|propertyName corresponding to Trusted Types sinks. Properties applying to all 21982 * tags use '*'. 21983 * 21984 * Extracted from, and should be kept in sync with 21985 * https://w3c.github.io/webappsec-trusted-types/dist/spec/#integrations 21986 */ 21987 21988 21989const TRUSTED_TYPES_SINKS = new Set([// NOTE: All strings in this set *must* be lowercase! 21990// TrustedHTML 21991'iframe|srcdoc', '*|innerhtml', '*|outerhtml', // NB: no TrustedScript here, as the corresponding tags are stripped by the compiler. 21992// TrustedScriptURL 21993'embed|src', 'object|codebase', 'object|data']); 21994/** 21995 * isTrustedTypesSink returns true if the given property on the given DOM tag is a Trusted Types 21996 * sink. In that case, use `ElementSchemaRegistry.securityContext` to determine which particular 21997 * Trusted Type is required for values passed to the sink: 21998 * - SecurityContext.HTML corresponds to TrustedHTML 21999 * - SecurityContext.RESOURCE_URL corresponds to TrustedScriptURL 22000 */ 22001 22002function isTrustedTypesSink(tagName, propName) { 22003 // Make sure comparisons are case insensitive, so that case differences between attribute and 22004 // property names do not have a security impact. 22005 tagName = tagName.toLowerCase(); 22006 propName = propName.toLowerCase(); 22007 return TRUSTED_TYPES_SINKS.has(tagName + '|' + propName) || TRUSTED_TYPES_SINKS.has('*|' + propName); 22008} 22009/** 22010 * @license 22011 * Copyright Google LLC All Rights Reserved. 22012 * 22013 * Use of this source code is governed by an MIT-style license that can be 22014 * found in the LICENSE file at https://angular.io/license 22015 */ 22016 22017 22018const PROPERTY_PARTS_SEPARATOR = '.'; 22019const ATTRIBUTE_PREFIX = 'attr'; 22020const CLASS_PREFIX = 'class'; 22021const STYLE_PREFIX = 'style'; 22022const TEMPLATE_ATTR_PREFIX$1 = '*'; 22023const ANIMATE_PROP_PREFIX = 'animate-'; 22024/** 22025 * Parses bindings in templates and in the directive host area. 22026 */ 22027 22028class BindingParser { 22029 constructor(_exprParser, _interpolationConfig, _schemaRegistry, errors) { 22030 this._exprParser = _exprParser; 22031 this._interpolationConfig = _interpolationConfig; 22032 this._schemaRegistry = _schemaRegistry; 22033 this.errors = errors; 22034 } 22035 22036 get interpolationConfig() { 22037 return this._interpolationConfig; 22038 } 22039 22040 createBoundHostProperties(properties, sourceSpan) { 22041 const boundProps = []; 22042 22043 for (const propName of Object.keys(properties)) { 22044 const expression = properties[propName]; 22045 22046 if (typeof expression === 'string') { 22047 this.parsePropertyBinding(propName, expression, true, sourceSpan, sourceSpan.start.offset, undefined, [], // Use the `sourceSpan` for `keySpan`. This isn't really accurate, but neither is the 22048 // sourceSpan, as it represents the sourceSpan of the host itself rather than the 22049 // source of the host binding (which doesn't exist in the template). Regardless, 22050 // neither of these values are used in Ivy but are only here to satisfy the function 22051 // signature. This should likely be refactored in the future so that `sourceSpan` 22052 // isn't being used inaccurately. 22053 boundProps, sourceSpan); 22054 } else { 22055 this._reportError(`Value of the host property binding "${propName}" needs to be a string representing an expression but got "${expression}" (${typeof expression})`, sourceSpan); 22056 } 22057 } 22058 22059 return boundProps; 22060 } 22061 22062 createDirectiveHostEventAsts(hostListeners, sourceSpan) { 22063 const targetEvents = []; 22064 22065 for (const propName of Object.keys(hostListeners)) { 22066 const expression = hostListeners[propName]; 22067 22068 if (typeof expression === 'string') { 22069 // Use the `sourceSpan` for `keySpan` and `handlerSpan`. This isn't really accurate, but 22070 // neither is the `sourceSpan`, as it represents the `sourceSpan` of the host itself 22071 // rather than the source of the host binding (which doesn't exist in the template). 22072 // Regardless, neither of these values are used in Ivy but are only here to satisfy the 22073 // function signature. This should likely be refactored
22073in the future so that `sourceSpan` 22074 // isn't being used inaccurately. 22075 this.parseEvent(propName, expression, 22076 /* isAssignmentEvent */ 22077 false, sourceSpan, sourceSpan, [], targetEvents, sourceSpan); 22078 } else { 22079 this._reportError(`Value of the host listener "${propName}" needs to be a string representing an expression but got "${expression}" (${typeof expression})`, sourceSpan); 22080 } 22081 } 22082 22083 return targetEvents; 22084 } 22085 22086 parseInterpolation(value, sourceSpan, interpolatedTokens) { 22087 const sourceInfo = sourceSpan.start.toString(); 22088 const absoluteOffset = sourceSpan.fullStart.offset; 22089 22090 try { 22091 const ast = this._exprParser.parseInterpolation(value, sourceInfo, absoluteOffset, interpolatedTokens, this._interpolationConfig); 22092 22093 if (ast) this._reportExpressionParserErrors(ast.errors, sourceSpan); 22094 return ast; 22095 } catch (e) { 22096 this._reportError(`${e}`, sourceSpan); 22097 22098 return this._exprParser.wrapLiteralPrimitive('ERROR', sourceInfo, absoluteOffset); 22099 } 22100 } 22101 /** 22102 * Similar to `parseInterpolation`, but treats the provided string as a single expression 22103 * element that would normally appear within the interpolation prefix and suffix (`{{` and `}}`). 22104 * This is used for parsing the switch expression in ICUs. 22105 */ 22106 22107 22108 parseInterpolationExpression(expression, sourceSpan) { 22109 const sourceInfo = sourceSpan.start.toString(); 22110 const absoluteOffset = sourceSpan.start.offset; 22111 22112 try { 22113 const ast = this._exprParser.parseInterpolationExpression(expression, sourceInfo, absoluteOffset); 22114 22115 if (ast) this._reportExpressionParserErrors(ast.errors, sourceSpan); 22116 return ast; 22117 } catch (e) { 22118 this._reportError(`${e}`, sourceSpan); 22119 22120 return this._exprParser.wrapLiteralPrimitive('ERROR', sourceInfo, absoluteOffset); 22121 } 22122 } 22123 /** 22124 * Parses the bindings in a microsyntax expression, and converts them to 22125 * `ParsedProperty` or `ParsedVariable`. 22126 * 22127 * @param tplKey template binding name 22128 * @param tplValue template binding value 22129 * @param sourceSpan span of template binding relative to entire the template 22130 * @param absoluteValueOffset start of the tplValue relative to the entire template 22131 * @param targetMatchableAttrs potential attributes to match in the template 22132 * @param targetProps target property bindings in the template 22133 * @param targetVars target variables in the template 22134 */ 22135 22136 22137 parseInlineTemplateBinding(tplKey, tplValue, sourceSpan, absoluteValueOffset, targetMatchableAttrs, targetProps, targetVars, isIvyAst) { 22138 const absoluteKeyOffset = sourceSpan.start.offset + TEMPLATE_ATTR_PREFIX$1.length; 22139 22140 const bindings = this._parseTemplateBindings(tplKey, tplValue, sourceSpan, absoluteKeyOffset, absoluteValueOffset); 22141 22142 for (const binding of bindings) { 22143 // sourceSpan is for the entire HTML attribute. bindingSpan is for a particular 22144 // binding within the microsyntax expression so it's more narrow than sourceSpan. 22145 const bindingSpan = moveParseSourceSpan(sourceSpan, binding.sourceSpan); 22146 const key = binding.key.source; 22147 const keySpan = moveParseSourceSpan(sourceSpan, binding.key.span); 22148 22149 if (binding instanceof VariableBinding) { 22150 const value = binding.value ? binding.value.source : '$implicit'; 22151 const valueSpan = binding.value ? moveParseSourceSpan(sourceSpan, binding.value.span) : undefined; 22152 targetVars.push(new ParsedVariable(key, value, bindingSpan, keySpan, valueSpan)); 22153 } else if (binding.value) { 22154 const srcSpan = isIvyAst ? bindingSpan : sourceSpan; 22155 const valueSpan = moveParseSourceSpan(sourceSpan, binding.value.ast.sourceSpan); 22156 22157 this._parsePropertyAst(key, binding.value, srcSpan, keySpan, valueSpan, targetMatchableAttrs, targetProps); 22158 } else { 22159 targetMatchableAttrs.push([key, '' 22160 /* value */ 22161 ]); // Since this is a literal attribute with no RHS, source span should be 22162 // just the key span. 22163 22164 this.parseLiteralAttr(key, null 22165 /* value */ 22166 , keySpan, absoluteValueOffset, undefined 22167 /* valueSpan */ 22168 , targetMatchableAttrs, targetProps, keySpan); 22169 } 22170 } 22171 } 22172 /** 22173 * Parses the bindings in a microsyntax expression, e.g. 22174 * ``` 22175 * <tag *tplKey="let value1 = prop; let value2 = localVar"> 22176 * ``` 22177 * 22178 * @param tplKey template binding name 22179 * @param tplValue template binding value 22180 * @param sourceSpan span of template binding relative to entire the template 22181 * @param absoluteKeyOffset start of the `tplKey` 22182 * @param absoluteValueOffset start of the `tplValue` 22183 */ 22184 22185 22186 _parseTemplateBindings(tplKey, tplValue, sourceSpan, absoluteKeyOffset, absoluteValueOffset) { 22187 const sourceInfo = sourceSpan.start.toString(); 22188 22189 try { 22190 const bindingsResult = this._exprParser.parseTemplateBindings(tplKey, tplValue, sourceInfo, absoluteKeyOffset, absoluteValueOffset); 22191 22192 this._reportExpressionParserErrors(bindingsResult.errors, sourceSpan); 22193
22194 bindingsResult.warnings.forEach(warning => { 22195 this._reportError(warning, sourceSpan, ParseErrorLevel.WARNING); 22196 }); 22197 return bindingsResult.templateBindings; 22198 } catch (e) { 22199 this._reportError(`${e}`, sourceSpan); 22200 22201 return []; 22202 } 22203 } 22204 22205 parseLiteralAttr(name, value, sourceSpan, absoluteOffset, valueSpan, targetMatchableAttrs, targetProps, keySpan) { 22206 if (isAnimationLabel(name)) { 22207 name = name.substring(1); 22208 22209 if (keySpan !== undefined) { 22210 keySpan = moveParseSourceSpan(keySpan, new AbsoluteSourceSpan(keySpan.start.offset + 1, keySpan.end.offset)); 22211 } 22212 22213 if (value) { 22214 this._reportError(`Assigning animation triggers via @prop="exp" attributes with an expression is invalid.` + ` Use property bindings (e.g. [@prop]="exp") or use an attribute without a value (e.g. @prop) instead.`, sourceSpan, ParseErrorLevel.ERROR); 22215 } 22216 22217 this._parseAnimation(name, value, sourceSpan, absoluteOffset, keySpan, valueSpan, targetMatchableAttrs, targetProps); 22218 } else { 22219 targetProps.push(new ParsedProperty(name, this._exprParser.wrapLiteralPrimitive(value, '', absoluteOffset), ParsedPropertyType.LITERAL_ATTR, sourceSpan, keySpan, valueSpan)); 22220 } 22221 } 22222 22223 parsePropertyBinding(name, expression, isHost, sourceSpan, absoluteOffset, valueSpan, targetMatchableAttrs, targetProps, keySpan) { 22224 if (name.length === 0) { 22225 this._reportError(`Property name is missing in binding`, sourceSpan); 22226 } 22227 22228 let isAnimationProp = false; 22229 22230 if (name.startsWith(ANIMATE_PROP_PREFIX)) { 22231 isAnimationProp = true; 22232 name = name.substring(ANIMATE_PROP_PREFIX.length); 22233 22234 if (keySpan !== undefined) { 22235 keySpan = moveParseSourceSpan(keySpan, new AbsoluteSourceSpan(keySpan.start.offset + ANIMATE_PROP_PREFIX.length, keySpan.end.offset)); 22236 } 22237 } else if (isAnimationLabel(name)) { 22238 isAnimationProp = true; 22239 name = name.substring(1); 22240 22241 if (keySpan !== undefined) { 22242 keySpan = moveParseSourceSpan(keySpan, new AbsoluteSourceSpan(keySpan.start.offset + 1, keySpan.end.offset)); 22243 } 22244 } 22245 22246 if (isAnimationProp) { 22247 this._parseAnimation(name, expression, sourceSpan, absoluteOffset, keySpan, valueSpan, targetMatchableAttrs, targetProps); 22248 } else { 22249 this._parsePropertyAst(name, this._parseBinding(expression, isHost, valueSpan || sourceSpan, absoluteOffset), sourceSpan, keySpan, valueSpan, targetMatchableAttrs, targetProps); 22250 } 22251 } 22252 22253 parsePropertyInterpolation(name, value, sourceSpan, valueSpan, targetMatchableAttrs, targetProps, keySpan, interpolatedTokens) { 22254 const expr = this.parseInterpolation(value, valueSpan || sourceSpan, interpolatedTokens); 22255 22256 if (expr) { 22257 this._parsePropertyAst(name, expr, sourceSpan, keySpan, valueSpan, targetMatchableAttrs, targetProps); 22258 22259 return true; 22260 } 22261 22262 return false; 22263 } 22264 22265 _parsePropertyAst(name, ast, sourceSpan, keySpan, valueSpan, targetMatchableAttrs, targetProps) { 22266 targetMatchableAttrs.push([name, ast.source]); 22267 targetProps.push(new ParsedProperty(name, ast, ParsedPropertyType.DEFAULT, sourceSpan, keySpan, valueSpan)); 22268 } 22269 22270 _parseAnimation(name, expression, sourceSpan, absoluteOffset, keySpan, valueSpan, targetMatchableAttrs, targetProps) { 22271 if (name.length === 0) { 22272 this._reportError('Animation trigger is missing', sourceSpan); 22273 } // This will occur when a @trigger is not paired with an expression. 22274 // For animations it is valid to not have an expression since */void 22275 // states will be applied by angular when the element is attached/detached 22276 22277 22278 const ast = this._parseBinding(expression || 'undefined', false, valueSpan || sourceSpan, absoluteOffset); 22279 22280 targetMatchableAttrs.push([name, ast.source]); 22281 targetProps.push(new ParsedProperty(name, ast, ParsedPropertyType.ANIMATION, sourceSpan, keySpan, valueSpan)); 22282 } 22283 22284 _parseBinding(value, isHostBinding, sourceSpan, absoluteOffset) { 22285 const sourceInfo = (sourceSpan && sourceSpan.start || '(unknown)').toString(); 22286 22287 try { 22288 const ast = isHostBinding ? this._exprParser.parseSimpleBinding(value, sourceInfo, absoluteOffset, this._interpolationConfig) : this._exprParser.parseBinding(value, sourceInfo, absoluteOffset, this._interpolationConfig); 22289 if (ast) this._reportExpressionParserErrors(ast.errors, sourceSpan); 22290 return ast; 22291 } catch (e) { 22292 this._reportError(`${e}`, sourceSpan); 22293 22294 return this._exprParser.wrapLiteralPrimitive('ERROR', sourceInfo, absoluteOffset); 22295 } 22296 } 22297 22298 createBoundElementProperty(elementSelector, boundProp, skipValidation = false, mapPropertyName = true) { 22299 if (boundProp.isAnimation) { 22300 return new BoundElementProperty(boundProp.name, 4 22301 /* BindingType.Animation */ 22302 , SecurityContext.NONE, boundProp.expression, null, boundProp.sourceSpan, boundProp.keySpan, boundProp.valueSpan); 22303 } 22304 22305 let unit = null; 22306 let bindingType = undefined; 22307 let boundPropertyName = null; 22308 const parts = boundProp.name.split(PROPERTY_PARTS_SEPARATOR); 22309 let securityContexts = undefined; // Check for special cases (prefix style, attr, class) 22310 22311 if (parts.length > 1) { 22312 if (parts[0] == ATTRIBUTE_PREFIX) { 22313 boundPropertyName = parts.slice(1).join(PROPERTY_PARTS_SEPARATOR); 22314 22315 if (!skipValidation) {
22316 this._validatePropertyOrAttributeName(boundPropertyName, boundProp.sourceSpan, true); 22317 } 22318 22319 securityContexts = calcPossibleSecurityContexts(this._schemaRegistry, elementSelector, boundPropertyName, true); 22320 const nsSeparatorIdx = boundPropertyName.indexOf(':'); 22321 22322 if (nsSeparatorIdx > -1) { 22323 const ns = boundPropertyName.substring(0, nsSeparatorIdx); 22324 const name = boundPropertyName.substring(nsSeparatorIdx + 1); 22325 boundPropertyName = mergeNsAndName(ns, name); 22326 } 22327 22328 bindingType = 1 22329 /* BindingType.Attribute */ 22330 ; 22331 } else if (parts[0] == CLASS_PREFIX) { 22332 boundPropertyName = parts[1]; 22333 bindingType = 2 22334 /* BindingType.Class */ 22335 ; 22336 securityContexts = [SecurityContext.NONE]; 22337 } else if (parts[0] == STYLE_PREFIX) { 22338 unit = parts.length > 2 ? parts[2] : null; 22339 boundPropertyName = parts[1]; 22340 bindingType = 3 22341 /* BindingType.Style */ 22342 ; 22343 securityContexts = [SecurityContext.STYLE]; 22344 } 22345 } // If not a special case, use the full property name 22346 22347 22348 if (boundPropertyName === null) { 22349 const mappedPropName = this._schemaRegistry.getMappedPropName(boundProp.name); 22350 22351 boundPropertyName = mapPropertyName ? mappedPropName : boundProp.name; 22352 securityContexts = calcPossibleSecurityContexts(this._schemaRegistry, elementSelector, mappedPropName, false); 22353 bindingType = 0 22354 /* BindingType.Property */ 22355 ; 22356 22357 if (!skipValidation) { 22358 this._validatePropertyOrAttributeName(mappedPropName, boundProp.sourceSpan, false); 22359 } 22360 } 22361 22362 return new BoundElementProperty(boundPropertyName, bindingType, securityContexts[0], boundProp.expression, unit, boundProp.sourceSpan, boundProp.keySpan, boundProp.valueSpan); 22363 } // TODO: keySpan should be required but was made optional to avoid changing VE parser. 22364 22365 22366 parseEvent(name, expression, isAssignmentEvent, sourceSpan, handlerSpan, targetMatchableAttrs, targetEvents, keySpan) { 22367 if (name.length === 0) { 22368 this._reportError(`Event name is missing in binding`, sourceSpan); 22369 } 22370 22371 if (isAnimationLabel(name)) { 22372 name = name.slice(1); 22373 22374 if (keySpan !== undefined) { 22375 keySpan = moveParseSourceSpan(keySpan, new AbsoluteSourceSpan(keySpan.start.offset + 1, keySpan.end.offset)); 22376 } 22377 22378 this._parseAnimationEvent(name, expression, isAssignmentEvent, sourceSpan, handlerSpan, targetEvents, keySpan); 22379 } else { 22380 this._parseRegularEvent(name, expression, isAssignmentEvent, sourceSpan, handlerSpan, targetMatchableAttrs, targetEvents, keySpan); 22381 } 22382 } 22383 22384 calcPossibleSecurityContexts(selector, propName, isAttribute) { 22385 const prop = this._schemaRegistry.getMappedPropName(propName); 22386 22387 return calcPossibleSecurityContexts(this._schemaRegistry, selector, prop, isAttribute); 22388 } 22389 22390 _parseAnimationEvent(name, expression, isAssignmentEvent, sourceSpan, handlerSpan, targetEvents, keySpan) { 22391 const matches = splitAtPeriod(name, [name, '']); 22392 const eventName = matches[0]; 22393 const phase = matches[1].toLowerCase(); 22394 22395 const ast = this._parseAction(expression, isAssignmentEvent, handlerSpan); 22396 22397 targetEvents.push(new ParsedEvent(eventName, phase, 1 22398 /* ParsedEventType.Animation */ 22399 , ast, sourceSpan, handlerSpan, keySpan)); 22400 22401 if (eventName.length === 0) { 22402 this._reportError(`Animation event name is missing in binding`, sourceSpan); 22403 } 22404 22405 if (phase) { 22406 if (phase !== 'start' && phase !== 'done') { 22407 this._reportError(`The provided animation output phase value "${phase}" for "@${eventName}" is not supported (use start or done)`, sourceSpan); 22408 } 22409 } else { 22410 this._reportError(`The animation trigger output event (@${eventName}) is missing its phase value name (start or done are currently supported)`, sourceSpan); 22411 } 22412 } 22413 22414 _parseRegularEvent(name, expression, isAssignmentEvent, sourceSpan, handlerSpan, targetMatchableAttrs, targetEvents, keySpan) { 22415 // long format: 'target: eventName' 22416 const [target, eventName] = splitAtColon(name, [null, name]); 22417 22418 const ast = this._parseAction(expression, isAssignmentEvent, handlerSpan); 22419 22420 targetMatchableAttrs.push([name, ast.source]); 22421 targetEvents.push(new ParsedEvent(eventName, target, 0 22422 /* ParsedEventType.Regular */ 22423 , ast, sourceSpan, handlerSpan, keySpan)); // Don't detect directives for event names for now, 22424 // so don't add the event name to the matchableAttrs 22425 } 22426
22427 _parseAction(value, isAssignmentEvent, sourceSpan) { 22428 const sourceInfo = (sourceSpan && sourceSpan.start || '(unknown').toString(); 22429 const absoluteOffset = sourceSpan && sourceSpan.start ? sourceSpan.start.offset : 0; 22430 22431 try { 22432 const ast = this._exprParser.parseAction(value, isAssignmentEvent, sourceInfo, absoluteOffset, this._interpolationConfig); 22433 22434 if (ast) { 22435 this._reportExpressionParserErrors(ast.errors, sourceSpan); 22436 } 22437 22438 if (!ast || ast.ast instanceof EmptyExpr) { 22439 this._reportError(`Empty expressions are not allowed`, sourceSpan); 22440 22441 return this._exprParser.wrapLiteralPrimitive('ERROR', sourceInfo, absoluteOffset); 22442 } 22443 22444 return ast; 22445 } catch (e) { 22446 this._reportError(`${e}`, sourceSpan); 22447 22448 return this._exprParser.wrapLiteralPrimitive('ERROR', sourceInfo, absoluteOffset); 22449 } 22450 } 22451 22452 _reportError(message, sourceSpan, level = ParseErrorLevel.ERROR) { 22453 this.errors.push(new ParseError(sourceSpan, message, level)); 22454 } 22455 22456 _reportExpressionParserErrors(errors, sourceSpan) { 22457 for (const error of errors) { 22458 this._reportError(error.message, sourceSpan); 22459 } 22460 } 22461 /** 22462 * @param propName the name of the property / attribute 22463 * @param sourceSpan 22464 * @param isAttr true when binding to an attribute 22465 */ 22466 22467 22468 _validatePropertyOrAttributeName(propName, sourceSpan, isAttr) { 22469 const report = isAttr ? this._schemaRegistry.validateAttribute(propName) : this._schemaRegistry.validateProperty(propName); 22470 22471 if (report.error) { 22472 this._reportError(report.msg, sourceSpan, ParseErrorLevel.ERROR); 22473 } 22474 } 22475 22476} 22477 22478class PipeCollector extends RecursiveAstVisitor { 22479 constructor() { 22480 super(...arguments); 22481 this.pipes = new Map(); 22482 } 22483 22484 visitPipe(ast, context) { 22485 this.pipes.set(ast.name, ast); 22486 ast.exp.visit(this); 22487 this.visitAll(ast.args, context); 22488 return null; 22489 } 22490 22491} 22492 22493function isAnimationLabel(name) { 22494 return name[0] == '@'; 22495} 22496 22497function calcPossibleSecurityContexts(registry, selector, propName, isAttribute) { 22498 const ctxs = []; 22499 CssSelector.parse(selector).forEach(selector => { 22500 const elementNames = selector.element ? [selector.element] : registry.allKnownElementNames(); 22501 const notElementNames = new Set(selector.notSelectors.filter(selector => selector.isElementSelector()).map(selector => selector.element)); 22502 const possibleElementNames = elementNames.filter(elementName => !notElementNames.has(elementName)); 22503 ctxs.push(...possibleElementNames.map(elementName => registry.securityContext(elementName, propName, isAttribute))); 22504 }); 22505 return ctxs.length === 0 ? [SecurityContext.NONE] : Array.from(new Set(ctxs)).sort(); 22506} 22507/** 22508 * Compute a new ParseSourceSpan based off an original `sourceSpan` by using 22509 * absolute offsets from the specified `absoluteSpan`. 22510 * 22511 * @param sourceSpan original source span 22512 * @param absoluteSpan absolute source span to move to 22513 */ 22514 22515 22516function moveParseSourceSpan(sourceSpan, absoluteSpan) { 22517 // The difference of two absolute offsets provide the relative offset 22518 const startDiff = absoluteSpan.start - sourceSpan.start.offset; 22519 const endDiff = absoluteSpan.end - sourceSpan.end.offset; 22520 return new ParseSourceSpan(sourceSpan.start.moveBy(startDiff), sourceSpan.end.moveBy(endDiff), sourceSpan.fullStart.moveBy(startDiff), sourceSpan.details); 22521} 22522/** 22523 * @license 22524 * Copyright Google LLC All Rights Reserved. 22525 * 22526 * Use of this source code is governed by an MIT-style license that can be 22527 * found in the LICENSE file at https://angular.io/license 22528 */ 22529// Some of the code comes from WebComponents.JS 22530// https://github.com/webcomponents/webcomponentsjs/blob/master/src/HTMLImports/path.js 22531 22532 22533function isStyleUrlResolvable(url) { 22534 if (url == null || url.length === 0 || url[0] == '/') return false; 22535 const schemeMatch = url.match(URL_WITH_SCHEMA_REGEXP); 22536 return schemeMatch === null || schemeMatch[1] == 'package' || schemeMatch[1] == 'asset'; 22537} 22538 22539const URL_WITH_SCHEMA_REGEXP = /^([^:/?#]+):/; 22540/** 22541 * @license 22542 * Copyright Google LLC All Rights Reserved. 22543 * 22544 * Use of this source code is governed by an MIT-style license that can be 22545 * found in the LICENSE file at https://angular.io/license 22546 */ 22547 22548const NG_CONTENT_SELECT_ATTR$1 = 'select'; 22549const LINK_ELEMENT = 'link'; 22550const LINK_STYLE_REL_ATTR = 'rel'; 22551const LINK_STYLE_HREF_ATTR = 'href'; 22552const LINK_STYLE_REL_VALUE = 'stylesheet'; 22553const STYLE_ELEMENT = 'style'; 22554const SCRIPT_ELEMENT = 'script'; 22555const NG_NON_BINDABLE_ATTR = 'ngNonBindable'; 22556const NG_PROJECT_AS = 'ngProjectAs'; 22557 22558function preparseElement(ast) { 22559 let selectAttr = null; 22560 let hrefAttr = null; 22561 let relAttr = null; 22562 let nonBindable = false;
22563 let projectAs = ''; 22564 ast.attrs.forEach(attr => { 22565 const lcAttrName = attr.name.toLowerCase(); 22566 22567 if (lcAttrName == NG_CONTENT_SELECT_ATTR$1) { 22568 selectAttr = attr.value; 22569 } else if (lcAttrName == LINK_STYLE_HREF_ATTR) { 22570 hrefAttr = attr.value; 22571 } else if (lcAttrName == LINK_STYLE_REL_ATTR) { 22572 relAttr = attr.value; 22573 } else if (attr.name == NG_NON_BINDABLE_ATTR) { 22574 nonBindable = true; 22575 } else if (attr.name == NG_PROJECT_AS) { 22576 if (attr.value.length > 0) { 22577 projectAs = attr.value; 22578 } 22579 } 22580 }); 22581 selectAttr = normalizeNgContentSelect(selectAttr); 22582 const nodeName = ast.name.toLowerCase(); 22583 let type = PreparsedElementType.OTHER; 22584 22585 if (isNgContent(nodeName)) { 22586 type = PreparsedElementType.NG_CONTENT; 22587 } else if (nodeName == STYLE_ELEMENT) { 22588 type = PreparsedElementType.STYLE; 22589 } else if (nodeName == SCRIPT_ELEMENT) { 22590 type = PreparsedElementType.SCRIPT; 22591 } else if (nodeName == LINK_ELEMENT && relAttr == LINK_STYLE_REL_VALUE) { 22592 type = PreparsedElementType.STYLESHEET; 22593 } 22594 22595 return new PreparsedElement(type, selectAttr, hrefAttr, nonBindable, projectAs); 22596} 22597 22598var PreparsedElementType; 22599 22600(function (PreparsedElementType) { 22601 PreparsedElementType[PreparsedElementType["NG_CONTENT"] = 0] = "NG_CONTENT"; 22602 PreparsedElementType[PreparsedElementType["STYLE"] = 1] = "STYLE"; 22603 PreparsedElementType[PreparsedElementType["STYLESHEET"] = 2] = "STYLESHEET"; 22604 PreparsedElementType[PreparsedElementType["SCRIPT"] = 3] = "SCRIPT"; 22605 PreparsedElementType[PreparsedElementType["OTHER"] = 4] = "OTHER"; 22606})(PreparsedElementType || (PreparsedElementType = {})); 22607 22608class PreparsedElement { 22609 constructor(type, selectAttr, hrefAttr, nonBindable, projectAs) { 22610 this.type = type; 22611 this.selectAttr = selectAttr; 22612 this.hrefAttr = hrefAttr; 22613 this.nonBindable = nonBindable; 22614 this.projectAs = projectAs; 22615 } 22616 22617} 22618 22619function normalizeNgContentSelect(selectAttr) { 22620 if (selectAttr === null || selectAttr.length === 0) { 22621 return '*'; 22622 } 22623 22624 return selectAttr; 22625} 22626/** 22627 * @license 22628 * Copyright Google LLC All Rights Reserved. 22629 * 22630 * Use of this source code is governed by an MIT-style license that can be 22631 * found in the LICENSE file at https://angular.io/license 22632 */ 22633 22634 22635const BIND_NAME_REGEXP = /^(?:(bind-)|(let-)|(ref-|#)|(on-)|(bindon-)|(@))(.*)$/; // Group 1 = "bind-" 22636 22637const KW_BIND_IDX = 1; // Group 2 = "let-" 22638 22639const KW_LET_IDX = 2; // Group 3 = "ref-/#" 22640 22641const KW_REF_IDX = 3; // Group 4 = "on-" 22642 22643const KW_ON_IDX = 4; // Group 5 = "bindon-" 22644 22645const KW_BINDON_IDX = 5; // Group 6 = "@" 22646 22647const KW_AT_IDX = 6; // Group 7 = the identifier after "bind-", "let-", "ref-/#", "on-", "bindon-" or "@" 22648 22649const IDENT_KW_IDX = 7; 22650const BINDING_DELIMS = { 22651 BANANA_BOX: { 22652 start: '[(', 22653 end: ')]' 22654 }, 22655 PROPERTY: { 22656 start: '[', 22657 end: ']' 22658 }, 22659 EVENT: { 22660 start: '(', 22661 end: ')' 22662 } 22663}; 22664const TEMPLATE_ATTR_PREFIX = '*'; 22665 22666function htmlAstToRender3Ast(htmlNodes, bindingParser, options) { 22667 const transformer = new HtmlAstToIvyAst(bindingParser, options); 22668 const ivyNodes = visitAll(transformer, htmlNodes); // Errors might originate in either the binding parser or the html to ivy transformer 22669 22670 const allErrors = bindingParser.errors.concat(transformer.errors); 22671 const result = { 22672 nodes: ivyNodes, 22673 errors: allErrors, 22674 styleUrls: transformer.styleUrls, 22675 styles: transformer.styles, 22676 ngContentSelectors: transformer.ngContentSelectors 22677 }; 22678 22679 if (options.collectCommentNodes) { 22680 result.commentNodes = transformer.commentNodes; 22681 } 22682 22683 return result; 22684} 22685 22686class HtmlAstToIvyAst { 22687 constructor(bindingParser, options) { 22688 this.bindingParser = bindingParser; 22689 this.options = options; 22690 this.errors = []; 22691 this.styles = []; 22692 this.styleUrls = []; 22693 this.ngContentSelectors = []; // This array will be populated if `Render3ParseOptions['collectCommentNodes']` is true 22694 22695 this.commentNodes = []; 22696 this.inI18nBlock = false; 22697 } // HTML visitor 22698 22699 22700 visitElement(element) { 22701 const isI18nRootElement = isI18nRootNode(element.i18n); 22702 22703 if (isI18nRootElement) { 22704 if (this.inI18nBlock) { 22705 this.reportError('Cannot mark an element as translatable inside of a translatable section. Please remove the nested i18n marker.', element.sourceSpan); 22706 } 22707 22708 this.inI18nBlock = true; 22709 } 22710 22711 const preparsedElement = preparseElement(element); 22712 22713 if (preparsedElement.type === PreparsedElementType.SCRIPT) { 22714 return null; 22715 } else if (preparsedElement.type === PreparsedElementType.STYLE) { 22716 const contents = textContents(element); 22717 22718 if (contents !== null) { 22719 this.styles.push(contents); 22720 } 22721 22722 return null; 22723 } else if (preparsedElement.type === PreparsedElementType.STYLESHEET && isStyleUrlResolvable(preparsedElement.hrefAttr)) { 22724 this.styleUrls.push(preparsedElement.hrefAttr); 22725 return null; 22726 } // Whether the element is a `<ng-template>` 22727 22728 22729 const isTemplateElement = isNgTemplate(element.name); 22730 const parsedProperties = []; 22731 const boundEvents = []; 22732 const variables = []; 22733 const references = []; 22734 const attributes = []; 22735 const i18nAttrsMeta = {}; 22736 const templateParsedProperties = []; 22737 const templateVariables = []; // Whether the element has any *-attribute 22738 22739 let elementHasInlineTemplate = false;
22740 22741 for (const attribute of element.attrs) { 22742 let hasBinding = false; 22743 const normalizedName = normalizeAttributeName(attribute.name); // `*attr` defines template bindings 22744 22745 let isTemplateBinding = false; 22746 22747 if (attribute.i18n) { 22748 i18nAttrsMeta[attribute.name] = attribute.i18n; 22749 } 22750 22751 if (normalizedName.startsWith(TEMPLATE_ATTR_PREFIX)) { 22752 // *-attributes 22753 if (elementHasInlineTemplate) { 22754 this.reportError(`Can't have multiple template bindings on one element. Use only one attribute prefixed with *`, attribute.sourceSpan); 22755 } 22756 22757 isTemplateBinding = true; 22758 elementHasInlineTemplate = true; 22759 const templateValue = attribute.value; 22760 const templateKey = normalizedName.substring(TEMPLATE_ATTR_PREFIX.length); 22761 const parsedVariables = []; 22762 const absoluteValueOffset = attribute.valueSpan ? attribute.valueSpan.start.offset : // If there is no value span the attribute does not have a value, like `attr` in 22763 //`<div attr></div>`. In this case, point to one character beyond the last character of 22764 // the attribute name. 22765 attribute.sourceSpan.start.offset + attribute.name.length; 22766 this.bindingParser.parseInlineTemplateBinding(templateKey, templateValue, attribute.sourceSpan, absoluteValueOffset, [], templateParsedProperties, parsedVariables, true 22767 /* isIvyAst */ 22768 ); 22769 templateVariables.push(...parsedVariables.map(v => new Variable(v.name, v.value, v.sourceSpan, v.keySpan, v.valueSpan))); 22770 } else { 22771 // Check for variables, events, property bindings, interpolation 22772 hasBinding = this.parseAttribute(isTemplateElement, attribute, [], parsedProperties, boundEvents, variables, references); 22773 } 22774 22775 if (!hasBinding && !isTemplateBinding) { 22776 // don't include the bindings as attributes as well in the AST 22777 attributes.push(this.visitAttribute(attribute)); 22778 } 22779 } 22780 22781 const children = visitAll(preparsedElement.nonBindable ? NON_BINDABLE_VISITOR : this, element.children); 22782 let parsedElement; 22783 22784 if (preparsedElement.type === PreparsedElementType.NG_CONTENT) { 22785 // `<ng-content>` 22786 if (element.children && !element.children.every(node => isEmptyTextNode(node) || isCommentNode(node))) { 22787 this.reportError(`<ng-content> element cannot have content.`, element.sourceSpan); 22788 } 22789 22790 const selector = preparsedElement.selectAttr; 22791 const attrs = element.attrs.map(attr => this.visitAttribute(attr)); 22792 parsedElement = new Content(selector, attrs, element.sourceSpan, element.i18n); 22793 this.ngContentSelectors.push(selector); 22794 } else if (isTemplateElement) { 22795 // `<ng-template>` 22796 const attrs = this.extractAttributes(element.name, parsedProperties, i18nAttrsMeta); 22797 parsedElement = new Template(element.name, attributes, attrs.bound, boundEvents, [ 22798 /* no template attributes */ 22799 ], children, references, variables, element.sourceSpan, element.startSourceSpan, element.endSourceSpan, element.i18n); 22800 } else { 22801 const attrs = this.extractAttributes(element.name, parsedProperties, i18nAttrsMeta); 22802 parsedElement = new Element$1(element.name, attributes, attrs.bound, boundEvents, children, references, element.sourceSpan, element.startSourceSpan, element.endSourceSpan, element.i18n); 22803 } 22804 22805 if (elementHasInlineTemplate) { 22806 // If this node is an inline-template (e.g. has *ngFor) then we need to create a template
22807 // node that contains this node. 22808 // Moreover, if the node is an element, then we need to hoist its attributes to the template 22809 // node for matching against content projection selectors. 22810 const attrs = this.extractAttributes('ng-template', templateParsedProperties, i18nAttrsMeta); 22811 const templateAttrs = []; 22812 attrs.literal.forEach(attr => templateAttrs.push(attr)); 22813 attrs.bound.forEach(attr => templateAttrs.push(attr)); 22814 const hoistedAttrs = parsedElement instanceof Element$1 ? { 22815 attributes: parsedElement.attributes, 22816 inputs: parsedElement.inputs, 22817 outputs: parsedElement.outputs 22818 } : { 22819 attributes: [], 22820 inputs: [], 22821 outputs: [] 22822 }; // For <ng-template>s with structural directives on them, avoid passing i18n information to 22823 // the wrapping template to prevent unnecessary i18n instructions from being generated. The 22824 // necessary i18n meta information will be extracted from child elements. 22825 22826 const i18n = isTemplateElement && isI18nRootElement ? undefined : element.i18n; 22827 const name = parsedElement instanceof Template ? null : parsedElement.name; 22828 parsedElement = new Template(name, hoistedAttrs.attributes, hoistedAttrs.inputs, hoistedAttrs.outputs, templateAttrs, [parsedElement], [ 22829 /* no references */ 22830 ], templateVariables, element.sourceSpan, element.startSourceSpan, element.endSourceSpan, i18n); 22831 } 22832 22833 if (isI18nRootElement) { 22834 this.inI18nBlock = false; 22835 } 22836 22837 return parsedElement; 22838 } 22839 22840 visitAttribute(attribute) { 22841 return new TextAttribute(attribute.name, attribute.value, attribute.sourceSpan, attribute.keySpan, attribute.valueSpan, attribute.i18n); 22842 } 22843 22844 visitText(text) { 22845 return this._visitTextWithInterpolation(text.value, text.sourceSpan, text.tokens, text.i18n); 22846 } 22847 22848 visitExpansion(expansion) { 22849 if (!expansion.i18n) { 22850 // do not generate Icu in case it was created 22851 // outside of i18n block in a template 22852 return null; 22853 } 22854 22855 if (!isI18nRootNode(expansion.i18n)) { 22856 throw new Error(`Invalid type "${expansion.i18n.constructor}" for "i18n" property of ${expansion.sourceSpan.toString()}. Expected a "Message"`); 22857 } 22858 22859 const message = expansion.i18n; 22860 const vars = {}; 22861 const placeholders = {}; // extract VARs from ICUs - we process them separately while 22862 // assembling resulting message via goog.getMsg function, since 22863 // we need to pass them to top-level goog.getMsg call 22864 22865 Object.keys(message.placeholders).forEach(key => { 22866 const value = message.placeholders[key]; 22867 22868 if (key.startsWith(I18N_ICU_VAR_PREFIX)) { 22869 // Currently when the `plural` or `select` keywords in an ICU contain trailing spaces (e.g. 22870 // `{count, select , ...}`), these spaces are also included into the key names in ICU vars 22871 // (e.g. "VAR_SELECT "). These trailing spaces are not desirable, since they will later be 22872 // converted into `_` symbols while normalizing placeholder names, which might lead to 22873 // mismatches at runtime (i.e. placeholder will not be replaced with the correct value). 22874 const formattedKey = key.trim(); 22875 const ast = this.bindingParser.parseInterpolationExpression(value.text, value.sourceSpan); 22876 vars[formattedKey] = new BoundText(ast, value.sourceSpan); 22877 } else { 22878 placeholders[key] = this._visitTextWithInterpolation(value.text, value.sourceSpan, null); 22879 } 22880 }); 22881 return new Icu$1(vars, placeholders, expansion.sourceSpan, message); 22882 } 22883 22884 visitExpansionCase(expansionCase) { 22885 return null; 22886 } 22887 22888 visitComment(comment) { 22889 if (this.options.collectCommentNodes) { 22890 this.commentNodes.push(new Comment$1(comment.value || '', comment.sourceSpan)); 22891 } 22892 22893 return null; 22894 } // convert view engine `ParsedProperty` to a format suitable for IVY 22895 22896 22897 extractAttributes(elementName, properties, i18nPropsMeta) { 22898 const bound = []; 22899 const literal = []; 22900 properties.forEach(prop => { 22901 const i18n = i18nPropsMeta[prop.name]; 22902 22903 if (prop.isLiteral) { 22904 literal.push(new TextAttribute(prop.name, prop.expression.source || '', prop.sourceSpan, prop.keySpan, prop.valueSpan, i18n)); 22905 } else { 22906 // Note that validation is skipped and property mapping is disabled 22907 // due to the fact that we need to make sure a given prop is not an 22908 // input of a directive and directive matching happens at runtime. 22909 const bep = this.bindingParser.createBoundElementProperty(elementName, prop, 22910 /* skipValidation */ 22911 true, 22912 /* mapPropertyName */ 22913 false); 22914 bound.push(BoundAttribute.fromBoundElementProperty(bep, i18n)); 22915 } 22916 }); 22917 return { 22918 bound, 22919 literal 22920 }; 22921 } 22922 22923 parseAttribute(isTemplateElement, attribute, matchableAttributes, parsedProperties, boundEvents, variables, references) { 22924 const name = normalizeAttributeName(attribute.name); 22925 const value = attribute.value; 22926 const srcSpan = attribute.sourceSpan; 22927 const absoluteOffset = attribute.valueSpan ? attribute.valueSpan.start.offset : srcSpan.start.offset; 22928 22929 function createKeySpan(srcSpan, prefix, identifier) { 22930 // We need to adjust the start location for the keySpan to account for the removed 'data-' 22931 // prefix from `normalizeAttributeName`. 22932 const normalizationAdjustment = attribute.name.length - name.length;
22933 const keySpanStart = srcSpan.start.moveBy(prefix.length + normalizationAdjustment); 22934 const keySpanEnd = keySpanStart.moveBy(identifier.length); 22935 return new ParseSourceSpan(keySpanStart, keySpanEnd, keySpanStart, identifier); 22936 } 22937 22938 const bindParts = name.match(BIND_NAME_REGEXP); 22939 22940 if (bindParts) { 22941 if (bindParts[KW_BIND_IDX] != null) { 22942 const identifier = bindParts[IDENT_KW_IDX]; 22943 const keySpan = createKeySpan(srcSpan, bindParts[KW_BIND_IDX], identifier); 22944 this.bindingParser.parsePropertyBinding(identifier, value, false, srcSpan, absoluteOffset, attribute.valueSpan, matchableAttributes, parsedProperties, keySpan); 22945 } else if (bindParts[KW_LET_IDX]) { 22946 if (isTemplateElement) { 22947 const identifier = bindParts[IDENT_KW_IDX]; 22948 const keySpan = createKeySpan(srcSpan, bindParts[KW_LET_IDX], identifier); 22949 this.parseVariable(identifier, value, srcSpan, keySpan, attribute.valueSpan, variables); 22950 } else { 22951 this.reportError(`"let-" is only supported on ng-template elements.`, srcSpan); 22952 } 22953 } else if (bindParts[KW_REF_IDX]) { 22954 const identifier = bindParts[IDENT_KW_IDX]; 22955 const keySpan = createKeySpan(srcSpan, bindParts[KW_REF_IDX], identifier); 22956 this.parseReference(identifier, value, srcSpan, keySpan, attribute.valueSpan, references); 22957 } else if (bindParts[KW_ON_IDX]) { 22958 const events = []; 22959 const identifier = bindParts[IDENT_KW_IDX]; 22960 const keySpan = createKeySpan(srcSpan, bindParts[KW_ON_IDX], identifier); 22961 this.bindingParser.parseEvent(identifier, value, 22962 /* isAssignmentEvent */ 22963 false, srcSpan, attribute.valueSpan || srcSpan, matchableAttributes, events, keySpan); 22964 addEvents(events, boundEvents); 22965 } else if (bindParts[KW_BINDON_IDX]) { 22966 const identifier = bindParts[IDENT_KW_IDX]; 22967 const keySpan = createKeySpan(srcSpan, bindParts[KW_BINDON_IDX], identifier); 22968 this.bindingParser.parsePropertyBinding(identifier, value, false, srcSpan, absoluteOffset, attribute.valueSpan, matchableAttributes, parsedProperties, keySpan); 22969 this.parseAssignmentEvent(identifier, value, srcSpan, attribute.valueSpan, matchableAttributes, boundEvents, keySpan); 22970 } else if (bindParts[KW_AT_IDX]) { 22971 const keySpan = createKeySpan(srcSpan, '', name); 22972 this.bindingParser.parseLiteralAttr(name, value, srcSpan, absoluteOffset, attribute.valueSpan, matchableAttributes, parsedProperties, keySpan); 22973 } 22974 22975 return true; 22976 } // We didn't see a kw-prefixed property binding, but we have not yet checked 22977 // for the []/()/[()] syntax. 22978 22979 22980 let delims = null; 22981 22982 if (name.startsWith(BINDING_DELIMS.BANANA_BOX.start)) { 22983 delims = BINDING_DELIMS.BANANA_BOX; 22984 } else if (name.startsWith(BINDING_DELIMS.PROPERTY.start)) { 22985 delims = BINDING_DELIMS.PROPERTY; 22986 } else if (name.startsWith(BINDING_DELIMS.EVENT.start)) { 22987 delims = BINDING_DELIMS.EVENT; 22988 } 22989 22990 if (delims !== null && // NOTE: older versions of the parser would match a start/end delimited 22991 // binding iff the property name was terminated by the ending delimiter 22992 // and the identifier in the binding was non-empty. 22993 // TODO(ayazhafiz): update this to handle malformed bindings. 22994 name.endsWith(delims.end) && name.length > delims.start.length + delims.end.length) { 22995 const identifier = name.substring(delims.start.length, name.length - delims.end.length); 22996 const keySpan = createKeySpan(srcSpan, delims.start, identifier); 22997 22998 if (delims.start === BINDING_DELIMS.BANANA_BOX.start) { 22999 this.bindingParser.parsePropertyBinding(identifier, value, false, srcSpan, absoluteOffset, attribute.valueSpan, matchableAttributes, parsedProperties, keySpan); 23000 this.parseAssignmentEvent(identifier, value, srcSpan, attribute.valueSpan, matchableAttributes, boundEvents, keySpan); 23001 } else if (delims.start === BINDING_DELIMS.PROPERTY.start) { 23002 this.bindingParser.parsePropertyBinding(identifier, value, false, srcSpan, absoluteOffset, attribute.valueSpan, matchableAttributes, parsedProperties, keySpan); 23003 } else { 23004 const events = []; 23005 this.bindingParser.parseEvent(identifier, value, 23006 /* isAssignmentEvent */ 23007 false, srcSpan, attribute.valueSpan || srcSpan, matchableAttributes, events, keySpan); 23008 addEvents(events, boundEvents); 23009 } 23010 23011 return true; 23012 } // No explicit binding found. 23013 23014
23015 const keySpan = createKeySpan(srcSpan, '' 23016 /* prefix */ 23017 , name); 23018 const hasBinding = this.bindingParser.parsePropertyInterpolation(name, value, srcSpan, attribute.valueSpan, matchableAttributes, parsedProperties, keySpan, attribute.valueTokens ?? null); 23019 return hasBinding; 23020 } 23021 23022 _visitTextWithInterpolation(value, sourceSpan, interpolatedTokens, i18n) { 23023 const valueNoNgsp = replaceNgsp(value); 23024 const expr = this.bindingParser.parseInterpolation(valueNoNgsp, sourceSpan, interpolatedTokens); 23025 return expr ? new BoundText(expr, sourceSpan, i18n) : new Text$3(valueNoNgsp, sourceSpan); 23026 } 23027 23028 parseVariable(identifier, value, sourceSpan, keySpan, valueSpan, variables) { 23029 if (identifier.indexOf('-') > -1) { 23030 this.reportError(`"-" is not allowed in variable names`, sourceSpan); 23031 } else if (identifier.length === 0) { 23032 this.reportError(`Variable does not have a name`, sourceSpan); 23033 } 23034 23035 variables.push(new Variable(identifier, value, sourceSpan, keySpan, valueSpan)); 23036 } 23037 23038 parseReference(identifier, value, sourceSpan, keySpan, valueSpan, references) { 23039 if (identifier.indexOf('-') > -1) { 23040 this.reportError(`"-" is not allowed in reference names`, sourceSpan); 23041 } else if (identifier.length === 0) { 23042 this.reportError(`Reference does not have a name`, sourceSpan); 23043 } else if (references.some(reference => reference.name === identifier)) { 23044 this.reportError(`Reference "#${identifier}" is defined more than once`, sourceSpan); 23045 } 23046 23047 references.push(new Reference(identifier, value, sourceSpan, keySpan, valueSpan)); 23048 } 23049 23050 parseAssignmentEvent(name, expression, sourceSpan, valueSpan, targetMatchableAttrs, boundEvents, keySpan) { 23051 const events = []; 23052 this.bindingParser.parseEvent(`${name}Change`, `${expression} =$event`, 23053 /* isAssignmentEvent */ 23054 true, sourceSpan, valueSpan || sourceSpan, targetMatchableAttrs, events, keySpan); 23055 addEvents(events, boundEvents); 23056 } 23057 23058 reportError(message, sourceSpan, level = ParseErrorLevel.ERROR) { 23059 this.errors.push(new ParseError(sourceSpan, message, level)); 23060 } 23061 23062} 23063 23064class NonBindableVisitor { 23065 visitElement(ast) { 23066 const preparsedElement = preparseElement(ast); 23067 23068 if (preparsedElement.type === PreparsedElementType.SCRIPT || preparsedElement.type === PreparsedElementType.STYLE || preparsedElement.type === PreparsedElementType.STYLESHEET) { 23069 // Skipping <script> for security reasons 23070 // Skipping <style> and stylesheets as we already processed them 23071 // in the StyleCompiler 23072 return null; 23073 } 23074 23075 const children = visitAll(this, ast.children, null); 23076 return new Element$1(ast.name, visitAll(this, ast.attrs), 23077 /* inputs */ 23078 [], 23079 /* outputs */ 23080 [], children, 23081 /* references */ 23082 [], ast.sourceSpan, ast.startSourceSpan, ast.endSourceSpan); 23083 } 23084 23085 visitComment(comment) { 23086 return null; 23087 } 23088 23089 visitAttribute(attribute) { 23090 return new TextAttribute(attribute.name, attribute.value, attribute.sourceSpan, attribute.keySpan, attribute.valueSpan, attribute.i18n); 23091 } 23092 23093 visitText(text) { 23094 return new Text$3(text.value, text.sourceSpan); 23095 } 23096 23097 visitExpansion(expansion) { 23098 return null; 23099 } 23100 23101 visitExpansionCase(expansionCase) { 23102 return null; 23103 } 23104 23105} 23106 23107const NON_BINDABLE_VISITOR = new NonBindableVisitor(); 23108 23109function normalizeAttributeName(attrName) { 23110 return /^data-/i.test(attrName) ? attrName.substring(5) : attrName; 23111} 23112 23113function addEvents(events, boundEvents) { 23114 boundEvents.push(...events.map(e => BoundEvent.fromParsedEvent(e))); 23115} 23116 23117function isEmptyTextNode(node) { 23118 return node instanceof Text && node.value.trim().length == 0; 23119} 23120 23121function isCommentNode(node) { 23122 return node instanceof Comment; 23123} 23124 23125function textContents(node) { 23126 if (node.children.length !== 1 || !(node.children[0] instanceof Text)) { 23127 return null; 23128 } else { 23129 return node.children[0].value; 23130 } 23131} 23132/** 23133 * @license 23134 * Copyright Google LLC All Rights Reserved. 23135 * 23136 * Use of this source code is governed by an MIT-style license that can be 23137 * found in the LICENSE file at https://angular.io/license 23138 */ 23139 23140 23141var TagType; 23142 23143(function (TagType) { 23144 TagType[TagType["ELEMENT"] = 0] = "ELEMENT"; 23145 TagType[TagType["TEMPLATE"] = 1] = "TEMPLATE"; 23146})(TagType || (TagType = {})); 23147/** 23148 * Generates an object that is used as a shared state between parent and all child contexts. 23149 */ 23150 23151 23152function setupRegistry() { 23153 return { 23154 getUniqueId: getSeqNumberGenerator(), 23155 icus: new Map() 23156 }; 23157} 23158/** 23159 * I18nContext is a helper class which keeps track of all i18n-related as
23159pects 23160 * (accumulates placeholders, bindings, etc) between i18nStart and i18nEnd instructions. 23161 * 23162 * When we enter a nested template, the top-level context is being passed down 23163 * to the nested component, which uses this context to generate a child instance 23164 * of I18nContext class (to handle nested template) and at the end, reconciles it back 23165 * with the parent context. 23166 * 23167 * @param index Instruction index of i18nStart, which initiates this context 23168 * @param ref Reference to a translation const that represents the content if thus context 23169 * @param level Nesting level defined for child contexts 23170 * @param templateIndex Instruction index of a template which this context belongs to 23171 * @param meta Meta information (id, meaning, description, etc) associated with this context 23172 */ 23173 23174 23175class I18nContext { 23176 constructor(index, ref, level = 0, templateIndex = null, meta, registry) { 23177 this.index = index; 23178 this.ref = ref; 23179 this.level = level; 23180 this.templateIndex = templateIndex; 23181 this.meta = meta; 23182 this.registry = registry; 23183 this.bindings = new Set(); 23184 this.placeholders = new Map(); 23185 this.isEmitted = false; 23186 this._unresolvedCtxCount = 0; 23187 this._registry = registry || setupRegistry(); 23188 this.id = this._registry.getUniqueId(); 23189 } 23190 23191 appendTag(type, node, index, closed) { 23192 if (node.isVoid && closed) { 23193 return; // ignore "close" for void tags 23194 } 23195 23196 const ph = node.isVoid || !closed ? node.startName : node.closeName; 23197 const content = { 23198 type, 23199 index, 23200 ctx: this.id, 23201 isVoid: node.isVoid, 23202 closed 23203 }; 23204 updatePlaceholderMap(this.placeholders, ph, content); 23205 } 23206 23207 get icus() { 23208 return this._registry.icus; 23209 } 23210 23211 get isRoot() { 23212 return this.level === 0; 23213 } 23214 23215 get isResolved() { 23216 return this._unresolvedCtxCount === 0; 23217 } 23218 23219 getSerializedPlaceholders() { 23220 const result = new Map(); 23221 this.placeholders.forEach((values, key) => result.set(key, values.map(serializePlaceholderValue))); 23222 return result; 23223 } // public API to accumulate i18n-related content 23224 23225 23226 appendBinding(binding) { 23227 this.bindings.add(binding); 23228 } 23229 23230 appendIcu(name, ref) { 23231 updatePlaceholderMap(this._registry.icus, name, ref); 23232 } 23233 23234 appendBoundText(node) { 23235 const phs = assembleBoundTextPlaceholders(node, this.bindings.size, this.id); 23236 phs.forEach((values, key) => updatePlaceholderMap(this.placeholders, key, ...values)); 23237 } 23238 23239 appendTemplate(node, index) { 23240 // add open and close tags at the same time, 23241 // since we process nested templates separately 23242 this.appendTag(TagType.TEMPLATE, node, index, false); 23243 this.appendTag(TagType.TEMPLATE, node, index, true); 23244 this._unresolvedCtxCount++; 23245 } 23246 23247 appendElement(node, index, closed) { 23248 this.appendTag(TagType.ELEMENT, node, index, closed); 23249 } 23250 23251 appendProjection(node, index) { 23252 // Add open and close tags at the same time, since `<ng-content>` has no content, 23253 // so when we come across `<ng-content>` we can register both open and close tags. 23254 // Note: runtime i18n logic doesn't distinguish `<ng-content>` tag placeholders and 23255 // regular element tag placeholders, so we generate element placeholders for both types. 23256 this.appendTag(TagType.ELEMENT, node, index, false); 23257 this.appendTag(TagType.ELEMENT, node, index, true); 23258 } 23259 /** 23260 * Generates an instance of a child context based on the root one, 23261 * when we enter a nested template within I18n section. 23262 * 23263 * @param index Instruction index of corresponding i18nStart, which initiates this context 23264 * @param templateIndex Instruction index of a template which this context belongs to 23265 * @param meta Meta information (id, meaning, description, etc) associated with this context 23266 * 23267 * @returns I18nContext instance 23268 */ 23269 23270 23271 forkChildContext(index, templateIndex, meta) { 23272 return new I18nContext(index, this.ref, this.level + 1, templateIndex, meta, this._registry); 23273 } 23274 /** 23275 * Reconciles child context into parent one once the end of the i18n block is reached (i18nEnd). 23276 * 23277 * @param context Child I18nContext instance to be reconciled with parent context. 23278 */ 23279 23280 23281 reconcileChildContext(context) { 23282 // set the right context id for open and close 23283 // template tags, so we can use it as sub-block ids 23284 ['start', 'close'].forEach(op => {
23285 const key = context.meta[`${op}Name`]; 23286 const phs = this.placeholders.get(key) || []; 23287 const tag = phs.find(findTemplateFn(this.id, context.templateIndex)); 23288 23289 if (tag) { 23290 tag.ctx = context.id; 23291 } 23292 }); // reconcile placeholders 23293 23294 const childPhs = context.placeholders; 23295 childPhs.forEach((values, key) => { 23296 const phs = this.placeholders.get(key); 23297 23298 if (!phs) { 23299 this.placeholders.set(key, values); 23300 return; 23301 } // try to find matching template... 23302 23303 23304 const tmplIdx = phs.findIndex(findTemplateFn(context.id, context.templateIndex)); 23305 23306 if (tmplIdx >= 0) { 23307 // ... if found - replace it with nested template content 23308 const isCloseTag = key.startsWith('CLOSE'); 23309 const isTemplateTag = key.endsWith('NG-TEMPLATE'); 23310 23311 if (isTemplateTag) { 23312 // current template's content is placed before or after 23313 // parent template tag, depending on the open/close attribute 23314 phs.splice(tmplIdx + (isCloseTag ? 0 : 1), 0, ...values); 23315 } else { 23316 const idx = isCloseTag ? values.length - 1 : 0; 23317 values[idx].tmpl = phs[tmplIdx]; 23318 phs.splice(tmplIdx, 1, ...values); 23319 } 23320 } else { 23321 // ... otherwise just append content to placeholder value 23322 phs.push(...values); 23323 } 23324 23325 this.placeholders.set(key, phs); 23326 }); 23327 this._unresolvedCtxCount--; 23328 } 23329 23330} // 23331// Helper methods 23332// 23333 23334 23335function wrap(symbol, index, contextId, closed) { 23336 const state = closed ? '/' : ''; 23337 return wrapI18nPlaceholder(`${state}${symbol}${index}`, contextId); 23338} 23339 23340function wrapTag(symbol, { 23341 index, 23342 ctx, 23343 isVoid 23344}, closed) { 23345 return isVoid ? wrap(symbol, index, ctx) + wrap(symbol, index, ctx, true) : wrap(symbol, index, ctx, closed); 23346} 23347 23348function findTemplateFn(ctx, templateIndex) { 23349 return token => typeof token === 'object' && token.type === TagType.TEMPLATE && token.index === templateIndex && token.ctx === ctx; 23350} 23351 23352function serializePlaceholderValue(value) { 23353 const element = (data, closed) => wrapTag('#', data, closed); 23354 23355 const template = (data, closed) => wrapTag('*', data, closed); 23356 23357 const projection = (data, closed) => wrapTag('!', data, closed); 23358 23359 switch (value.type) { 23360 case TagType.ELEMENT: 23361 // close element tag 23362 if (value.closed) { 23363 return element(value, true) + (value.tmpl ? template(value.tmpl, true) : ''); 23364 } // open element tag that also initiates a template 23365 23366 23367 if (value.tmpl) { 23368 return template(value.tmpl) + element(value) + (value.isVoid ? template(value.tmpl, true) : ''); 23369 } 23370 23371 return element(value); 23372 23373 case TagType.TEMPLATE: 23374 return template(value, value.closed); 23375 23376 default: 23377 return value; 23378 } 23379} 23380/** 23381 * @license 23382 * Copyright Google LLC All Rights Reserved. 23383 * 23384 * Use of this source code is governed by an MIT-style license that can be 23385 * found in the LICENSE file at https://angular.io/license 23386 */ 23387 23388 23389class IcuSerializerVisitor { 23390 visitText(text) { 23391 return text.value; 23392 } 23393 23394 visitContainer(container) { 23395 return container.children.map(child => child.visit(this)).join(''); 23396 } 23397 23398 visitIcu(icu) { 23399 const strCases = Object.keys(icu.cases).map(k => `${k} {${icu.cases[k].visit(this)}}`); 23400 const result = `{${icu.expressionPlaceholder}, ${icu.type}, ${strCases.join(' ')}}`; 23401 return result; 23402 } 23403 23404 visitTagPlaceholder(ph) { 23405 return ph.isVoid ? this.formatPh(ph.startName) : `${this.formatPh(ph.startName)}${ph.children.map(child => child.visit(this)).join('')}${this.formatPh(ph.closeName)}`; 23406 } 23407 23408 visitPlaceholder(ph) { 23409 return this.formatPh(ph.name); 23410 } 23411 23412 visitIcuPlaceholder(ph, context) { 23413 return this.formatPh(ph.name); 23414 } 23415 23416 formatPh(value) { 23417 return `{${formatI18nPlaceholderName(value, 23418 /* useCamelCase */ 23419 false)}}`; 23420 } 23421 23422} 23423 23424const serializer = new IcuSerializerVisitor(); 23425 23426function serializeIcuNode(icu) { 23427 return icu.visit(serializer); 23428} 23429/** 23430 * @license 23431 * Copyright Google LLC All Rights Reserved. 23432 * 23433 * Use of this source code is governed by an MIT-style license that can be 23434 * found in the LICENSE file at https://angular.io/license 23435 */ 23436 23437 23438const TAG_TO_PLACEHOLDER_NAMES = { 23439 'A': 'LINK', 23440 'B': 'BOLD_TEXT', 23441 'BR': 'LINE_BREAK', 23442 'EM': 'EMPHASISED_TEXT', 23443 'H1': 'HEADING_LEVEL1', 23444 'H2': 'HEADING_LEVEL2', 23445 'H3': 'HEADING_LEVEL3', 23446 'H4': 'HEADING_LEVEL4', 23447 'H5': 'HEADING_LEVEL5', 23448 'H6': 'HEADING_LEVEL6', 23449 'HR': 'HORIZONTAL_RULE', 23450 'I': 'ITALIC_TEXT', 23451 'LI': 'LIST_ITEM', 23452 'LINK': 'MEDIA_LINK', 23453 'OL': 'ORDERED_LIST', 23454 'P': 'PARAGRAPH', 23455 'Q': 'QUOTATION', 23456 'S': 'STRIKETHROUGH_TEXT', 23457 'SMALL': 'SMALL_TEXT', 23458 'SUB': 'SUBSTRIPT', 23459 'SUP': 'SUPERSCRIPT', 23460 'TBODY': 'TABLE_BODY', 23461 'TD': 'TABLE_CELL', 23462 'TFOOT': 'TABLE_FOOTER', 23463 'TH': 'TABLE_HEADER_CELL', 23464 'THEAD': 'TABLE_HEADER', 23465 'TR': 'TABLE_ROW', 23466 'TT': 'MONOSPACED_TEXT', 23467 'U': 'UNDERLINED_TEXT', 23468 'UL': 'UNORDERED_LIST' 23469}; 23470/**
23471 * Creates unique names for placeholder with different content. 23472 * 23473 * Returns the same placeholder name when the content is identical. 23474 */ 23475 23476class PlaceholderRegistry { 23477 constructor() { 23478 // Count the occurrence of the base name top generate a unique name 23479 this._placeHolderNameCounts = {}; // Maps signature to placeholder names 23480 23481 this._signatureToName = {}; 23482 } 23483 23484 getStartTagPlaceholderName(tag, attrs, isVoid) { 23485 const signature = this._hashTag(tag, attrs, isVoid); 23486 23487 if (this._signatureToName[signature]) { 23488 return this._signatureToName[signature]; 23489 } 23490 23491 const upperTag = tag.toUpperCase(); 23492 const baseName = TAG_TO_PLACEHOLDER_NAMES[upperTag] || `TAG_${upperTag}`; 23493 23494 const name = this._generateUniqueName(isVoid ? baseName : `START_${baseName}`); 23495 23496 this._signatureToName[signature] = name; 23497 return name; 23498 } 23499 23500 getCloseTagPlaceholderName(tag) { 23501 const signature = this._hashClosingTag(tag); 23502 23503 if (this._signatureToName[signature]) { 23504 return this._signatureToName[signature]; 23505 } 23506 23507 const upperTag = tag.toUpperCase(); 23508 const baseName = TAG_TO_PLACEHOLDER_NAMES[upperTag] || `TAG_${upperTag}`; 23509 23510 const name = this._generateUniqueName(`CLOSE_${baseName}`); 23511 23512 this._signatureToName[signature] = name; 23513 return name; 23514 } 23515 23516 getPlaceholderName(name, content) { 23517 const upperName = name.toUpperCase(); 23518 const signature = `PH: ${upperName}=${content}`; 23519 23520 if (this._signatureToName[signature]) { 23521 return this._signatureToName[signature]; 23522 } 23523 23524 const uniqueName = this._generateUniqueName(upperName); 23525 23526 this._signatureToName[signature] = uniqueName; 23527 return uniqueName; 23528 } 23529 23530 getUniquePlaceholder(name) { 23531 return this._generateUniqueName(name.toUpperCase()); 23532 } // Generate a hash for a tag - does not take attribute order into account 23533 23534 23535 _hashTag(tag, attrs, isVoid) { 23536 const start = `<${tag}`; 23537 const strAttrs = Object.keys(attrs).sort().map(name => ` ${name}=${attrs[name]}`).join(''); 23538 const end = isVoid ? '/>' : `></${tag}>`; 23539 return start + strAttrs + end; 23540 } 23541 23542 _hashClosingTag(tag) { 23543 return this._hashTag(`/${tag}`, {}, false); 23544 } 23545 23546 _generateUniqueName(base) { 23547 const seen = this._placeHolderNameCounts.hasOwnProperty(base); 23548 23549 if (!seen) { 23550 this._placeHolderNameCounts[base] = 1; 23551 return base; 23552 } 23553 23554 const id = this._placeHolderNameCounts[base]; 23555 this._placeHolderNameCounts[base] = id + 1; 23556 return `${base}_${id}`; 23557 } 23558 23559} 23560/** 23561 * @license 23562 * Copyright Google LLC All Rights Reserved. 23563 * 23564 * Use of this source code is governed by an MIT-style license that can be 23565 * found in the LICENSE file at https://angular.io/license 23566 */ 23567 23568 23569const _expParser = new Parser$1(new Lexer()); 23570/** 23571 * Returns a function converting html nodes to an i18n Message given an interpolationConfig 23572 */ 23573 23574 23575function createI18nMessageFactory(interpolationConfig) { 23576 const visitor = new _I18nVisitor(_expParser, interpolationConfig); 23577 return (nodes, meaning, description, customId, visitNodeFn) => visitor.toI18nMessage(nodes, meaning, description, customId, visitNodeFn); 23578} 23579 23580function noopVisitNodeFn(_html, i18n) { 23581 return i18n; 23582} 23583 23584class _I18nVisitor { 23585 constructor(_expressionParser, _interpolationConfig) { 23586 this._expressionParser = _expressionParser; 23587 this._interpolationConfig = _interpolationConfig; 23588 } 23589 23590 toI18nMessage(nodes, meaning = '', description = '', customId = '', visitNodeFn) { 23591 const context = { 23592 isIcu: nodes.length == 1 && nodes[0] instanceof Expansion, 23593 icuDepth: 0, 23594 placeholderRegistry: new PlaceholderRegistry(), 23595 placeholderToContent: {}, 23596 placeholderToMessage: {}, 23597 visitNodeFn: visitNodeFn || noopVisitNodeFn 23598 }; 23599 const i18nodes = visitAll(this, nodes, context); 23600 return new Message(i18nodes, context.placeholderToContent, context.placeholderToMessage, meaning, description, customId); 23601 } 23602 23603 visitElement(el, context) { 23604 const children = visitAll(this, el.children, context); 23605 const attrs = {}; 23606 el.attrs.forEach(attr => { 23607 // Do not visit the attributes, translatable ones are top-level ASTs 23608 attrs[attr.name] = attr.value; 23609 }); 23610 const isVoid = getHtmlTagDefinition(el.name).isVoid; 23611 const startPhName = context.placeholderRegistry.getStartTagPlaceholderName(el.name, attrs, isVoid); 23612 context.placeholderToContent[startPhName] = { 23613 text: el.startSourceSpan.toString(), 23614 sourceSpan: el.startSourceSpan 23615 };
23616 let closePhName = ''; 23617 23618 if (!isVoid) { 23619 closePhName = context.placeholderRegistry.getCloseTagPlaceholderName(el.name); 23620 context.placeholderToContent[closePhName] = { 23621 text: `</${el.name}>`, 23622 sourceSpan: el.endSourceSpan ?? el.sourceSpan 23623 }; 23624 } 23625 23626 const node = new TagPlaceholder(el.name, attrs, startPhName, closePhName, children, isVoid, el.sourceSpan, el.startSourceSpan, el.endSourceSpan); 23627 return context.visitNodeFn(el, node); 23628 } 23629 23630 visitAttribute(attribute, context) { 23631 const node = attribute.valueTokens === undefined || attribute.valueTokens.length === 1 ? new Text$2(attribute.value, attribute.valueSpan || attribute.sourceSpan) : this._visitTextWithInterpolation(attribute.valueTokens, attribute.valueSpan || attribute.sourceSpan, context, attribute.i18n); 23632 return context.visitNodeFn(attribute, node); 23633 } 23634 23635 visitText(text, context) { 23636 const node = text.tokens.length === 1 ? new Text$2(text.value, text.sourceSpan) : this._visitTextWithInterpolation(text.tokens, text.sourceSpan, context, text.i18n); 23637 return context.visitNodeFn(text, node); 23638 } 23639 23640 visitComment(comment, context) { 23641 return null; 23642 } 23643 23644 visitExpansion(icu, context) { 23645 context.icuDepth++; 23646 const i18nIcuCases = {}; 23647 const i18nIcu = new Icu(icu.switchValue, icu.type, i18nIcuCases, icu.sourceSpan); 23648 icu.cases.forEach(caze => { 23649 i18nIcuCases[caze.value] = new Container(caze.expression.map(node => node.visit(this, context)), caze.expSourceSpan); 23650 }); 23651 context.icuDepth--; 23652 23653 if (context.isIcu || context.icuDepth > 0) { 23654 // Returns an ICU node when: 23655 // - the message (vs a part of the message) is an ICU message, or 23656 // - the ICU message is nested. 23657 const expPh = context.placeholderRegistry.getUniquePlaceholder(`VAR_${icu.type}`); 23658 i18nIcu.expressionPlaceholder = expPh; 23659 context.placeholderToContent[expPh] = { 23660 text: icu.switchValue, 23661 sourceSpan: icu.switchValueSourceSpan 23662 }; 23663 return context.visitNodeFn(icu, i18nIcu); 23664 } // Else returns a placeholder 23665 // ICU placeholders should not be replaced with their original content but with the their 23666 // translations. 23667 // TODO(vicb): add a html.Node -> i18n.Message cache to avoid having to re-create the msg 23668 23669 23670 const phName = context.placeholderRegistry.getPlaceholderName('ICU', icu.sourceSpan.toString()); 23671 context.placeholderToMessage[phName] = this.toI18nMessage([icu], '', '', '', undefined); 23672 const node = new IcuPlaceholder(i18nIcu, phName, icu.sourceSpan); 23673 return context.visitNodeFn(icu, node); 23674 } 23675 23676 visitExpansionCase(_icuCase, _context) { 23677 throw new Error('Unreachable code'); 23678 } 23679 /** 23680 * Convert, text and interpolated tokens up into text and placeholder pieces. 23681 * 23682 * @param tokens The text and interpolated tokens. 23683 * @param sourceSpan The span of the whole of the `text` string. 23684 * @param context The current context of the visitor, used to compute and store placeholders. 23685 * @param previousI18n Any i18n metadata associated with this `text` from a previous pass. 23686 */ 23687 23688 23689 _visitTextWithInterpolation(tokens, sourceSpan, context, previousI18n) { 23690 // Return a sequence of `Text` and `Placeholder` nodes grouped in a `Container`. 23691 const nodes = []; // We will only create a container if there are actually interpolations, 23692 // so this flag tracks that. 23693 23694 let hasInterpolation = false; 23695 23696 for (const token of tokens) { 23697 switch (token.type) { 23698 case 8 23699 /* TokenType.INTERPOLATION */ 23700 : 23701 case 17 23702 /* TokenType.ATTR_VALUE_INTERPOLATION */ 23703 : 23704 hasInterpolation = true; 23705 const expression = token.parts[1]; 23706 const baseName = extractPlaceholderName(expression) || 'INTERPOLATION'; 23707 const phName = context.placeholderRegistry.getPlaceholderName(baseName, expression); 23708 context.placeholderToContent[phName] = { 23709 text: token.parts.join(''), 23710 sourceSpan: token.sourceSpan 23711 }; 23712 nodes.push(new Placeholder(expression, phName, token.sourceSpan)); 23713 break; 23714 23715 default: 23716 if (token.parts[0].length > 0) { 23717 // This token is text or an encoded entity. 23718 // If it is following on from a previous text node then merge it into that node 23719 // Otherwise, if it is following an interpolation, then add a new node. 23720 const previous = nodes[nodes.length - 1]; 23721 23722 if (previous instanceof Text$2) { 23723 previous.value += token.parts[0]; 23724 previous.sourceSpan = new ParseSourceSpan(previous.sourceSpan.start, token.sourceSpan.end, previous.sourceSpan.fullStart, previous.sourceSpan.details); 23725 } else { 23726 nodes.push(new Text$2(token.parts[0], token.sourceSpan)); 23727 } 23728 } 23729 23730 break; 23731 } 23732 } 23733 23734 if (hasInterpolation) { 23735 // Whitespace removal may have invalidated the interpolation source-spans. 23736 reusePreviousSourceSpans(nodes, previousI18n); 23737 return new Container(nodes, sourceSpan); 23738 } else { 23739 return nodes[0]; 23740 } 23741 } 23742 23743} 23744/** 23745 * Re-use the source-spans from `previousI18n` metadata for the `nodes`. 23746 *
23747 * Whitespace removal can invalidate the source-spans of interpolation nodes, so we 23748 * reuse the source-span stored from a previous pass before the whitespace was removed. 23749 * 23750 * @param nodes The `Text` and `Placeholder` nodes to be processed. 23751 * @param previousI18n Any i18n metadata for these `nodes` stored from a previous pass. 23752 */ 23753 23754 23755function reusePreviousSourceSpans(nodes, previousI18n) { 23756 if (previousI18n instanceof Message) { 23757 // The `previousI18n` is an i18n `Message`, so we are processing an `Attribute` with i18n 23758 // metadata. The `Message` should consist only of a single `Container` that contains the 23759 // parts (`Text` and `Placeholder`) to process. 23760 assertSingleContainerMessage(previousI18n); 23761 previousI18n = previousI18n.nodes[0]; 23762 } 23763 23764 if (previousI18n instanceof Container) { 23765 // The `previousI18n` is a `Container`, which means that this is a second i18n extraction pass 23766 // after whitespace has been removed from the AST nodes. 23767 assertEquivalentNodes(previousI18n.children, nodes); // Reuse the source-spans from the first pass. 23768 23769 for (let i = 0; i < nodes.length; i++) { 23770 nodes[i].sourceSpan = previousI18n.children[i].sourceSpan; 23771 } 23772 } 23773} 23774/** 23775 * Asserts that the `message` contains exactly one `Container` node. 23776 */ 23777 23778 23779function assertSingleContainerMessage(message) { 23780 const nodes = message.nodes; 23781 23782 if (nodes.length !== 1 || !(nodes[0] instanceof Container)) { 23783 throw new Error('Unexpected previous i18n message - expected it to consist of only a single `Container` node.'); 23784 } 23785} 23786/** 23787 * Asserts that the `previousNodes` and `node` collections have the same number of elements and 23788 * corresponding elements have the same node type. 23789 */ 23790 23791 23792function assertEquivalentNodes(previousNodes, nodes) { 23793 if (previousNodes.length !== nodes.length) { 23794 throw new Error('The number of i18n message children changed between first and second pass.'); 23795 } 23796 23797 if (previousNodes.some((node, i) => nodes[i].constructor !== node.constructor)) { 23798 throw new Error('The types of the i18n message children changed between first and second pass.'); 23799 } 23800} 23801 23802const _CUSTOM_PH_EXP = /\/\/[\s\S]*i18n[\s\S]*\([\s\S]*ph[\s\S]*=[\s\S]*("|')([\s\S]*?)\1[\s\S]*\)/g; 23803 23804function extractPlaceholderName(input) { 23805 return input.split(_CUSTOM_PH_EXP)[2]; 23806} 23807/** 23808 * @license 23809 * Copyright Google LLC All Rights Reserved. 23810 * 23811 * Use of this source code is governed by an MIT-style license that can be 23812 * found in the LICENSE file at https://angular.io/license 23813 */ 23814 23815/** 23816 * An i18n error. 23817 */ 23818 23819 23820class I18nError extends ParseError { 23821 constructor(span, msg) { 23822 super(span, msg); 23823 } 23824 23825} 23826/** 23827 * @license 23828 * Copyright Google LLC All Rights Reserved. 23829 * 23830 * Use of this source code is governed by an MIT-style license that can be 23831 * found in the LICENSE file at https://angular.io/license 23832 */ 23833 23834 23835const setI18nRefs = (htmlNode, i18nNode) => { 23836 if (htmlNode instanceof NodeWithI18n) { 23837 if (i18nNode instanceof IcuPlaceholder && htmlNode.i18n instanceof Message) { 23838 // This html node represents an ICU but this is a second processing pass, and the legacy id 23839 // was computed in the previous pass and stored in the `i18n` property as a message. 23840 // We are about to wipe out that property so capture the previous message to be reused when 23841 // generating the message for this ICU later. See `_generateI18nMessage()`. 23842 i18nNode.previousMessage = htmlNode.i18n; 23843 } 23844 23845 htmlNode.i18n = i18nNode; 23846 } 23847 23848 return i18nNode; 23849}; 23850/** 23851 * This visitor walks over HTML parse tree and converts information stored in 23852 * i18n-related attributes ("i18n" and "i18n-*") into i18n meta object that is 23853 * stored with other element's and attribute's information. 23854 */ 23855 23856 23857class I18nMetaVisitor { 23858 constructor(interpolationConfig = DEFAULT_INTERPOLATION_CONFIG, keepI18nAttrs = false, enableI18nLegacyMessageIdFormat = false) { 23859 this.interpolationConfig = interpolationConfig; 23860 this.keepI18nAttrs = keepI18nAttrs; 23861 this.enableI18nLegacyMessageIdFormat = enableI18nLegacyMessageIdFormat; // whether visited nodes contain i18n information 23862 23863 this.hasI18nMeta = false;
23864 this._errors = []; // i18n message generation factory 23865 23866 this._createI18nMessage = createI18nMessageFactory(this.interpolationConfig); 23867 } 23868 23869 _generateI18nMessage(nodes, meta = '', visitNodeFn) { 23870 const { 23871 meaning, 23872 description, 23873 customId 23874 } = this._parseMetadata(meta); 23875 23876 const message = this._createI18nMessage(nodes, meaning, description, customId, visitNodeFn); 23877 23878 this._setMessageId(message, meta); 23879 23880 this._setLegacyIds(message, meta); 23881 23882 return message; 23883 } 23884 23885 visitAllWithErrors(nodes) { 23886 const result = nodes.map(node => node.visit(this, null)); 23887 return new ParseTreeResult(result, this._errors); 23888 } 23889 23890 visitElement(element) { 23891 let message = undefined; 23892 23893 if (hasI18nAttrs(element)) { 23894 this.hasI18nMeta = true; 23895 const attrs = []; 23896 const attrsMeta = {}; 23897 23898 for (const attr of element.attrs) { 23899 if (attr.name === I18N_ATTR) { 23900 // root 'i18n' node attribute 23901 const i18n = element.i18n || attr.value; 23902 message = this._generateI18nMessage(element.children, i18n, setI18nRefs); 23903 23904 if (message.nodes.length === 0) { 23905 // Ignore the message if it is empty. 23906 message = undefined; 23907 } // Store the message on the element 23908 23909 23910 element.i18n = message; 23911 } else if (attr.name.startsWith(I18N_ATTR_PREFIX)) { 23912 // 'i18n-*' attributes 23913 const name = attr.name.slice(I18N_ATTR_PREFIX.length); 23914 23915 if (isTrustedTypesSink(element.name, name)) { 23916 this._reportError(attr, `Translating attribute '${name}' is disallowed for security reasons.`); 23917 } else { 23918 attrsMeta[name] = attr.value; 23919 } 23920 } else { 23921 // non-i18n attributes 23922 attrs.push(attr); 23923 } 23924 } // set i18n meta for attributes 23925 23926 23927 if (Object.keys(attrsMeta).length) { 23928 for (const attr of attrs) { 23929 const meta = attrsMeta[attr.name]; // do not create translation for empty attributes 23930 23931 if (meta !== undefined && attr.value) { 23932 attr.i18n = this._generateI18nMessage([attr], attr.i18n || meta); 23933 } 23934 } 23935 } 23936 23937 if (!this.keepI18nAttrs) { 23938 // update element's attributes, 23939 // keeping only non-i18n related ones 23940 element.attrs = attrs; 23941 } 23942 } 23943 23944 visitAll(this, element.children, message); 23945 return element; 23946 } 23947 23948 visitExpansion(expansion, currentMessage) { 23949 let message; 23950 const meta = expansion.i18n; 23951 this.hasI18nMeta = true; 23952 23953 if (meta instanceof IcuPlaceholder) { 23954 // set ICU placeholder name (e.g. "ICU_1"), 23955 // generated while processing root element contents, 23956 // so we can reference it when we output translation 23957 const name = meta.name; 23958 message = this._generateI18nMessage([expansion], meta); 23959 const icu = icuFromI18nMessage(message); 23960 icu.name = name; 23961 23962 if (currentMessage !== null) { 23963 // Also update the placeholderToMessage map with this new message 23964 currentMessage.placeholderToMessage[name] = message; 23965 } 23966 } else { 23967 // ICU is a top level message, try to use metadata from container element if provided via 23968 // `context` argument. Note: context may not be available for standalone ICUs (without 23969 // wrapping element), so fallback to ICU metadata in this case. 23970 message = this._generateI18nMessage([expansion], currentMessage || meta); 23971 } 23972 23973 expansion.i18n = message; 23974 return expansion; 23975 } 23976 23977 visitText(text) { 23978 return text; 23979 } 23980 23981 visitAttribute(attribute) { 23982 return attribute; 23983 } 23984 23985 visitComment(comment) { 23986 return comment; 23987 } 23988 23989 visitExpansionCase(expansionCase) { 23990 return expansionCase; 23991 } 23992 /** 23993 * Parse the general form `meta` passed into extract the explicit metadata needed to create a 23994 * `Message`. 23995 * 23996 * There are three possibilities for the `meta` variable 23997 * 1) a string from an `i18n` template attribute: parse it to extract the metadata values. 23998 * 2) a `Message` from a previous processing pass: reuse the metadata values in the message. 23999 * 4) other: ignore this and just process the message metadata as normal 24000 * 24001 * @param meta the bucket that holds information about the message 24002 * @returns the parsed metadata. 24003 */ 24004 24005 24006 _parseMetadata(meta) { 24007 return typeof meta === 'string' ? parseI18nMeta(meta) : meta instanceof Message ? meta : {}; 24008 } 24009 /** 24010 * Generate (or restore) message id if not specified already. 24011 */ 24012 24013 24014 _setMessageId(message, meta) { 24015 if (!message.id) { 24016 message.id = meta instanceof Message && meta.id || decimalDigest(message); 24017 } 24018 } 24019 /** 24020 * Update the `message` with a `legacyId` if necessary. 24021 * 24022 * @param message the message whose legacy id should be set 24023 * @param meta information about the message being processed 24024 */ 24025 24026 24027 _setLegacyIds(message, meta) { 24028 if (this.enableI18nLegacyMessageIdFormat) { 24029 message.legacyIds = [computeDigest(message), computeDecimalDigest(message)]; 24030 } else if (typeof meta !== 'string') { 24031 // This occurs if we are doing the 2nd pass after whitespace removal (see `parseTemplate()` in 24032 // `packages/compiler/src/render3/view/template.ts`). 24033 // In that case we want to reuse the legacy message generated in the 1st pass (see 24034 // `setI18nRefs()`). 24035 const previousMessage = meta instanceof Message ? meta : meta instanceof IcuPlaceholder ? meta.previousMessage : undefined; 24036 message.legacyIds = previousMessage ? previousMessage.legacyIds : []; 24037 } 24038 } 24039 24040 _reportError(node, msg) { 24041 this._errors.push(new I18nError(node.sourceSpan, msg)); 24042 } 24043 24044} 24045/** I18n separators for metadata **/ 24046 24047 24048const I18N_MEANING_SEPARATOR = '|'; 24049const I18N_ID_SEPARATOR = '@@'; 24050/** 24051 * Parses i18n metas like:
24052 * - "@@id", 24053 * - "description[@@id]", 24054 * - "meaning|description[@@id]" 24055 * and returns an object with parsed output. 24056 * 24057 * @param meta String that represents i18n meta 24058 * @returns Object with id, meaning and description fields 24059 */ 24060 24061function parseI18nMeta(meta = '') { 24062 let customId; 24063 let meaning; 24064 let description; 24065 meta = meta.trim(); 24066 24067 if (meta) { 24068 const idIndex = meta.indexOf(I18N_ID_SEPARATOR); 24069 const descIndex = meta.indexOf(I18N_MEANING_SEPARATOR); 24070 let meaningAndDesc; 24071 [meaningAndDesc, customId] = idIndex > -1 ? [meta.slice(0, idIndex), meta.slice(idIndex + 2)] : [meta, '']; 24072 [meaning, description] = descIndex > -1 ? [meaningAndDesc.slice(0, descIndex), meaningAndDesc.slice(descIndex + 1)] : ['', meaningAndDesc]; 24073 } 24074 24075 return { 24076 customId, 24077 meaning, 24078 description 24079 }; 24080} // Converts i18n meta information for a message (id, description, meaning) 24081// to a JsDoc statement formatted as expected by the Closure compiler. 24082 24083 24084function i18nMetaToJSDoc(meta) { 24085 const tags = []; 24086 24087 if (meta.description) { 24088 tags.push({ 24089 tagName: "desc" 24090 /* o.JSDocTagName.Desc */ 24091 , 24092 text: meta.description 24093 }); 24094 } else { 24095 // Suppress the JSCompiler warning that a `@desc` was not given for this message. 24096 tags.push({ 24097 tagName: "suppress" 24098 /* o.JSDocTagName.Suppress */ 24099 , 24100 text: '{msgDescriptions}' 24101 }); 24102 } 24103 24104 if (meta.meaning) { 24105 tags.push({ 24106 tagName: "meaning" 24107 /* o.JSDocTagName.Meaning */ 24108 , 24109 text: meta.meaning 24110 }); 24111 } 24112 24113 return jsDocComment(tags); 24114} 24115/** Closure uses `goog.getMsg(message)` to lookup translations */ 24116 24117 24118const GOOG_GET_MSG = 'goog.getMsg'; 24119/** 24120 * Generates a `goog.getMsg()` statement and reassignment. The template: 24121 * 24122 * ```html 24123 * <div i18n>Sent from {{ sender }} to <span class="receiver">{{ receiver }}</span></div> 24124 * ``` 24125 * 24126 * Generates: 24127 * 24128 * ```typescript 24129 * const MSG_FOO = goog.getMsg( 24130 * // Message template. 24131 * 'Sent from {$interpolation} to {$startTagSpan}{$interpolation_1}{$closeTagSpan}.', 24132 * // Placeholder values, set to magic strings which get replaced by the Angular runtime. 24133 * { 24134 * 'interpolation': '\uFFFD0\uFFFD', 24135 * 'startTagSpan': '\uFFFD1\uFFFD', 24136 * 'interpolation_1': '\uFFFD2\uFFFD', 24137 * 'closeTagSpan': '\uFFFD3\uFFFD', 24138 * }, 24139 * // Options bag. 24140 * { 24141 * // Maps each placeholder to the original Angular source code which generates it's value. 24142 * original_code: { 24143 * 'interpolation': '{{ sender }}', 24144 * 'startTagSpan': '<span class="receiver">', 24145 * 'interpolation_1': '{{ receiver }}', 24146 * 'closeTagSpan': '</span>', 24147 * }, 24148 * }, 24149 * ); 24150 * const I18N_0 = MSG_FOO; 24151 * ``` 24152 */ 24153 24154function createGoogleGetMsgStatements(variable$1, message, closureVar, placeholderValues) { 24155 const messageString = serializeI18nMessageForGetMsg(message); 24156 const args = [literal(messageString)]; 24157 24158 if (Object.keys(placeholderValues).length) { 24159 // Message template parameters containing the magic strings replaced by the Angular runtime with 24160 // real data, e.g. `{'interpolation': '\uFFFD0\uFFFD'}`. 24161 args.push(mapLiteral(formatI18nPlaceholderNamesInMap(placeholderValues, true 24162 /* useCamelCase */ 24163 ), true 24164 /* quoted */ 24165 )); // Message options object, which contains original source code for placeholders (as they are 24166 // present in a template, e.g. 24167 // `{original_code: {'interpolation': '{{ name }}', 'startTagSpan': '<span>'}}`. 24168 24169 args.push(mapLiteral({ 24170 original_code: literalMap(Object.keys(placeholderValues).map(param => ({ 24171 key: formatI18nPlaceholderName(param), 24172 quoted: true, 24173 value: message.placeholders[param] ? // Get source span for typical placeholder if it exists. 24174 literal(message.placeholders[param].sourceSpan.toString()) : // Otherwise must be an ICU expression, get it's source span. 24175 literal(message.placeholderToMessage[param].nodes.map(node => node.sourceSpan.toString()).join('')) 24176 }))) 24177 })); 24178 } // /** 24179 // * @desc description of message 24180 // * @meaning meaning of message 24181 // */ 24182 // const MSG_... = goog.getMsg(..); 24183 // I18N_X = MSG_...; 24184 24185 24186 const googGetMsgStmt = closureVar.set(variable(GOOG_GET_MSG).callFn(args)).toConstDecl(); 24187 googGetMsgStmt.addLeadingComment(i18nMetaToJSDoc(message));
24188 const i18nAssignmentStmt = new ExpressionStatement(variable$1.set(closureVar)); 24189 return [googGetMsgStmt, i18nAssignmentStmt]; 24190} 24191/** 24192 * This visitor walks over i18n tree and generates its string representation, including ICUs and 24193 * placeholders in `{$placeholder}` (for plain messages) or `{PLACEHOLDER}` (inside ICUs) format. 24194 */ 24195 24196 24197class GetMsgSerializerVisitor { 24198 formatPh(value) { 24199 return `{$${formatI18nPlaceholderName(value)}}`; 24200 } 24201 24202 visitText(text) { 24203 return text.value; 24204 } 24205 24206 visitContainer(container) { 24207 return container.children.map(child => child.visit(this)).join(''); 24208 } 24209 24210 visitIcu(icu) { 24211 return serializeIcuNode(icu); 24212 } 24213 24214 visitTagPlaceholder(ph) { 24215 return ph.isVoid ? this.formatPh(ph.startName) : `${this.formatPh(ph.startName)}${ph.children.map(child => child.visit(this)).join('')}${this.formatPh(ph.closeName)}`; 24216 } 24217 24218 visitPlaceholder(ph) { 24219 return this.formatPh(ph.name); 24220 } 24221 24222 visitIcuPlaceholder(ph, context) { 24223 return this.formatPh(ph.name); 24224 } 24225 24226} 24227 24228const serializerVisitor = new GetMsgSerializerVisitor(); 24229 24230function serializeI18nMessageForGetMsg(message) { 24231 return message.nodes.map(node => node.visit(serializerVisitor, null)).join(''); 24232} 24233 24234function createLocalizeStatements(variable, message, params) { 24235 const { 24236 messageParts, 24237 placeHolders 24238 } = serializeI18nMessageForLocalize(message); 24239 const sourceSpan = getSourceSpan(message); 24240 const expressions = placeHolders.map(ph => params[ph.text]); 24241 const localizedString$1 = localizedString(message, messageParts, placeHolders, expressions, sourceSpan); 24242 const variableInitialization = variable.set(localizedString$1); 24243 return [new ExpressionStatement(variableInitialization)]; 24244} 24245/** 24246 * This visitor walks over an i18n tree, capturing literal strings and placeholders. 24247 * 24248 * The result can be used for generating the `$localize` tagged template literals. 24249 */ 24250 24251 24252class LocalizeSerializerVisitor { 24253 constructor(placeholderToMessage, pieces) { 24254 this.placeholderToMessage = placeholderToMessage; 24255 this.pieces = pieces; 24256 } 24257 24258 visitText(text) { 24259 if (this.pieces[this.pieces.length - 1] instanceof LiteralPiece) { 24260 // Two literal pieces in a row means that there was some comment node in-between. 24261 this.pieces[this.pieces.length - 1].text += text.value; 24262 } else { 24263 const sourceSpan = new ParseSourceSpan(text.sourceSpan.fullStart, text.sourceSpan.end, text.sourceSpan.fullStart, text.sourceSpan.details); 24264 this.pieces.push(new LiteralPiece(text.value, sourceSpan)); 24265 } 24266 } 24267 24268 visitContainer(container) { 24269 container.children.forEach(child => child.visit(this)); 24270 } 24271 24272 visitIcu(icu) { 24273 this.pieces.push(new LiteralPiece(serializeIcuNode(icu), icu.sourceSpan)); 24274 } 24275 24276 visitTagPlaceholder(ph) { 24277 this.pieces.push(this.createPlaceholderPiece(ph.startName, ph.startSourceSpan ?? ph.sourceSpan)); 24278 24279 if (!ph.isVoid) { 24280 ph.children.forEach(child => child.visit(this)); 24281 this.pieces.push(this.createPlaceholderPiece(ph.closeName, ph.endSourceSpan ?? ph.sourceSpan)); 24282 } 24283 } 24284 24285 visitPlaceholder(ph) { 24286 this.pieces.push(this.createPlaceholderPiece(ph.name, ph.sourceSpan)); 24287 } 24288 24289 visitIcuPlaceholder(ph) { 24290 this.pieces.push(this.createPlaceholderPiece(ph.name, ph.sourceSpan, this.placeholderToMessage[ph.name])); 24291 } 24292 24293 createPlaceholderPiece(name, sourceSpan, associatedMessage) { 24294 return new PlaceholderPiece(formatI18nPlaceholderName(name, 24295 /* useCamelCase */ 24296 false), sourceSpan, associatedMessage); 24297 } 24298 24299} 24300/** 24301 * Serialize an i18n message into two arrays: messageParts and placeholders. 24302 * 24303 * These arrays will be used to generate `$localize` tagged template literals. 24304 * 24305 * @param message The message to be serialized.
24306 * @returns an object containing the messageParts and placeholders. 24307 */ 24308 24309 24310function serializeI18nMessageForLocalize(message) { 24311 const pieces = []; 24312 const serializerVisitor = new LocalizeSerializerVisitor(message.placeholderToMessage, pieces); 24313 message.nodes.forEach(node => node.visit(serializerVisitor)); 24314 return processMessagePieces(pieces); 24315} 24316 24317function getSourceSpan(message) { 24318 const startNode = message.nodes[0]; 24319 const endNode = message.nodes[message.nodes.length - 1]; 24320 return new ParseSourceSpan(startNode.sourceSpan.fullStart, endNode.sourceSpan.end, startNode.sourceSpan.fullStart, startNode.sourceSpan.details); 24321} 24322/** 24323 * Convert the list of serialized MessagePieces into two arrays. 24324 * 24325 * One contains the literal string pieces and the other the placeholders that will be replaced by 24326 * expressions when rendering `$localize` tagged template literals. 24327 * 24328 * @param pieces The pieces to process. 24329 * @returns an object containing the messageParts and placeholders. 24330 */ 24331 24332 24333function processMessagePieces(pieces) { 24334 const messageParts = []; 24335 const placeHolders = []; 24336 24337 if (pieces[0] instanceof PlaceholderPiece) { 24338 // The first piece was a placeholder so we need to add an initial empty message part. 24339 messageParts.push(createEmptyMessagePart(pieces[0].sourceSpan.start)); 24340 } 24341 24342 for (let i = 0; i < pieces.length; i++) { 24343 const part = pieces[i]; 24344 24345 if (part instanceof LiteralPiece) { 24346 messageParts.push(part); 24347 } else { 24348 placeHolders.push(part); 24349 24350 if (pieces[i - 1] instanceof PlaceholderPiece) { 24351 // There were two placeholders in a row, so we need to add an empty message part. 24352 messageParts.push(createEmptyMessagePart(pieces[i - 1].sourceSpan.end)); 24353 } 24354 } 24355 } 24356 24357 if (pieces[pieces.length - 1] instanceof PlaceholderPiece) { 24358 // The last piece was a placeholder so we need to add a final empty message part. 24359 messageParts.push(createEmptyMessagePart(pieces[pieces.length - 1].sourceSpan.end)); 24360 } 24361 24362 return { 24363 messageParts, 24364 placeHolders 24365 }; 24366} 24367 24368function createEmptyMessagePart(location) { 24369 return new LiteralPiece('', new ParseSourceSpan(location, location)); 24370} 24371/** 24372 * @license 24373 * Copyright Google LLC All Rights Reserved. 24374 * 24375 * Use of this source code is governed by an MIT-style license that can be 24376 * found in the LICENSE file at https://angular.io/license 24377 */ 24378// Selector attribute name of `<ng-content>` 24379 24380 24381const NG_CONTENT_SELECT_ATTR = 'select'; // Attribute name of `ngProjectAs`. 24382 24383const NG_PROJECT_AS_ATTR_NAME = 'ngProjectAs'; // Global symbols available only inside event bindings. 24384 24385const EVENT_BINDING_SCOPE_GLOBALS = new Set(['$event']); // List of supported global targets for event listeners 24386 24387const GLOBAL_TARGET_RESOLVERS = new Map([['window', Identifiers.resolveWindow], ['document', Identifiers.resolveDocument], ['body', Identifiers.resolveBody]]); 24388const LEADING_TRIVIA_CHARS = [' ', '\n', '\r', '\t']; // if (rf & flags) { .. } 24389 24390function renderFlagCheckIfStmt(flags, statements) { 24391 return ifStmt(variable(RENDER_FLAGS).bitwiseAnd(literal(flags), null, false), statements); 24392} 24393 24394function prepareEventListenerParameters(eventAst, handlerName = null, scope = null) { 24395 const { 24396 type, 24397 name, 24398 target, 24399 phase, 24400 handler 24401 } = eventAst; 24402 24403 if (target && !GLOBAL_TARGET_RESOLVERS.has(target)) { 24404 throw new Error(`Unexpected global target '${target}' defined for '${name}' event. 24405 Supported list of global targets: ${Array.from(GLOBAL_TARGET_RESOLVERS.keys())}.`); 24406 } 24407 24408 const eventArgumentName = '$event'; 24409 const implicitReceiverAccesses = new Set(); 24410 const implicitReceiverExpr = scope === null || scope.bindingLevel === 0 ? variable(CONTEXT_NAME) : scope.getOrCreateSharedContextVar(0); 24411 const bindingStatements = convertActionBinding(scope, implicitReceiverExpr, handler, 'b', eventAst.handlerSpan, implicitReceiverAccesses, EVENT_BINDING_SCOPE_GLOBALS); 24412 const statements = []; 24413 const variableDeclarations = scope?.variableDeclarations();
24414 const restoreViewStatement = scope?.restoreViewStatement(); 24415 24416 if (variableDeclarations) { 24417 // `variableDeclarations` needs to run first, because 24418 // `restoreViewStatement` depends on the result. 24419 statements.push(...variableDeclarations); 24420 } 24421 24422 statements.push(...bindingStatements); 24423 24424 if (restoreViewStatement) { 24425 statements.unshift(restoreViewStatement); // If there's a `restoreView` call, we need to reset the view at the end of the listener 24426 // in order to avoid a leak. If there's a `return` statement already, we wrap it in the 24427 // call, e.g. `return resetView(ctx.foo())`. Otherwise we add the call as the last statement. 24428 24429 const lastStatement = statements[statements.length - 1]; 24430 24431 if (lastStatement instanceof ReturnStatement) { 24432 statements[statements.length - 1] = new ReturnStatement(invokeInstruction(lastStatement.value.sourceSpan, Identifiers.resetView, [lastStatement.value])); 24433 } else { 24434 statements.push(new ExpressionStatement(invokeInstruction(null, Identifiers.resetView, []))); 24435 } 24436 } 24437 24438 const eventName = type === 1 24439 /* ParsedEventType.Animation */ 24440 ? prepareSyntheticListenerName(name, phase) : name; 24441 const fnName = handlerName && sanitizeIdentifier(handlerName); 24442 const fnArgs = []; 24443 24444 if (implicitReceiverAccesses.has(eventArgumentName)) { 24445 fnArgs.push(new FnParam(eventArgumentName, DYNAMIC_TYPE)); 24446 } 24447 24448 const handlerFn = fn(fnArgs, statements, INFERRED_TYPE, null, fnName); 24449 const params = [literal(eventName), handlerFn]; 24450 24451 if (target) { 24452 params.push(literal(false), // `useCapture` flag, defaults to `false` 24453 importExpr(GLOBAL_TARGET_RESOLVERS.get(target))); 24454 } 24455 24456 return params; 24457} 24458 24459function createComponentDefConsts() { 24460 return { 24461 prepareStatements: [], 24462 constExpressions: [], 24463 i18nVarRefsCache: new Map() 24464 }; 24465} 24466 24467class TemplateDefinitionBuilder { 24468 constructor(constantPool, parentBindingScope, level = 0, contextName, i18nContext, templateIndex, templateName, _namespace, relativeContextFilePath, i18nUseExternalIds, _constants = createComponentDefConsts()) { 24469 this.constantPool = constantPool; 24470 this.level = level; 24471 this.contextName = contextName; 24472 this.i18nContext = i18nContext; 24473 this.templateIndex = templateIndex; 24474 this.templateName = templateName; 24475 this._namespace = _namespace; 24476 this.i18nUseExternalIds = i18nUseExternalIds; 24477 this._constants = _constants; 24478 this._dataIndex = 0; 24479 this._bindingContext = 0; 24480 this._prefixCode = []; 24481 /** 24482 * List of callbacks to generate creation mode instructions. We store them here as we process 24483 * the template so bindings in listeners are resolved only once all nodes have been visited. 24484 * This ensures all local refs and context variables are available for matching. 24485 */ 24486 24487 this._creationCodeFns = []; 24488 /** 24489 * List of callbacks to generate update mode instructions. We store them here as we process 24490 * the template so bindings are resolved only once all nodes have been visited. This ensures 24491 * all local refs and context variables are available for matching. 24492 */ 24493 24494 this._updateCodeFns = []; 24495 /** Index of the currently-selected node. */ 24496 24497 this._currentIndex = 0; 24498 /** Temporary variable declarations generated from visiting pipes, literals, etc. */ 24499 24500 this._tempVariables = []; 24501 /** 24502 * List of callbacks to build nested templates. Nested templates must not be visited until 24503 * after the parent template has finished visiting all of its nodes. This ensures that all 24504 * local ref bindings in nested templates are able to find local ref values if the refs 24505 * are defined after the template declaration. 24506 */ 24507 24508 this._nestedTemplateFns = []; // i18n context local to this template 24509 24510 this.i18n = null; // Number of slots to reserve for pureFunctions 24511 24512 this._pureFunctionSlots = 0; // Number of binding slots 24513 24514 this._bindingSlots = 0; // Projection slots found in the template. Projection slots can distribute projected 24515 // nodes based on a selector, or can just use the wildcard selector to match 24516 // all nodes which aren't matching any selector. 24517 24518 this._ngContentReservedSlots = []; // Number of non-default selectors found in all parent templates of this template. We need to 24519 // track it to properly adjust projection slot index in the `projection` instruction. 24520 24521 this._ngContentSelectorsOffset = 0; // Expression that should be used as implicit receiver when convert
24521ing template 24522 // expressions to output AST. 24523 24524 this._implicitReceiverExpr = null; // These should be handled in the template or element directly. 24525 24526 this.visitReference = invalid; 24527 this.visitVariable = invalid; 24528 this.visitTextAttribute = invalid; 24529 this.visitBoundAttribute = invalid; 24530 this.visitBoundEvent = invalid; 24531 this._bindingScope = parentBindingScope.nestedScope(level); // Turn the relative context file path into an identifier by replacing non-alphanumeric 24532 // characters with underscores. 24533 24534 this.fileBasedI18nSuffix = relativeContextFilePath.replace(/[^A-Za-z0-9]/g, '_') + '_'; 24535 this._valueConverter = new ValueConverter(constantPool, () => this.allocateDataSlot(), numSlots => this.allocatePureFunctionSlots(numSlots), (name, localName, slot, value) => { 24536 this._bindingScope.set(this.level, localName, value); 24537 24538 this.creationInstruction(null, Identifiers.pipe, [literal(slot), literal(name)]); 24539 }); 24540 } 24541 24542 buildTemplateFunction(nodes, variables, ngContentSelectorsOffset = 0, i18n) { 24543 this._ngContentSelectorsOffset = ngContentSelectorsOffset; 24544 24545 if (this._namespace !== Identifiers.namespaceHTML) { 24546 this.creationInstruction(null, this._namespace); 24547 } // Create variable bindings 24548 24549
24550 variables.forEach(v => this.registerContextVariables(v)); // Initiate i18n context in case: 24551 // - this template has parent i18n context 24552 // - or the template has i18n meta associated with it, 24553 // but it's not initiated by the Element (e.g. <ng-template i18n>) 24554 24555 const initI18nContext = this.i18nContext || isI18nRootNode(i18n) && !isSingleI18nIcu(i18n) && !(isSingleElementTemplate(nodes) && nodes[0].i18n === i18n); 24556 const selfClosingI18nInstruction = hasTextChildrenOnly(nodes); 24557 24558 if (initI18nContext) { 24559 this.i18nStart(null, i18n, selfClosingI18nInstruction); 24560 } // This is the initial pass through the nodes of this template. In this pass, we 24561 // queue all creation mode and update mode instructions for generation in the second 24562 // pass. It's necessary to separate the passes to ensure local refs are defined before 24563 // resolving bindings. We also count bindings in this pass as we walk bound expressions. 24564 24565 24566 visitAll$1(this, nodes); // Add total binding count to pure function count so pure function instructions are 24567 // generated with the correct slot offset when update instructions are processed. 24568 24569 this._pureFunctionSlots += this._bindingSlots; // Pipes are walked in the first pass (to enqueue `pipe()` creation instructions and 24570 // `pipeBind` update instructions), so we have to update the slot offsets manually 24571 // to account for bindings. 24572 24573 this._valueConverter.updatePipeSlotOffsets(this._bindingSlots); // Nested templates must be processed before creation instructions so template() 24574 // instructions can be generated with the correct internal const count. 24575 24576 24577 this._nestedTemplateFns.forEach(buildTemplateFn => buildTemplateFn()); // Output the `projectionDef` instruction when some `<ng-content>` tags are present. 24578 // The `projectionDef` instruction is only emitted for the component template and 24579 // is skipped for nested templates (<ng-template> tags). 24580 24581 24582 if (this.level === 0 && this._ngContentReservedSlots.length) { 24583 const parameters = []; // By default the `projectionDef` instructions creates one slot for the wildcard 24584 // selector if no parameters are passed. Therefore we only want to allocate a new 24585 // array for the projection slots if the default projection slot is not sufficient. 24586 24587 if (this._ngContentReservedSlots.length > 1 || this._ngContentReservedSlots[0] !== '*') { 24588 const r3ReservedSlots = this._ngContentReservedSlots.map(s => s !== '*' ? parseSelectorToR3Selector(s) : s); 24589 24590 parameters.push(this.constantPool.getConstLiteral(asLiteral(r3ReservedSlots), true)); 24591 } // Since we accumulate ngContent selectors while processing template elements, 24592 // we *prepend* `projectionDef` to creation instructions block, to put it before 24593 // any `projection` instructions 24594 24595 24596 this.creationInstruction(null, Identifiers.projectionDef, parameters, 24597 /* prepend */ 24598 true); 24599 } 24600 24601 if (initI18nContext) { 24602 this.i18nEnd(null, selfClosingI18nInstruction); 24603 } // Generate all the creation mode instructions (e.g. resolve bindings in listeners) 24604 24605 24606 const creationStatements = getInstructionStatements(this._creationCodeFns); // Generate all the update mode instructions (e.g. resolve property or text bindings) 24607 24608 const updateStatements = getInstructionStatements(this._updateCodeFns); // Variable declaration must occur after binding resolution so we can generate context 24609 // instructions that build on each other. 24610 // e.g. const b = nextContext().$implicit(); const b = nextContext(); 24611 24612 const creationVariables = this._bindingScope.viewSnapshotStatements(); 24613 24614 const updateVariables = this._bindingScope.variableDeclarations().concat(this._tempVariables); 24615 24616 const creationBlock = creationStatements.length > 0 ? [renderFlagCheckIfStmt(1 24617 /* core.RenderFlags.Create */ 24618 , creationVariables.concat(creationStatements))] : []; 24619 const updateBlock = updateStatements.length > 0 ? [renderFlagCheckIfStmt(2 24620 /* core.RenderFlags.Update */ 24621 , updateVariables.concat(updateStatements))] : []; 24622 return fn( // i.e. (rf: RenderFlags, ctx: any) 24623 [new FnParam(RENDER_FLAGS, NUMBER_TYPE), new FnParam(CONTEXT_NAME, null)], [// Temporary variable declarations for query refresh (i.e. let _t: any;) 24624 ...this._prefixCode, // Creating mode (i.e. if (rf & RenderFlags.
24624Create) { ... }) 24625 ...creationBlock, // Binding and refresh mode (i.e. if (rf & RenderFlags.Update) {...}) 24626 ...updateBlock], INFERRED_TYPE, null, this.templateName); 24627 } // LocalResolver 24628 24629 24630 getLocal(name) { 24631 return this._bindingScope.get(name); 24632 } // LocalResolver 24633 24634 24635 notifyImplicitReceiverUse() { 24636 this._bindingScope.notifyImplicitReceiverUse(); 24637 } // LocalResolver 24638 24639 24640 maybeRestoreView() { 24641 this._bindingScope.maybeRestoreView(); 24642 } 24643 24644 i18nTranslate(message, params = {}, ref, transformFn) { 24645 const _ref = ref || this.i18nGenerateMainBlockVar(); // Closure Compiler requires const names to start with `MSG_` but disallows any other const to 24646 // start with `MSG_`. We define a variable starting with `MSG_` just for the `goog.getMsg` call 24647 24648 24649 const closureVar = this.i18nGenerateClosureVar(message.id); 24650 const statements = getTranslationDeclStmts(message, _ref, closureVar, params, transformFn); 24651 24652 this._constants.prepareStatements.push(...statements); 24653 24654 return _ref; 24655 } 24656 24657 registerContextVariables(variable$1) { 24658 const scopedName = this._bindingScope.freshReferenceName(); 24659 24660 const retrievalLevel = this.level; 24661 const lhs = variable(variable$1.name + scopedName); 24662 24663 this._bindingScope.set(retrievalLevel, variable$1.name, lhs, 1 24664 /* DeclarationPriority.CONTEXT */ 24665 , (scope, relativeLevel) => { 24666 let rhs; 24667 24668 if (scope.bindingLevel === retrievalLevel) { 24669 if (scope.isListenerScope() && scope.hasRestoreViewVariable()) { 24670 // e.g. restoredCtx. 24671 // We have to get the context from a view reference, if one is available, because 24672 // the context that was passed in during creation may not be correct anymore. 24673 // For more information see: https://github.com/angular/angular/pull/40360. 24674 rhs = variable(RESTORED_VIEW_CONTEXT_NAME); 24675 scope.notifyRestoredViewContextUse(); 24676 } else { 24677 // e.g. ctx 24678 rhs = variable(CONTEXT_NAME); 24679 } 24680 } else { 24681 const sharedCtxVar = scope.getSharedContextName(retrievalLevel); // e.g. ctx_r0 OR x(2); 24682 24683 rhs = sharedCtxVar ? sharedCtxVar : generateNextContextExpr(relativeLevel); 24684 } // e.g. const $item$ = x(2).$implicit; 24685 24686 24687 return [lhs.set(rhs.prop(variable$1.value || IMPLICIT_REFERENCE)).toConstDecl()]; 24688 }); 24689 } 24690 24691 i18nAppendBindings(expressions) { 24692 if (expressions.length > 0) { 24693 expressions.forEach(expression => this.i18n.appendBinding(expression)); 24694 } 24695 } 24696 24697 i18nBindProps(props) { 24698 const bound = {}; 24699 Object.keys(props).forEach(key => { 24700 const prop = props[key]; 24701 24702 if (prop instanceof Text$3) { 24703 bound[key] = literal(prop.value); 24704 } else { 24705 const value = prop.value.visit(this._valueConverter); 24706 this.allocateBindingSlots(value); 24707 24708 if (value instanceof Interpolation) { 24709 const { 24710 strings, 24711 expressions 24712 } = value; 24713 const { 24714 id, 24715 bindings 24716 } = this.i18n; 24717 const label = assembleI18nBoundString(strings, bindings.size, id); 24718 this.i18nAppendBindings(expressions); 24719 bound[key] = literal(label); 24720 } 24721 } 24722 }); 24723 return bound; 24724 } // Generates top level vars for i18n blocks (i.e. `i18n_N`). 24725 24726 24727 i18nGenerateMainBlockVar() { 24728 return variable(this.constantPool.uniqueName(TRANSLATION_VAR_PREFIX)); 24729 } // Generates vars with Closure-specific names for i18n blocks (i.e. `MSG_XXX`). 24730 24731 24732 i18nGenerateClosureVar(messageId) { 24733 let name; 24734 const suffix = this.fileBasedI18nSuffix.toUpperCase(); 24735 24736 if (this.i18nUseExternalIds) { 24737 const prefix = getTranslationConstPrefix(`EXTERNAL_`); 24738 const uniqueSuffix = this.constantPool.uniqueName(suffix); 24739 name = `${prefix}${sanitizeIdentifier(messageId)}$$${uniqueSuffix}`; 24740 } else { 24741 const prefix = getTranslationConstPrefix(suffix); 24742 name = this.constantPool.uniqueName(prefix); 24743 } 24744 24745 return variable(name); 24746 } 24747 24748 i18nUpdateRef(context) { 24749 const { 24750 icus, 24751 meta, 24752 isRoot, 24753 isResolved, 24754 isEmitted 24755 } = context; 24756 24757 if (isRoot && isResolved && !isEmitted && !isSingleI18nIcu(meta)) {
24758 context.isEmitted = true; 24759 const placeholders = context.getSerializedPlaceholders(); 24760 let icuMapping = {}; 24761 let params = placeholders.size ? placeholdersToParams(placeholders) : {}; 24762 24763 if (icus.size) { 24764 icus.forEach((refs, key) => { 24765 if (refs.length === 1) { 24766 // if we have one ICU defined for a given 24767 // placeholder - just output its reference 24768 params[key] = refs[0]; 24769 } else { 24770 // ... otherwise we need to activate post-processing 24771 // to replace ICU placeholders with proper values 24772 const placeholder = wrapI18nPlaceholder(`${I18N_ICU_MAPPING_PREFIX}${key}`); 24773 params[key] = literal(placeholder); 24774 icuMapping[key] = literalArr(refs); 24775 } 24776 }); 24777 } // translation requires post processing in 2 cases: 24778 // - if we have placeholders with multiple values (ex. `START_DIV`: [�#1�, �#2�, ...]) 24779 // - if we have multiple ICUs that refer to the same placeholder name 24780 24781 24782 const needsPostprocessing = Array.from(placeholders.values()).some(value => value.length > 1) || Object.keys(icuMapping).length; 24783 let transformFn; 24784 24785 if (needsPostprocessing) { 24786 transformFn = raw => { 24787 const args = [raw]; 24788 24789 if (Object.keys(icuMapping).length) { 24790 args.push(mapLiteral(icuMapping, true)); 24791 } 24792 24793 return invokeInstruction(null, Identifiers.i18nPostprocess, args); 24794 }; 24795 } 24796 24797 this.i18nTranslate(meta, params, context.ref, transformFn); 24798 } 24799 } 24800 24801 i18nStart(span = null, meta, selfClosing) { 24802 const index = this.allocateDataSlot(); 24803 this.i18n = this.i18nContext ? this.i18nContext.forkChildContext(index, this.templateIndex, meta) : new I18nContext(index, this.i18nGenerateMainBlockVar(), 0, this.templateIndex, meta); // generate i18nStart instruction 24804 24805 const { 24806 id, 24807 ref 24808 } = this.i18n; 24809 const params = [literal(index), this.addToConsts(ref)]; 24810 24811 if (id > 0) { 24812 // do not push 3rd argument (sub-block id) 24813 // into i18nStart call for top level i18n context 24814 params.push(literal(id)); 24815 } 24816 24817 this.creationInstruction(span, selfClosing ? Identifiers.i18n : Identifiers.i18nStart, params); 24818 } 24819 24820 i18nEnd(span = null, selfClosing) { 24821 if (!this.i18n) { 24822 throw new Error('i18nEnd is executed with no i18n context present'); 24823 } 24824 24825 if (this.i18nContext) { 24826 this.i18nContext.reconcileChildContext(this.i18n); 24827 this.i18nUpdateRef(this.i18nContext); 24828 } else { 24829 this.i18nUpdateRef(this.i18n); 24830 } // setup accumulated bindings 24831 24832 24833 const { 24834 index, 24835 bindings 24836 } = this.i18n; 24837 24838 if (bindings.size) { 24839 for (const binding of bindings) { 24840 // for i18n block, advance to the most recent element index (by taking the current number of 24841 // elements and subtracting one) before invoking `i18nExp` instructions, to make sure the 24842 // necessary lifecycle hooks of components/directives are properly flushed. 24843 this.updateInstructionWithAdvance(this.getConstCount() - 1, span, Identifiers.i18nExp, () => this.convertPropertyBinding(binding)); 24844 } 24845 24846 this.updateInstruction(span, Identifiers.i18nApply, [literal(index)]); 24847 } 24848 24849 if (!selfClosing) { 24850 this.creationInstruction(span, Identifiers.i18nEnd); 24851 } 24852 24853 this.i18n = null; // reset local i18n context 24854 } 24855 24856 i18nAttributesInstruction(nodeIndex, attrs, sourceSpan) { 24857 let hasBindings = false; 24858 const i18nAttrArgs = []; 24859 attrs.forEach(attr => { 24860 const message = attr.i18n; 24861 const converted = attr.value.visit(this._valueConverter); 24862 this.allocateBindingSlots(converted); 24863 24864 if (converted instanceof Interpolation) { 24865 const placeholders = assembleBoundTextPlaceholders(message); 24866 const params = placeholdersToParams(placeholders); 24867 i18nAttrArgs.push(literal(attr.name), this.i18nTranslate(message, params)); 24868 converted.expressions.forEach(expression => { 24869 hasBindings = true; 24870 this.updateInstructionWithAdvance(nodeIndex, sourceSpan, Identifiers.i18nExp, () => this.convertPropertyBinding(expression)); 24871 }); 24872 } 24873 }); 24874 24875 if (i18nAttrArgs.length > 0) { 24876 const index = literal(this.allocateDataSlot()); 24877 const constIndex = this.addToConsts(literalArr(i18nAttrArgs)); 24878 this.creationInstruction(sourceSpan, Identifiers.i18nAttributes, [index, constIndex]); 24879 24880 if (hasBindings) { 24881 this.updateInstruction(sourceSpan, Identifiers.i18nApply, [index]); 24882 } 24883 } 24884 } 24885
24886 getNamespaceInstruction(namespaceKey) { 24887 switch (namespaceKey) { 24888 case 'math': 24889 return Identifiers.namespaceMathML; 24890 24891 case 'svg': 24892 return Identifiers.namespaceSVG; 24893 24894 default: 24895 return Identifiers.namespaceHTML; 24896 } 24897 } 24898 24899 addNamespaceInstruction(nsInstruction, element) { 24900 this._namespace = nsInstruction; 24901 this.creationInstruction(element.startSourceSpan, nsInstruction); 24902 } 24903 /** 24904 * Adds an update instruction for an interpolated property or attribute, such as 24905 * `prop="{{value}}"` or `attr.title="{{value}}"` 24906 */ 24907 24908 24909 interpolatedUpdateInstruction(instruction, elementIndex, attrName, input, value, params) { 24910 this.updateInstructionWithAdvance(elementIndex, input.sourceSpan, instruction, () => [literal(attrName), ...this.getUpdateInstructionArguments(value), ...params]); 24911 } 24912 24913 visitContent(ngContent) { 24914 const slot = this.allocateDataSlot(); 24915 const projectionSlotIdx = this._ngContentSelectorsOffset + this._ngContentReservedSlots.length; 24916 const parameters = [literal(slot)]; 24917 24918 this._ngContentReservedSlots.push(ngContent.selector); 24919 24920 const nonContentSelectAttributes = ngContent.attributes.filter(attr => attr.name.toLowerCase() !== NG_CONTENT_SELECT_ATTR); 24921 const attributes = this.getAttributeExpressions(ngContent.name, nonContentSelectAttributes, [], []); 24922 24923 if (attributes.length > 0) { 24924 parameters.push(literal(projectionSlotIdx), literalArr(attributes)); 24925 } else if (projectionSlotIdx !== 0) { 24926 parameters.push(literal(projectionSlotIdx)); 24927 } 24928 24929 this.creationInstruction(ngContent.sourceSpan, Identifiers.projection, parameters); 24930 24931 if (this.i18n) { 24932 this.i18n.appendProjection(ngContent.i18n, slot); 24933 } 24934 } 24935 24936 visitElement(element) { 24937 const elementIndex = this.allocateDataSlot(); 24938 const stylingBuilder = new StylingBuilder(null); 24939 let isNonBindableMode = false; 24940 const isI18nRootElement = isI18nRootNode(element.i18n) && !isSingleI18nIcu(element.i18n); 24941 const outputAttrs = []; 24942 const [namespaceKey, elementName] = splitNsName(element.name); 24943 const isNgContainer$1 = isNgContainer(element.name); // Handle styling, i18n, ngNonBindable attributes 24944 24945 for (const attr of element.attributes) { 24946 const { 24947 name, 24948 value 24949 } = attr; 24950 24951 if (name === NON_BINDABLE_ATTR) { 24952 isNonBindableMode = true; 24953 } else if (name === 'style') { 24954 stylingBuilder.registerStyleAttr(value); 24955 } else if (name === 'class') { 24956 stylingBuilder.registerClassAttr(value); 24957 } else { 24958 outputAttrs.push(attr); 24959 } 24960 } // Regular element or ng-container creation mode 24961 24962 24963 const parameters = [literal(elementIndex)]; 24964 24965 if (!isNgContainer$1) { 24966 parameters.push(literal(elementName)); 24967 } // Add the attributes 24968 24969 24970 const allOtherInputs = []; 24971 const boundI18nAttrs = []; 24972 element.inputs.forEach(input => { 24973 const stylingInputWasSet = stylingBuilder.registerBoundInput(input); 24974 24975 if (!stylingInputWasSet) { 24976 if (input.type === 0 24977 /* BindingType.Property */ 24978 && input.i18n) { 24979 boundI18nAttrs.push(input); 24980 } else { 24981 allOtherInputs.push(input); 24982 } 24983 } 24984 }); // add attributes for directive and projection matching purposes 24985 24986 const attributes = this.getAttributeExpressions(element.name, outputAttrs, allOtherInputs, element.outputs, stylingBuilder, [], boundI18nAttrs); 24987 parameters.push(this.addAttrsToConsts(attributes)); // local refs (ex.: <div #foo #bar="baz">) 24988 24989 const refs = this.prepareRefsArray(element.references); 24990 parameters.push(this.addToConsts(refs)); 24991 const wasInNamespace = this._namespace; 24992 const currentNamespace = this.getNamespaceInstruction(namespaceKey); // If the namespace is changing now, include an instruction to change it 24993 // during element creation. 24994 24995 if (currentNamespace !== wasInNamespace) { 24996 this.addNamespaceInstruction(currentNamespace, element); 24997 } 24998 24999 if (this.i18n) { 25000 this.i18n.appendElement(element.i18n, elementIndex); 25001 } // Note that we do not append text node instructions and ICUs inside i18n section, 25002 // so we exclude them while calculating whether current element has children 25003 25004 25005 const hasChildren = !isI18nRootElement && this.i18n ? !hasTextChildrenOnly(element.children) : element.children.length > 0; 25006 const createSelfClosingInstruction = !stylingBuilder.hasBindingsWithPipes && element.outputs.length === 0 && boundI18nAttrs.length === 0 && !hasChildren; 25007 const createSelfClosingI18nInstruction = !createSelfClosingInstruction && hasTextChildrenOnly(element.children); 25008 25009 if (createSelfClosingInstruction) { 25010 this.creationInstruction(element.sourceSpan, isNgContainer$1 ? Identifiers.elementContainer : Identifiers.element, trimTrailingNulls(parameters)); 25011 } else { 25012 this.creationInstruction(element.startSourceSpan, isNgContainer$1 ? Identifiers.elementContainerStart : Identifiers.elementStart, trimTrailingNulls(parameters)); 25013 25014 if (isNonBindableMode) { 25015 this.creationInstruction(element.startSourceSpan, Identifiers.disableBindings); 25016 } 25017 25018 if (boundI18nAttrs.length > 0) { 25019 this.i18nAttributesInstruction(elementIndex, boundI18nAttrs, element.startSourceSpan ?? element.sourceSpan); 25020 } // Generate Listeners (outputs) 25021 25022 25023 if (element.outputs.length > 0) { 25024 for (const outputAst of element.outputs) { 25025 this.creationInstruction(outputAst.sourceSpan, Identifiers.listener, this.prepareListenerParameter(element.name, outputAst, elementIndex)); 25026 } 25027 } // Note: it's important to keep i18n/i18nStart instructions after i18nAttributes and 25028 // listeners, to make sure i18nAttributes instruction targets current element at runtime. 25029 25030 25031 if (isI18nRootElement) { 25032 this.i18nStart(element.startSourceSpan, element.i18n, createSelfClosingI18nInstruction); 25033 } 25034 } // the code here will collect all update-level styling instructions and add them to the 25035 // update block of the template function AOT code. Instructions like `styleProp`, 25036 // `styleMap`, `classMap`, `classProp` 25037 // are all generated and assigned in the code below. 25038 25039 25040 const stylingInstructions = stylingBuilder.buildUpdateLevelInstructions(this._valueConverter); 25041 const limit = stylingInstructions.length - 1; 25042 25043 for (let i = 0; i <= limit; i++) { 25044 const instruction = stylingInstructions[i]; 25045 this._bindingSlots += this.processStylingUpdateInstruction(elementIndex, instruction); 25046 } // the reason why `undefined` is used is because the renderer understands this as a 25047 // special value to symbolize that there is no RHS to this binding 25048 // TODO (matsko): revisit this once FW-959 is approached 25049 25050 25051 const emptyValueBindInstruction = literal(undefined); 25052 const propertyBindings = []; 25053 const attributeBindings = []; // Generate element input bindings 25054
25055 allOtherInputs.forEach(input => { 25056 const inputType = input.type; 25057 25058 if (inputType === 4 25059 /* BindingType.Animation */ 25060 ) { 25061 const value = input.value.visit(this._valueConverter); // animation bindings can be presented in the following formats: 25062 // 1. [@binding]="fooExp" 25063 // 2. [@binding]="{value:fooExp, params:{...}}" 25064 // 3. [@binding] 25065 // 4. @binding 25066 // All formats will be valid for when a synthetic binding is created. 25067 // The reasoning for this is because the renderer should get each 25068 // synthetic binding value in the order of the array that they are 25069 // defined in... 25070 25071 const hasValue = value instanceof LiteralPrimitive ? !!value.value : true; 25072 this.allocateBindingSlots(value); 25073 propertyBindings.push({ 25074 span: input.sourceSpan, 25075 paramsOrFn: getBindingFunctionParams(() => hasValue ? this.convertPropertyBinding(value) : emptyValueBindInstruction, prepareSyntheticPropertyName(input.name)) 25076 }); 25077 } else { 25078 // we must skip attributes with associated i18n context, since these attributes are handled 25079 // separately and corresponding `i18nExp` and `i18nApply` instructions will be generated 25080 if (input.i18n) return; 25081 const value = input.value.visit(this._valueConverter); 25082 25083 if (value !== undefined) { 25084 const params = []; 25085 const [attrNamespace, attrName] = splitNsName(input.name); 25086 const isAttributeBinding = inputType === 1 25087 /* BindingType.Attribute */ 25088 ; 25089 let sanitizationRef = resolveSanitizationFn(input.securityContext, isAttributeBinding); 25090 25091 if (!sanitizationRef) { 25092 // If there was no sanitization function found based on the security context 25093 // of an attribute/property - check whether this attribute/property is 25094 // one of the security-sensitive <iframe> attributes (and that the current 25095 // element is actually an <iframe>). 25096 if (isIframeElement(element.name) && isIframeSecuritySensitiveAttr(input.name)) { 25097 sanitizationRef = importExpr(Identifiers.validateIframeAttribute); 25098 } 25099 } 25100 25101 if (sanitizationRef) { 25102 params.push(sanitizationRef); 25103 } 25104 25105 if (attrNamespace) { 25106 const namespaceLiteral = literal(attrNamespace); 25107 25108 if (sanitizationRef) { 25109 params.push(namespaceLiteral); 25110 } else { 25111 // If there wasn't a sanitization ref, we need to add 25112 // an extra param so that we can pass in the namespace. 25113 params.push(literal(null), namespaceLiteral); 25114 } 25115 } 25116 25117 this.allocateBindingSlots(value); 25118 25119 if (inputType === 0 25120 /* BindingType.Property */ 25121 ) { 25122 if (value instanceof Interpolation) { 25123 // prop="{{value}}" and friends 25124 this.interpolatedUpdateInstruction(getPropertyInterpolationExpression(value), elementIndex, attrName, input, value, params); 25125 } else { 25126 // [prop]="value" 25127 // Collect all the properties so that we can chain into a single function at the end. 25128 propertyBindings.push({ 25129 span: input.sourceSpan, 25130 paramsOrFn: getBindingFunctionParams(() => this.convertPropertyBinding(value), attrName, params) 25131 }); 25132 } 25133 } else if (inputType === 1 25134 /* BindingType.Attribute */ 25135 ) { 25136 if (value instanceof Interpolation && getInterpolationArgsLength(value) > 1) { 25137 // attr.name="text{{value}}" and friends 25138 this.interpolatedUpdateInstruction(getAttributeInterpolationExpression(value), elementIndex, attrName, input, value, params); 25139 } else { 25140 const boundValue = value instanceof Interpolation ? value.expressions[0] : value; // [attr.name]="value" or attr.name="{{value}}" 25141 // Collect the attribute bindings so that they can be chained at the end. 25142 25143 attributeBindings.push({
25144 span: input.sourceSpan, 25145 paramsOrFn: getBindingFunctionParams(() => this.convertPropertyBinding(boundValue), attrName, params) 25146 }); 25147 } 25148 } else { 25149 // class prop 25150 this.updateInstructionWithAdvance(elementIndex, input.sourceSpan, Identifiers.classProp, () => { 25151 return [literal(elementIndex), literal(attrName), this.convertPropertyBinding(value), ...params]; 25152 }); 25153 } 25154 } 25155 } 25156 }); 25157 25158 for (const propertyBinding of propertyBindings) { 25159 this.updateInstructionWithAdvance(elementIndex, propertyBinding.span, Identifiers.property, propertyBinding.paramsOrFn); 25160 } 25161 25162 for (const attributeBinding of attributeBindings) { 25163 this.updateInstructionWithAdvance(elementIndex, attributeBinding.span, Identifiers.attribute, attributeBinding.paramsOrFn); 25164 } // Traverse element child nodes 25165 25166 25167 visitAll$1(this, element.children); 25168 25169 if (!isI18nRootElement && this.i18n) { 25170 this.i18n.appendElement(element.i18n, elementIndex, true); 25171 } 25172 25173 if (!createSelfClosingInstruction) { 25174 // Finish element construction mode. 25175 const span = element.endSourceSpan ?? element.sourceSpan; 25176 25177 if (isI18nRootElement) { 25178 this.i18nEnd(span, createSelfClosingI18nInstruction); 25179 } 25180 25181 if (isNonBindableMode) { 25182 this.creationInstruction(span, Identifiers.enableBindings); 25183 } 25184 25185 this.creationInstruction(span, isNgContainer$1 ? Identifiers.elementContainerEnd : Identifiers.elementEnd); 25186 } 25187 } 25188 25189 visitTemplate(template) { 25190 const NG_TEMPLATE_TAG_NAME = 'ng-template'; 25191 const templateIndex = this.allocateDataSlot(); 25192 25193 if (this.i18n) { 25194 this.i18n.appendTemplate(template.i18n, templateIndex); 25195 } 25196 25197 const tagNameWithoutNamespace = template.tagName ? splitNsName(template.tagName)[1] : template.tagName; 25198 const contextName = `${this.contextName}${template.tagName ? '_' + sanitizeIdentifier(template.tagName) : ''}_${templateIndex}`; 25199 const templateName = `${contextName}_Template`; 25200 const parameters = [literal(templateIndex), variable(templateName), // We don't care about the tag's namespace here, because we infer 25201 // it based on the parent nodes inside the template instruction. 25202 literal(tagNameWithoutNamespace)]; // prepare attributes parameter (including attributes used for directive matching) 25203 25204 const attrsExprs = this.getAttributeExpressions(NG_TEMPLATE_TAG_NAME, template.attributes, template.inputs, template.outputs, undefined 25205 /* styles */ 25206 , template.templateAttrs); 25207 parameters.push(this.addAttrsToConsts(attrsExprs)); // local refs (ex.: <ng-template #foo>) 25208 25209 if (template.references && template.references.length) { 25210 const refs = this.prepareRefsArray(template.references); 25211 parameters.push(this.addToConsts(refs)); 25212 parameters.push(importExpr(Identifiers.templateRefExtractor)); 25213 } // Create the template function 25214 25215 25216 const templateVisitor = new TemplateDefinitionBuilder(this.constantPool, this._bindingScope, this.level + 1, contextName, this.i18n, templateIndex, templateName, this._namespace, this.fileBasedI18nSuffix, this.i18nUseExternalIds, this._constants); // Nested templates must not be visited until after their parent templates have completed 25217 // processing, so they are queued here until after the initial pass. Otherwise, we wouldn't 25218 // be able to support bindings in nested templates to local refs that occur after the 25219 // template definition. e.g. <div *ngIf="showing">{{ foo }}</div> <div #foo></div> 25220 25221 this._nestedTemplateFns.push(() => { 25222 const templateFunctionExpr = templateVisitor.buildTemplateFunction(template.children, template.variables, this._ngContentReservedSlots.length + this._ngContentSelectorsOffset, template.i18n); 25223 this.constantPool.statements.push(templateFunctionExpr.toDeclStmt(templateName)); 25224 25225 if (templateVisitor._ngContentReservedSlots.length) { 25226 this._ngContentReservedSlots.push(...templateVisitor._ngContentReservedSlots); 25227 } 25228 }); // e.g. template(1, MyComp_Template_1) 25229 25230 25231 this.creationInstruction(template.sourceSpan, Identifiers.templateCreate, () => { 25232 parameters.splice(2, 0, literal(templateVisitor.getConstCount()), literal(templateVisitor.getVarCount())); 25233 return trimTrailingNulls(parameters); 25234 }); // handle property bindings e.g. ɵɵproperty('ngForOf', ctx.items), et al; 25235 25236 this.templatePropertyBindings(templateIndex, template.templateAttrs); // Only add normal input/output binding instructions on explicit <ng-template> elements. 25237 25238 if (tagNameWithoutNamespace === NG_TEMPLATE_TAG_NAME) { 25239 const [i18nInputs, inputs] = partitionArray(template.inputs, hasI18nMeta); // Add i18n attributes that may act as inputs to directives. If such attributes are present, 25240 // generate `i18nAttributes` instruction. Note: we generate it only for explicit <ng-template> 25241 // elements, in case of inline templates, corresponding instructions will be generated in the 25242 // nested template function. 25243 25244 if (i18nInputs.length > 0) { 25245 this.i18nAttributesInstruction(templateIndex, i18nInputs, template.startSourceSpan ?? template.sourceSpan); 25246 } // Add the input bindings 25247 25248 25249 if (inputs.length > 0) { 25250 this.templatePropertyBindings(templateIndex, inputs); 25251 } // Generate listeners for directive output 25252 25253 25254 for (const outputAst of template.outputs) { 25255 this.creationInstruction(outputAst.sourceSpan, Identifiers.listener, this.prepareListenerParameter('ng_template', outputAst, templateIndex)); 25256 } 25257 } 25258 } 25259 25260 visitBoundText(text) { 25261 if (this.i18n) { 25262 const value = text.value.visit(this._valueConverter); 25263 this.allocateBindingSlots(value); 25264 25265 if (value instanceof Interpolation) { 25266 this.i18n.appendBoundText(text.i18n); 25267 this.i18nAppendBindings(value.expressions); 25268 } 25269 25270 return; 25271 } 25272 25273 const nodeIndex = this.allocateDataSlot(); 25274 this.creationInstruction(text.sourceSpan, Identifiers.text, [literal(nodeIndex)]); 25275 const value = text.value.visit(this._valueConverter); 25276 this.allocateBindingSlots(value); 25277 25278 if (value instanceof Interpolation) { 25279 this.updateInstructionWithAdvance(nodeIndex, text.sourceSpan, getTextInterpolationExpression(value), () => this.getUpdateInstructionArguments(value)); 25280 } else { 25281 error('Text nodes should be interpolated and never bound directly.'); 25282 } 25283 } 25284 25285 visitText(text) { 25286 // when a text element is located within a translatable 25287 // block, we exclude this text element from instructions set, 25288 // since it will be captured in i18n content and processed at runtime 25289 if (!this.i18n) { 25290 this.creationInstruction(text.sourceSpan, Identifiers.text, [literal(this.allocateDataSlot()), literal(text.value)]); 25291 } 25292 } 25293 25294 visitIcu(icu) { 25295 let initWasInvoked = false; // if an ICU was created outside of i18n block, we still treat 25296 // it as a translatable entity and invoke i18nStart and i18nEnd 25297 // to generate i18n context and the necessary instructions 25298 25299 if (!this.i18n) { 25300 initWasInvoked = true; 25301 this.i18nStart(null, icu.i18n, true); 25302 } 25303 25304 const i18n = this.i18n;
25305 const vars = this.i18nBindProps(icu.vars); 25306 const placeholders = this.i18nBindProps(icu.placeholders); // output ICU directly and keep ICU reference in context 25307 25308 const message = icu.i18n; // we always need post-processing function for ICUs, to make sure that: 25309 // - all placeholders in a form of {PLACEHOLDER} are replaced with actual values (note: 25310 // `goog.getMsg` does not process ICUs and uses the `{PLACEHOLDER}` format for placeholders 25311 // inside ICUs) 25312 // - all ICU vars (such as `VAR_SELECT` or `VAR_PLURAL`) are replaced with correct values 25313 25314 const transformFn = raw => { 25315 const params = { ...vars, 25316 ...placeholders 25317 }; 25318 const formatted = formatI18nPlaceholderNamesInMap(params, 25319 /* useCamelCase */ 25320 false); 25321 return invokeInstruction(null, Identifiers.i18nPostprocess, [raw, mapLiteral(formatted, true)]); 25322 }; // in case the whole i18n message is a single ICU - we do not need to 25323 // create a separate top-level translation, we can use the root ref instead 25324 // and make this ICU a top-level translation 25325 // note: ICU placeholders are replaced with actual values in `i18nPostprocess` function 25326 // separately, so we do not pass placeholders into `i18nTranslate` function. 25327 25328 25329 if (isSingleI18nIcu(i18n.meta)) { 25330 this.i18nTranslate(message, 25331 /* placeholders */ 25332 {}, i18n.ref, transformFn); 25333 } else { 25334 // output ICU directly and keep ICU reference in context 25335 const ref = this.i18nTranslate(message, 25336 /* placeholders */ 25337 {}, 25338 /* ref */ 25339 undefined, transformFn); 25340 i18n.appendIcu(icuFromI18nMessage(message).name, ref); 25341 } 25342 25343 if (initWasInvoked) { 25344 this.i18nEnd(null, true); 25345 } 25346 25347 return null; 25348 } 25349 25350 allocateDataSlot() { 25351 return this._dataIndex++; 25352 } 25353 25354 getConstCount() { 25355 return this._dataIndex; 25356 } 25357 25358 getVarCount() { 25359 return this._pureFunctionSlots; 25360 } 25361 25362 getConsts() { 25363 return this._constants; 25364 } 25365 25366 getNgContentSelectors() { 25367 return this._ngContentReservedSlots.length ? this.constantPool.getConstLiteral(asLiteral(this._ngContentReservedSlots), true) : null; 25368 } 25369 25370 bindingContext() { 25371 return `${this._bindingContext++}`; 25372 } 25373 25374 templatePropertyBindings(templateIndex, attrs) { 25375 const propertyBindings = []; 25376 25377 for (const input of attrs) { 25378 if (!(input instanceof BoundAttribute)) { 25379 continue; 25380 } 25381 25382 const value = input.value.visit(this._valueConverter); 25383 25384 if (value === undefined) { 25385 continue; 25386 } 25387 25388 this.allocateBindingSlots(value); 25389 25390 if (value instanceof Interpolation) { 25391 // Params typically contain attribute namespace and value sanitizer, which is applicable 25392 // for regular HTML elements, but not applicable for <ng-template> (since props act as 25393 // inputs to directives), so keep params array empty. 25394 const params = []; // prop="{{value}}" case 25395 25396 this.interpolatedUpdateInstruction(getPropertyInterpolationExpression(value), templateIndex, input.name, input, value, params); 25397 } else { 25398 // [prop]="value" case 25399 propertyBindings.push({ 25400 span: input.sourceSpan, 25401 paramsOrFn: getBindingFunctionParams(() => this.convertPropertyBinding(value), input.name) 25402 }); 25403 } 25404 } 25405 25406 for (const propertyBinding of propertyBindings) { 25407 this.updateInstructionWithAdvance(templateIndex, propertyBinding.span, Identifiers.property, propertyBinding.paramsOrFn); 25408 } 25409 } // Bindings must only be resolved after all local refs have been visited, so all 25410 // instructions are queued in callbacks that execute once the initial pass has completed. 25411 // Otherwise, we wouldn't be able to support local refs that are defined after their 25412 // bindings. e.g. {{ foo }} <div #foo></div> 25413 25414 25415 instructionFn(fns, span, reference, paramsOrFn, prepend = false) { 25416 fns[prepend ? 'unshift' : 'push']({ 25417 span, 25418 reference, 25419 paramsOrFn 25420 }); 25421 } 25422 25423 processStylingUpdateInstruction(elementIndex, instruction) { 25424 let allocateBindingSlots = 0; 25425 25426 if (instruction) { 25427 for (const call of instruction.calls) { 25428 allocateBindingSlots += call.allocateBindingSlots; 25429 this.updateInstructionWithAdvance(elementIndex, call.sourceSpan, instruction.reference, () => call.params(value =>
25429 call.supportsInterpolation && value instanceof Interpolation ? this.getUpdateInstructionArguments(value) : this.convertPropertyBinding(value))); 25430 } 25431 } 25432 25433 return allocateBindingSlots; 25434 } 25435 25436 creationInstruction(span, reference, paramsOrFn, prepend) { 25437 this.instructionFn(this._creationCodeFns, span, reference, paramsOrFn || [], prepend); 25438 } 25439 25440 updateInstructionWithAdvance(nodeIndex, span, reference, paramsOrFn) { 25441 this.addAdvanceInstructionIfNecessary(nodeIndex, span); 25442 this.updateInstruction(span, reference, paramsOrFn); 25443 } 25444 25445 updateInstruction(span, reference, paramsOrFn) { 25446 this.instructionFn(this._updateCodeFns, span, reference, paramsOrFn || []); 25447 } 25448 25449 addAdvanceInstructionIfNecessary(nodeIndex, span) { 25450 if (nodeIndex !== this._currentIndex) { 25451 const delta = nodeIndex - this._currentIndex; 25452 25453 if (delta < 1) { 25454 throw new Error('advance instruction can only go forwards'); 25455 } 25456 25457 this.instructionFn(this._updateCodeFns, span, Identifiers.advance, [literal(delta)]); 25458 this._currentIndex = nodeIndex; 25459 } 25460 } 25461 25462 allocatePureFunctionSlots(numSlots) { 25463 const originalSlots = this._pureFunctionSlots; 25464 this._pureFunctionSlots += numSlots; 25465 return originalSlots; 25466 } 25467 25468 allocateBindingSlots(value) { 25469 this._bindingSlots += value instanceof Interpolation ? value.expressions.length : 1; 25470 } 25471 /** 25472 * Gets an expression that refers to the implicit receiver. The implicit 25473 * receiver is always the root level context. 25474 */ 25475 25476 25477 getImplicitReceiverExpr() { 25478 if (this._implicitReceiverExpr) { 25479 return this._implicitReceiverExpr; 25480 } 25481 25482 return this._implicitReceiverExpr = this.level === 0 ? variable(CONTEXT_NAME) : this._bindingScope.getOrCreateSharedContextVar(0); 25483 } 25484 25485 convertPropertyBinding(value) { 25486 const convertedPropertyBinding = convertPropertyBinding(this, this.getImplicitReceiverExpr(), value, this.bindingContext()); 25487 const valExpr = convertedPropertyBinding.currValExpr; 25488 25489 this._tempVariables.push(...convertedPropertyBinding.stmts); 25490 25491 return valExpr; 25492 } 25493 /** 25494 * Gets a list of argument expressions to pass to an update instruction expression. Also updates 25495 * the temp variables state with temp variables that were identified as needing to be created 25496 * while visiting the arguments. 25497 * @param value The original expression we will be resolving an arguments list from. 25498 */ 25499 25500 25501 getUpdateInstructionArguments(value) { 25502 const { 25503 args, 25504 stmts 25505 } = convertUpdateArguments(this, this.getImplicitReceiverExpr(), value, this.bindingContext()); 25506 25507 this._tempVariables.push(...stmts); 25508 25509 return args; 25510 } 25511 /** 25512 * Prepares all attribute expression values for the `TAttributes` array. 25513 * 25514 * The purpose of this function is to properly construct an attributes array that 25515 * is passed into the `elementStart` (or just `element`) functions. Because there 25516 * are many different types of attributes, the array needs to be constructed in a 25517 * special way so that `elementStart` can properly evaluate them. 25518 * 25519 * The format looks like this: 25520 * 25521 * ``` 25522 * attrs = [prop, value, prop2, value2, 25523 * PROJECT_AS, selector, 25524 * CLASSES, class1, class2, 25525 * STYLES, style1, value1, style2, value2, 25526 * BINDINGS, name1, name2, name3, 25527 * TEMPLATE, name4, name5, name6, 25528 * I18N, name7, name8, ...] 25529 * ``` 25530 * 25531 * Note that this function will fully ignore all synthetic (@foo) attribute values 25532 * because those values are intended to always be generated as property instructions. 25533 */ 25534 25535 25536 getAttributeExpressions(elementName, renderAttributes, inputs, outputs, styles, templateAttrs = [], boundI18nAttrs = []) { 25537 const alreadySeen = new Set(); 25538 const attrExprs = []; 25539 let ngProjectAsAttr; 25540 25541 for (const attr of renderAttributes) { 25542 if (attr.name === NG_PROJECT_AS_ATTR_NAME) { 25543 ngProjectAsAttr = attr; 25544 } // Note that static i18n attributes aren't in the i18n array, 25545 // because they're treated in the same way as regular attributes. 25546 25547 25548 if (attr.i18n) { 25549 // When i18n attributes are present on elements with structural directives 25550 // (e.g. `<div *ngIf title="Hello" i18n-title>`), we want to avoid generating 25551 // duplicate i18n translation blocks for `ɵɵtemplate` and `ɵɵelement` instruction 25552 // attributes. So we do a cache lookup to see if suitable i18n translation block 25553 // already exists. 25554 const { 25555 i18nVarRefsCache 25556 } = this._constants; 25557 let i18nVarRef; 25558 25559 if (i18nVarRefsCache.has(attr.i18n)) { 25560 i18nVarRef = i18nVarRefsCache.get(attr.i18n); 25561 } else { 25562 i18nVarRef = this.i18nTranslate(attr.i18n); 25563 i18nVarRefsCache.set(attr.i18n, i18nVarRef); 25564 } 25565
25566 attrExprs.push(literal(attr.name), i18nVarRef); 25567 } else { 25568 attrExprs.push(...getAttributeNameLiterals(attr.name), trustedConstAttribute(elementName, attr)); 25569 } 25570 } // Keep ngProjectAs next to the other name, value pairs so we can verify that we match 25571 // ngProjectAs marker in the attribute name slot. 25572 25573 25574 if (ngProjectAsAttr) { 25575 attrExprs.push(...getNgProjectAsLiteral(ngProjectAsAttr)); 25576 } 25577 25578 function addAttrExpr(key, value) { 25579 if (typeof key === 'string') { 25580 if (!alreadySeen.has(key)) { 25581 attrExprs.push(...getAttributeNameLiterals(key)); 25582 value !== undefined && attrExprs.push(value); 25583 alreadySeen.add(key); 25584 } 25585 } else { 25586 attrExprs.push(literal(key)); 25587 } 25588 } // it's important that this occurs before BINDINGS and TEMPLATE because once `elementStart` 25589 // comes across the BINDINGS or TEMPLATE markers then it will continue reading each value as 25590 // as single property value cell by cell. 25591 25592 25593 if (styles) { 25594 styles.populateInitialStylingAttrs(attrExprs); 25595 } 25596 25597 if (inputs.length || outputs.length) { 25598 const attrsLengthBeforeInputs = attrExprs.length; 25599 25600 for (let i = 0; i < inputs.length; i++) { 25601 const input = inputs[i]; // We don't want the animation and attribute bindings in the 25602 // attributes array since they aren't used for directive matching. 25603 25604 if (input.type !== 4 25605 /* BindingType.Animation */ 25606 && input.type !== 1 25607 /* BindingType.Attribute */ 25608 ) { 25609 addAttrExpr(input.name); 25610 } 25611 } 25612 25613 for (let i = 0; i < outputs.length; i++) { 25614 const output = outputs[i]; 25615 25616 if (output.type !== 1 25617 /* ParsedEventType.Animation */ 25618 ) { 25619 addAttrExpr(output.name); 25620 } 25621 } // this is a cheap way of adding the marker only after all the input/output 25622 // values have been filtered (by not including the animation ones) and added 25623 // to the expressions. The marker is important because it tells the runtime 25624 // code that this is where attributes without values start... 25625 25626 25627 if (attrExprs.length !== attrsLengthBeforeInputs) { 25628 attrExprs.splice(attrsLengthBeforeInputs, 0, literal(3 25629 /* core.AttributeMarker.Bindings */ 25630 )); 25631 } 25632 } 25633 25634 if (templateAttrs.length) { 25635 attrExprs.push(literal(4 25636 /* core.AttributeMarker.Template */ 25637 )); 25638 templateAttrs.forEach(attr => addAttrExpr(attr.name)); 25639 } 25640 25641 if (boundI18nAttrs.length) { 25642 attrExprs.push(literal(6 25643 /* core.AttributeMarker.I18n */ 25644 )); 25645 boundI18nAttrs.forEach(attr => addAttrExpr(attr.name)); 25646 } 25647 25648 return attrExprs; 25649 } 25650 25651 addToConsts(expression) { 25652 if (isNull(expression)) { 25653 return TYPED_NULL_EXPR; 25654 } 25655 25656 const consts = this._constants.constExpressions; // Try to reuse a literal that's already in the array, if possible. 25657 25658 for (let i = 0; i < consts.length; i++) { 25659 if (consts[i].isEquivalent(expression)) { 25660 return literal(i); 25661 } 25662 } 25663 25664 return literal(consts.push(expression) - 1); 25665 } 25666 25667 addAttrsToConsts(attrs) { 25668 return attrs.length > 0 ? this.addToConsts(literalArr(attrs)) : TYPED_NULL_EXPR; 25669 } 25670 25671 prepareRefsArray(references) { 25672 if (!references || references.length === 0) { 25673 return TYPED_NULL_EXPR; 25674 } 25675 25676 const refsParam = flatten(references.map(reference => { 25677 const slot = this.allocateDataSlot(); // Generate the update temporary. 25678 25679 const variableName = this._bindingScope.freshReferenceName(); 25680 25681 const retrievalLevel = this.level; 25682 const lhs = variable(variableName); 25683 25684 this._bindingScope.set(retrievalLevel, reference.name, lhs, 0 25685 /* DeclarationPriority.DEFAULT */ 25686 , (scope, relativeLevel) => { 25687 // e.g. nextContext(2); 25688 const nextContextStmt = relativeLevel > 0 ? [generateNextContextExpr(relativeLevel).toStmt()] : []; // e.g. const $foo$ = reference(1); 25689 25690 const refExpr = lhs.set(importExpr(Identifiers.reference).callFn([literal(slot)])); 25691 return nextContextStmt.concat(refExpr.toConstDecl()); 25692 }, true); 25693 25694 return [reference.name, reference.value]; 25695 })); 25696 return asLiteral(refsParam); 25697 } 25698 25699 prepareListenerParameter(tagName, outputAst, index) { 25700 return () => { 25701 const eventName = outputAst.name; 25702 const bindingFnName = outputAst.type === 1 25703 /* ParsedEventType.Animation */ 25704 ? // synthetic @listener.foo values are treated the exact same as are standard listeners 25705 prepareSyntheticListenerFunctionName(eventName, outputAst.phase) : sanitizeIdentifier(eventName); 25706 const handlerName = `${this.templateName}_${tagName}_${bindingFnName}_${index}_listener`; 25707 25708 const scope = this._bindingScope.nestedScope(this._bindingScope.bindingLevel, EVENT_BINDING_SCOPE_GLOBALS); 25709 25710 return prepareEventListenerParameters(outputAst, handlerName, scope); 25711 }; 25712 } 25713 25714} 25715 25716class ValueConverter extends AstMemoryEfficientTransformer { 25717 constructor(constantPool, allocateSlot, allocatePureFunctionSlots, definePipe) { 25718 super(); 25719 this.constantPool = constantPool; 25720 this.allocateSlot = allocateSlot; 25721 this.allocatePureFunctionSlots = allocatePureFunctionSlots; 25722 this.definePipe = definePipe; 25723 this._pipeBindExprs = []; 25724 } // AstMemoryEfficientTransformer 25725 25726 25727 visitPipe(pipe, context) { 25728 // Allocate a slot to create the pipe 25729 const slot = this.allocateSlot(); 25730 const slotPseudoLocal = `PIPE:${slot}`; // Allocate one slot for the result plus one slot per pipe argument 25731 25732 const pureFunctionSlot = this.allocatePureFunctionSlots(2 + pipe.args.length); 25733 const target = new PropertyRead(pipe.span, pipe.sourceSpan, pipe.nameSpan, new ImplicitReceiver(pipe.span, pipe.sourceSpan), slotPseudoLocal); 25734 const { 25735 identifier, 25736 isVarLength 25737 } = pipeBindingCallInfo(pipe.args); 25738 this.definePipe(pipe.name, slotPseudoLocal, slot, importExpr(identifier)); 25739 const args = [pipe.exp, ...pipe.args]; 25740 const convertedArgs = isVarLength ? this.visitAll([new LiteralArray(pipe.span, pipe.sourceSpan, args)]) : this.visitAll(args); 25741 const pipeBindExpr = new Call(pipe.span, pipe.sourceSpan, target, [new LiteralPrimitive(pipe.span, pipe.sourceSpan, slot), new LiteralPrimitive(pipe.span, pipe.sourceSpan, pureFunctionSlot), ...convertedArgs], null); 25742 25743 this._pipeBindExprs.push(pipeBindExpr); 25744 25745 return pipeBindExpr; 25746 } 25747 25748 updatePipeSlotOffsets(bindingSlots) {
25749 this._pipeBindExprs.forEach(pipe => { 25750 // update the slot offset arg (index 1) to account for binding slots 25751 const slotOffset = pipe.args[1]; 25752 slotOffset.value += bindingSlots; 25753 }); 25754 } 25755 25756 visitLiteralArray(array, context) { 25757 return new BuiltinFunctionCall(array.span, array.sourceSpan, this.visitAll(array.expressions), values => { 25758 // If the literal has calculated (non-literal) elements transform it into 25759 // calls to literal factories that compose the literal and will cache intermediate 25760 // values. 25761 const literal = literalArr(values); 25762 return getLiteralFactory(this.constantPool, literal, this.allocatePureFunctionSlots); 25763 }); 25764 } 25765 25766 visitLiteralMap(map, context) { 25767 return new BuiltinFunctionCall(map.span, map.sourceSpan, this.visitAll(map.values), values => { 25768 // If the literal has calculated (non-literal) elements transform it into 25769 // calls to literal factories that compose the literal and will cache intermediate 25770 // values. 25771 const literal = literalMap(values.map((value, index) => ({ 25772 key: map.keys[index].key, 25773 value, 25774 quoted: map.keys[index].quoted 25775 }))); 25776 return getLiteralFactory(this.constantPool, literal, this.allocatePureFunctionSlots); 25777 }); 25778 } 25779 25780} // Pipes always have at least one parameter, the value they operate on 25781 25782 25783const pipeBindingIdentifiers = [Identifiers.pipeBind1, Identifiers.pipeBind2, Identifiers.pipeBind3, Identifiers.pipeBind4]; 25784 25785function pipeBindingCallInfo(args) { 25786 const identifier = pipeBindingIdentifiers[args.length]; 25787 return { 25788 identifier: identifier || Identifiers.pipeBindV, 25789 isVarLength: !identifier 25790 }; 25791} 25792 25793const pureFunctionIdentifiers = [Identifiers.pureFunction0, Identifiers.pureFunction1, Identifiers.pureFunction2, Identifiers.pureFunction3, Identifiers.pureFunction4, Identifiers.pureFunction5, Identifiers.pureFunction6, Identifiers.pureFunction7, Identifiers.pureFunction8]; 25794 25795function pureFunctionCallInfo(args) { 25796 const identifier = pureFunctionIdentifiers[args.length]; 25797 return { 25798 identifier: identifier || Identifiers.pureFunctionV, 25799 isVarLength: !identifier 25800 }; 25801} // e.g. x(2); 25802 25803 25804function generateNextContextExpr(relativeLevelDiff) { 25805 return importExpr(Identifiers.nextContext).callFn(relativeLevelDiff > 1 ? [literal(relativeLevelDiff)] : []); 25806} 25807 25808function getLiteralFactory(constantPool, literal$1, allocateSlots) { 25809 const { 25810 literalFactory, 25811 literalFactoryArguments 25812 } = constantPool.getLiteralFactory(literal$1); // Allocate 1 slot for the result plus 1 per argument 25813 25814 const startSlot = allocateSlots(1 + literalFactoryArguments.length); 25815 const { 25816 identifier, 25817 isVarLength 25818 } = pureFunctionCallInfo(literalFactoryArguments); // Literal factories are pure functions that only need to be re-invoked when the parameters 25819 // change. 25820 25821 const args = [literal(startSlot), literalFactory]; 25822 25823 if (isVarLength) { 25824 args.push(literalArr(literalFactoryArguments)); 25825 } else { 25826 args.push(...literalFactoryArguments); 25827 } 25828 25829 return importExpr(identifier).callFn(args); 25830} 25831/** 25832 * Gets an array of literals that can be added to an expression 25833 * to represent the name and namespace of an attribute. E.g. 25834 * `:xlink:href` turns into `[AttributeMarker.NamespaceURI, 'xlink', 'href']`. 25835 * 25836 * @param name Name of the attribute, including the namespace. 25837 */ 25838 25839 25840function getAttributeNameLiterals(name) { 25841 const [attributeNamespace, attributeName] = splitNsName(name); 25842 const nameLiteral = literal(attributeName); 25843 25844 if (attributeNamespace) { 25845 return [literal(0 25846 /* core.AttributeMarker.NamespaceURI */ 25847 ), literal(attributeNamespace), nameLiteral]; 25848 } 25849 25850 return [nameLiteral]; 25851} 25852/** The prefix used to get a shared context in BindingScope's map. */ 25853 25854 25855const SHARED_CONTEXT_KEY = '$$shared_ctx$$'; 25856 25857class BindingScope { 25858 constructor(bindingLevel = 0, parent = null, globals) { 25859 this.bindingLevel = bindingLevel; 25860 this.parent = parent; 25861 this.globals = globals; 25862 /** Keeps a map from local variables to their BindingData. */ 25863 25864 this.map = new Map(); 25865 this.referenceNameIndex = 0; 25866 this.restoreViewVariable = null; 25867 this.usesRestoredViewContext = false;
25868 25869 if (globals !== undefined) { 25870 for (const name of globals) { 25871 this.set(0, name, variable(name)); 25872 } 25873 } 25874 } 25875 25876 static createRootScope() { 25877 return new BindingScope(); 25878 } 25879 25880 get(name) { 25881 let current = this; 25882 25883 while (current) { 25884 let value = current.map.get(name); 25885 25886 if (value != null) { 25887 if (current !== this) { 25888 // make a local copy and reset the `declare` state 25889 value = { 25890 retrievalLevel: value.retrievalLevel, 25891 lhs: value.lhs, 25892 declareLocalCallback: value.declareLocalCallback, 25893 declare: false, 25894 priority: value.priority 25895 }; // Cache the value locally. 25896 25897 this.map.set(name, value); // Possibly generate a shared context var 25898 25899 this.maybeGenerateSharedContextVar(value); 25900 this.maybeRestoreView(); 25901 } 25902 25903 if (value.declareLocalCallback && !value.declare) { 25904 value.declare = true; 25905 } 25906 25907 return value.lhs; 25908 } 25909 25910 current = current.parent; 25911 } // If we get to this point, we are looking for a property on the top level component 25912 // - If level === 0, we are on the top and don't need to re-declare `ctx`. 25913 // - If level > 0, we are in an embedded view. We need to retrieve the name of the 25914 // local var we used to store the component context, e.g. const $comp$ = x(); 25915 25916 25917 return this.bindingLevel === 0 ? null : this.getComponentProperty(name); 25918 } 25919 /** 25920 * Create a local variable for later reference. 25921 * 25922 * @param retrievalLevel The level from which this value can be retrieved 25923 * @param name Name of the variable. 25924 * @param lhs AST representing the left hand side of the `let lhs = rhs;`. 25925 * @param priority The sorting priority of this var 25926 * @param declareLocalCallback The callback to invoke when declaring this local var 25927 * @param localRef Whether or not this is a local ref 25928 */ 25929 25930 25931 set(retrievalLevel, name, lhs, priority = 0 25932 /* DeclarationPriority.DEFAULT */ 25933 , declareLocalCallback, localRef) { 25934 if (this.map.has(name)) { 25935 if (localRef) { 25936 // Do not throw an error if it's a local ref and do not update existing value, 25937 // so the first defined ref is always returned. 25938 return this; 25939 } 25940 25941 error(`The name ${name} is already defined in scope to be ${this.map.get(name)}`); 25942 } 25943 25944 this.map.set(name, { 25945 retrievalLevel: retrievalLevel, 25946 lhs: lhs, 25947 declare: false, 25948 declareLocalCallback: declareLocalCallback, 25949 priority: priority 25950 }); 25951 return this; 25952 } // Implemented as part of LocalResolver. 25953 25954 25955 getLocal(name) { 25956 return this.get(name); 25957 } // Implemented as part of LocalResolver. 25958 25959 25960 notifyImplicitReceiverUse() { 25961 if (this.bindingLevel !== 0) { 25962 // Since the implicit receiver is accessed in an embedded view, we need to 25963 // ensure that we declare a shared context variable for the current template 25964 // in the update variables. 25965 this.map.get(SHARED_CONTEXT_KEY + 0).declare = true; 25966 } 25967 } 25968 25969 nestedScope(level, globals) { 25970 const newScope = new BindingScope(level, this, globals); 25971 if (level > 0) newScope.generateSharedContextVar(0); 25972 return newScope; 25973 } 25974 /** 25975 * Gets or creates a shared context variable and returns its expression. Note that 25976 * this does not mean that the shared variable will be declared. Variables in the 25977 * binding scope will be only declared if they are used. 25978 */ 25979 25980 25981 getOrCreateSharedContextVar(retrievalLevel) { 25982 const bindingKey = SHARED_CONTEXT_KEY + retrievalLevel; 25983 25984 if (!this.map.has(bindingKey)) { 25985 this.generateSharedContextVar(retrievalLevel); 25986 } // Shared context variables are always generated as "ReadVarExpr". 25987 25988 25989 return this.map.get(bindingKey).lhs; 25990 } 25991 25992 getSharedContextName(retrievalLevel) { 25993 const sharedCtxObj = this.map.get(SHARED_CONTEXT_KEY + retrievalLevel); // Shared context variables are always generated as "ReadVarExpr". 25994 25995 return sharedCtxObj && sharedCtxObj.declare ? sharedCtxObj.lhs : null; 25996 } 25997 25998 maybeGenerateSharedContextVar(value) { 25999 if (value.priority === 1 26000 /* DeclarationPriority.CONTEXT */ 26001 && value.retrievalLevel < this.bindingLevel) { 26002 const sharedCtxObj = this.map.get(SHARED_CONTEXT_KEY + value.retrievalLevel); 26003 26004 if (sharedCtxObj) { 26005 sharedCtxObj.declare = true; 26006 } else { 26007 this.generateSharedContextVar(value.retrievalLevel); 26008 } 26009 } 26010 } 26011 26012 generateSharedContextVar(retrievalLevel) { 26013 const lhs = variable(CONTEXT_NAME + this.freshReferenceName()); 26014 this.map.set(SHARED_CONTEXT_KEY + retrievalLevel, { 26015 retrievalLevel: retrievalLevel, 26016 lhs: lhs, 26017 declareLocalCallback: (scope, relativeLevel) => { 26018 // const ctx_r0 = nextContext(2); 26019 return [lhs.set(generateNextContextExpr(relativeLevel)).toConstDecl()]; 26020 }, 26021 declare: false, 26022 priority: 2 26023 /* DeclarationPriority.SHARED_CONTEXT */ 26024 26025 }); 26026 } 26027 26028 getComponentProperty(name) { 26029 const componentValue = this.map.get(SHARED_CONTEXT_KEY + 0); 26030 componentValue.declare = true; 26031 this.maybeRestoreView(); 26032 return componentValue.lhs.prop(name); 26033 } 26034 26035 maybeRestoreView() { 26036 // View restoration is required for listener instructions inside embedded views, because 26037 // they only run in creation mode and they can have references to the context object. 26038 // If the context object changes in update mode, the reference will be incorrect, because 26039 // it was established during creation. 26040 if (this.isListenerScope()) { 26041 if (!this.parent.restoreViewVariable) { 26042 // parent saves variable to generate a shared `const $s$ = getCurrentView();` instruction 26043 this.parent.restoreViewVariable = variable(this.parent.freshReferenceName()); 26044 } 26045 26046 this.restoreViewVariable = this.parent.restoreViewVariable; 26047 } 26048 } 26049
26050 restoreViewStatement() { 26051 if (this.restoreViewVariable) { 26052 const restoreCall = invokeInstruction(null, Identifiers.restoreView, [this.restoreViewVariable]); // Either `const restoredCtx = restoreView($state$);` or `restoreView($state$);` 26053 // depending on whether it is being used. 26054 26055 return this.usesRestoredViewContext ? variable(RESTORED_VIEW_CONTEXT_NAME).set(restoreCall).toConstDecl() : restoreCall.toStmt(); 26056 } 26057 26058 return null; 26059 } 26060 26061 viewSnapshotStatements() { 26062 // const $state$ = getCurrentView(); 26063 return this.restoreViewVariable ? [this.restoreViewVariable.set(invokeInstruction(null, Identifiers.getCurrentView, [])).toConstDecl()] : []; 26064 } 26065 26066 isListenerScope() { 26067 return this.parent && this.parent.bindingLevel === this.bindingLevel; 26068 } 26069 26070 variableDeclarations() { 26071 let currentContextLevel = 0; 26072 return Array.from(this.map.values()).filter(value => value.declare).sort((a, b) => b.retrievalLevel - a.retrievalLevel || b.priority - a.priority).reduce((stmts, value) => { 26073 const levelDiff = this.bindingLevel - value.retrievalLevel; 26074 const currStmts = value.declareLocalCallback(this, levelDiff - currentContextLevel); 26075 currentContextLevel = levelDiff; 26076 return stmts.concat(currStmts); 26077 }, []); 26078 } 26079 26080 freshReferenceName() {
26081 let current = this; // Find the top scope as it maintains the global reference count 26082 26083 while (current.parent) current = current.parent; 26084 26085 const ref = `${REFERENCE_PREFIX}${current.referenceNameIndex++}`; 26086 return ref; 26087 } 26088 26089 hasRestoreViewVariable() { 26090 return !!this.restoreViewVariable; 26091 } 26092 26093 notifyRestoredViewContextUse() { 26094 this.usesRestoredViewContext = true; 26095 } 26096 26097} 26098/** 26099 * Creates a `CssSelector` given a tag name and a map of attributes 26100 */ 26101 26102 26103function createCssSelector(elementName, attributes) { 26104 const cssSelector = new CssSelector(); 26105 const elementNameNoNs = splitNsName(elementName)[1]; 26106 cssSelector.setElement(elementNameNoNs); 26107 Object.getOwnPropertyNames(attributes).forEach(name => { 26108 const nameNoNs = splitNsName(name)[1]; 26109 const value = attributes[name]; 26110 cssSelector.addAttribute(nameNoNs, value); 26111 26112 if (name.toLowerCase() === 'class') { 26113 const classes = value.trim().split(/\s+/); 26114 classes.forEach(className => cssSelector.addClassName(className)); 26115 } 26116 }); 26117 return cssSelector; 26118} 26119/** 26120 * Creates an array of expressions out of an `ngProjectAs` attributes 26121 * which can be added to the instruction parameters. 26122 */ 26123 26124 26125function getNgProjectAsLiteral(attribute) { 26126 // Parse the attribute value into a CssSelectorList. Note that we only take the 26127 // first selector, because we don't support multiple selectors in ngProjectAs. 26128 const parsedR3Selector = parseSelectorToR3Selector(attribute.value)[0]; 26129 return [literal(5 26130 /* core.AttributeMarker.ProjectAs */ 26131 ), asLiteral(parsedR3Selector)]; 26132} 26133/** 26134 * Gets the instruction to generate for an interpolated property 26135 * @param interpolation An Interpolation AST 26136 */ 26137 26138 26139function getPropertyInterpolationExpression(interpolation) { 26140 switch (getInterpolationArgsLength(interpolation)) { 26141 case 1: 26142 return Identifiers.propertyInterpolate; 26143 26144 case 3: 26145 return Identifiers.propertyInterpolate1; 26146 26147 case 5: 26148 return Identifiers.propertyInterpolate2; 26149 26150 case 7: 26151 return Identifiers.propertyInterpolate3; 26152 26153 case 9: 26154 return Identifiers.propertyInterpolate4; 26155 26156 case 11: 26157 return Identifiers.propertyInterpolate5; 26158 26159 case 13: 26160 return Identifiers.propertyInterpolate6; 26161 26162 case 15: 26163 return Identifiers.propertyInterpolate7; 26164 26165 case 17: 26166 return Identifiers.propertyInterpolate8; 26167 26168 default: 26169 return Identifiers.propertyInterpolateV; 26170 } 26171} 26172/** 26173 * Gets the instruction to generate for an interpolated attribute 26174 * @param interpolation An Interpolation AST 26175 */ 26176 26177 26178function getAttributeInterpolationExpression(interpolation) { 26179 switch (getInterpolationArgsLength(interpolation)) { 26180 case 3: 26181 return Identifiers.attributeInterpolate1; 26182 26183 case 5: 26184 return Identifiers.attributeInterpolate2; 26185 26186 case 7: 26187 return Identifiers.attributeInterpolate3; 26188 26189 case 9: 26190 return Identifiers.attributeInterpolate4; 26191 26192 case 11: 26193 return Identifiers.attributeInterpolate5; 26194 26195 case 13: 26196 return Identifiers.attributeInterpolate6; 26197 26198 case 15: 26199 return Identifiers.attributeInterpolate7; 26200 26201 case 17: 26202 return Identifiers.attributeInterpolate8; 26203 26204 default: 26205 return Identifiers.attributeInterpolateV; 26206 } 26207} 26208/** 26209 * Gets the instruction to generate for interpolated text. 26210 * @param interpolation An Interpolation AST 26211 */ 26212 26213 26214function getTextInterpolationExpression(interpolation) { 26215 switch (getInterpolationArgsLength(interpolation)) { 26216 case 1: 26217 return Identifiers.textInterpolate; 26218 26219 case 3: 26220 return Identifiers.textInterpolate1; 26221 26222 case 5: 26223 return Identifiers.textInterpolate2; 26224 26225 case 7: 26226 return Identifiers.textInterpolate3; 26227 26228 case 9: 26229 return Identifiers.textInterpolate4; 26230 26231 case 11: 26232 return Identifiers.textInterpolate5; 26233 26234 case 13: 26235 return Identifiers.textInterpolate6; 26236 26237 case 15: 26238 return Identifiers.textInterpolate7; 26239 26240 case 17: 26241 return Identifiers.textInterpolate8; 26242 26243 default: 26244 return Identifiers.textInterpolateV; 26245 } 26246} 26247/** 26248 * Parse a template into render3 `Node`s and additional metadata, with no other dependencies. 26249 * 26250 * @param template text of the template to parse 26251 * @param templateUrl URL to use for source mapping of the parsed template 26252 * @param options options to modify how the template is parsed 26253 */ 26254 26255 26256function parseTemplate(template, templateUrl, options = {}) { 26257 const { 26258 interpolationConfig,
26259 preserveWhitespaces, 26260 enableI18nLegacyMessageIdFormat 26261 } = options; 26262 const bindingParser = makeBindingParser(interpolationConfig); 26263 const htmlParser = new HtmlParser(); 26264 const parseResult = htmlParser.parse(template, templateUrl, { 26265 leadingTriviaChars: LEADING_TRIVIA_CHARS, 26266 ...options, 26267 tokenizeExpansionForms: true 26268 }); 26269 26270 if (!options.alwaysAttemptHtmlToR3AstConversion && parseResult.errors && parseResult.errors.length > 0) { 26271 const parsedTemplate = { 26272 interpolationConfig, 26273 preserveWhitespaces, 26274 errors: parseResult.errors, 26275 nodes: [], 26276 styleUrls: [], 26277 styles: [], 26278 ngContentSelectors: [] 26279 }; 26280 26281 if (options.collectCommentNodes) { 26282 parsedTemplate.commentNodes = []; 26283 } 26284 26285 return parsedTemplate; 26286 } 26287 26288 let rootNodes = parseResult.rootNodes; // process i18n meta information (scan attributes, generate ids) 26289 // before we run whitespace removal process, because existing i18n 26290 // extraction process (ng extract-i18n) relies on a raw content to generate 26291 // message ids 26292 26293 const i18nMetaVisitor = new I18nMetaVisitor(interpolationConfig, 26294 /* keepI18nAttrs */ 26295 !preserveWhitespaces, enableI18nLegacyMessageIdFormat); 26296 const i18nMetaResult = i18nMetaVisitor.visitAllWithErrors(rootNodes); 26297 26298 if (!options.alwaysAttemptHtmlToR3AstConversion && i18nMetaResult.errors && i18nMetaResult.errors.length > 0) { 26299 const parsedTemplate = { 26300 interpolationConfig, 26301 preserveWhitespaces, 26302 errors: i18nMetaResult.errors, 26303 nodes: [], 26304 styleUrls: [], 26305 styles: [], 26306 ngContentSelectors: [] 26307 }; 26308 26309 if (options.collectCommentNodes) { 26310 parsedTemplate.commentNodes = []; 26311 } 26312 26313 return parsedTemplate; 26314 } 26315 26316 rootNodes = i18nMetaResult.rootNodes; 26317 26318 if (!preserveWhitespaces) { 26319 rootNodes = visitAll(new WhitespaceVisitor(), rootNodes); // run i18n meta visitor again in case whitespaces are removed (because that might affect 26320 // generated i18n message content) and first pass indicated that i18n content is present in a 26321 // template. During this pass i18n IDs generated at the first pass will be preserved, so we can 26322 // mimic existing extraction process (ng extract-i18n) 26323 26324 if (i18nMetaVisitor.hasI18nMeta) { 26325 rootNodes = visitAll(new I18nMetaVisitor(interpolationConfig, 26326 /* keepI18nAttrs */ 26327 false), rootNodes); 26328 } 26329 } 26330 26331 const { 26332 nodes, 26333 errors, 26334 styleUrls, 26335 styles, 26336 ngContentSelectors, 26337 commentNodes 26338 } = htmlAstToRender3Ast(rootNodes, bindingParser, { 26339 collectCommentNodes: !!options.collectCommentNodes 26340 }); 26341 errors.push(...parseResult.errors, ...i18nMetaResult.errors); 26342 const parsedTemplate = { 26343 interpolationConfig, 26344 preserveWhitespaces, 26345 errors: errors.length > 0 ? errors : null, 26346 nodes, 26347 styleUrls, 26348 styles, 26349 ngContentSelectors 26350 }; 26351 26352 if (options.collectCommentNodes) { 26353 parsedTemplate.commentNodes = commentNodes; 26354 } 26355 26356 return parsedTemplate; 26357} 26358 26359const elementRegistry = new DomElementSchemaRegistry(); 26360/** 26361 * Construct a `BindingParser` with a default configuration. 26362 */ 26363 26364function makeBindingParser(interpolationConfig = DEFAULT_INTERPOLATION_CONFIG) { 26365 return new BindingParser(new Parser$1(new Lexer()), interpolationConfig, elementRegistry, []); 26366} 26367 26368function resolveSanitizationFn(context, isAttribute) { 26369 switch (context) { 26370 case SecurityContext.HTML: 26371 return importExpr(Identifiers.sanitizeHtml); 26372 26373 case SecurityContext.SCRIPT: 26374 return importExpr(Identifiers.sanitizeScript); 26375 26376 case SecurityContext.STYLE: 26377 // the compiler does not fill in an instruction for [style.prop?] binding 26378 // values because the style algorithm knows internally what props are subject 26379 // to sanitization (only [attr.style] values are explicitly sanitized) 26380 return isAttribute ? importExpr(Identifiers.sanitizeStyle) : null; 26381 26382 case SecurityContext.URL: 26383 return importExpr(Identifiers.sanitizeUrl); 26384 26385 case SecurityContext.RESOURCE_URL: 26386 return importExpr(Identifiers.sanitizeResourceUrl); 26387 26388 default: 26389 return null; 26390 } 26391} 26392 26393function trustedConstAttribute(tagName, attr) { 26394 const value = asLiteral(attr.value); 26395 26396 if (isTrustedTypesSink(tagName, attr.name)) { 26397 switch (elementRegistry.securityContext(tagName, attr.name, 26398 /* isAttribute */ 26399 true)) { 26400 case SecurityContext.HTML: 26401 return taggedTemplate(importExpr(Identifiers.trustConstantHtml), new TemplateLiteral([new TemplateLiteralElement(attr.value)], []), undefined, attr.valueSpan); 26402 // NB: no SecurityContext.SCRIPT here, as the corresponding tags are stripped by the compiler. 26403 26404 case SecurityContext.RESOURCE_URL: 26405 return taggedTemplate(importExpr(Identifiers.trustConstantResourceUrl), new TemplateLiteral([new TemplateLiteralElement(attr.value)], []), undefined, attr.valueSpan); 26406 26407 default: 26408 return value; 26409 } 26410 } else { 26411 return value; 26412 } 26413} 26414 26415function isSingleElementTemplate(children) { 26416 return children.length === 1 && children[0] instanceof Element$1; 26417} 26418 26419function isTextNode(node) { 26420 return node instanceof Text$3 || node instanceof BoundText || node instanceof Icu$1; 26421} 26422 26423function isIframeElement(tagName) { 26424 return tagName.toLowerCase() === 'iframe'; 26425} 26426 26427function hasTextChildrenOnly(children) { 26428 return children.every(isTextNode); 26429} 26430 26431function getBindingFunctionParams(deferredParams, name, eagerParams) { 26432 return () => { 26433 const value = deferredParams(); 26434 const fnParams = Array.isArray(value) ? value : [value]; 26435 26436 if (eagerParams) { 26437 fnParams.push(...eagerParams); 26438 } 26439 26440 if (name) { 26441 // We want the property name to always be the first function parameter. 26442 fnParams.unshift(literal(name)); 26443 } 26444 26445 return fnParams; 26446 }; 26447} 26448/** Name of the global variable that is used to determine if we use Closure translations or not */ 26449 26450 26451const NG_I18N_CLOSURE_MODE = 'ngI18nClosureMode'; 26452/** 26453 * Generate statements that define a given translation message. 26454 * 26455 * ``` 26456 * var I18N_1; 26457 * if (typeof ngI18nClosureMode !== undefined && ngI18nClosureMode) { 26458 * var MSG_EXTERNAL_XXX = goog.getMsg( 26459 * "Some message with {$interpolation}!", 26460 * { "interpolation": "\uFFFD0\uFFFD" } 26461 * ); 26462 * I18N_1 = MSG_EXTERNAL_XXX; 26463 * } 26464 * else { 26465 * I18N_1 = $localize`Some message with ${'\uFFFD0\uFFFD'}!`; 26466 * } 26467 * ``` 26468 * 26469 * @param message The original i18n AST message node 26470 * @param variable The variable that will be assigned the translation, e.g. `I18N_1`. 26471 * @param closureVar The variable for Closure `goog.getMsg` calls, e.g. `MSG_EXTERNAL_XXX`. 26472 * @param params Object mapping placeholder names to their values (e.g. 26473 * `{ "interpolation": "\uFFFD0\uFFFD" }`). 26474 * @param transformFn Optional transformation function that will be applied to the translation (e.g. 26475 * post-processing). 26476 * @returns An array of statements that defined a given translation. 26477 */ 26478 26479function getTranslationDeclStmts(message, variable, closureVar, params = {}, transformFn) { 26480 const statements = [declareI18nVariable(variable), ifStmt(createClosureModeGuard(), createGoogleGetMsgStatements(variable, message, closureVar, params), createLocalizeStatements(variable, message, formatI18nPlaceholderNamesInMap(params, 26481 /* useCamelCase */ 26482 false)))]; 26483 26484 if (transformFn) {
26485 statements.push(new ExpressionStatement(variable.set(transformFn(variable)))); 26486 } 26487 26488 return statements; 26489} 26490/** 26491 * Create the expression that will be used to guard the closure mode block 26492 * It is equivalent to: 26493 * 26494 * ``` 26495 * typeof ngI18nClosureMode !== undefined && ngI18nClosureMode 26496 * ``` 26497 */ 26498 26499 26500function createClosureModeGuard() { 26501 return typeofExpr(variable(NG_I18N_CLOSURE_MODE)).notIdentical(literal('undefined', STRING_TYPE)).and(variable(NG_I18N_CLOSURE_MODE)); 26502} 26503 26504function flatten(list) { 26505 return list.reduce((flat, item) => { 26506 const flatItem = Array.isArray(item) ? flatten(item) : item; 26507 return flat.concat(flatItem); 26508 }, []); 26509} 26510/** 26511 * @license 26512 * Copyright Google LLC All Rights Reserved. 26513 * 26514 * Use of this source code is governed by an MIT-style license that can be 26515 * found in the LICENSE file at https://angular.io/license 26516 */ 26517// This regex matches any binding names that contain the "attr." prefix, e.g. "attr.required" 26518// If there is a match, the first matching group will contain the attribute name to bind. 26519 26520 26521const ATTR_REGEX = /attr\.([^\]]+)/;
26522const COMPONENT_VARIABLE = '%COMP%'; 26523const HOST_ATTR = `_nghost-${COMPONENT_VARIABLE}`; 26524const CONTENT_ATTR = `_ngcontent-${COMPONENT_VARIABLE}`; 26525 26526function baseDirectiveFields(meta, constantPool, bindingParser) { 26527 const definitionMap = new DefinitionMap(); 26528 const selectors = parseSelectorToR3Selector(meta.selector); // e.g. `type: MyDirective` 26529 26530 definitionMap.set('type', meta.internalType); // e.g. `selectors: [['', 'someDir', '']]` 26531 26532 if (selectors.length > 0) { 26533 definitionMap.set('selectors', asLiteral(selectors)); 26534 } 26535 26536 if (meta.queries.length > 0) { 26537 // e.g. `contentQueries: (rf, ctx, dirIndex) => { ... } 26538 definitionMap.set('contentQueries', createContentQueriesFunction(meta.queries, constantPool, meta.name)); 26539 } 26540 26541 if (meta.viewQueries.length) { 26542 definitionMap.set('viewQuery', createViewQueriesFunction(meta.viewQueries, constantPool, meta.name)); 26543 } // e.g. `hostBindings: (rf, ctx) => { ... } 26544 26545 26546 definitionMap.set('hostBindings', createHostBindingsFunction(meta.host, meta.typeSourceSpan, bindingParser, constantPool, meta.selector || '', meta.name, definitionMap)); // e.g 'inputs: {a: 'a'}` 26547 26548 definitionMap.set('inputs', conditionallyCreateMapObjectLiteral(meta.inputs, true)); // e.g 'outputs: {a: 'a'}` 26549 26550 definitionMap.set('outputs', conditionallyCreateMapObjectLiteral(meta.outputs)); 26551 26552 if (meta.exportAs !== null) { 26553 definitionMap.set('exportAs', literalArr(meta.exportAs.map(e => literal(e)))); 26554 } 26555 26556 if (meta.isStandalone) { 26557 definitionMap.set('standalone', literal(true)); 26558 } 26559 26560 return definitionMap; 26561} 26562/** 26563 * Add features to the definition map. 26564 */ 26565 26566 26567function addFeatures(definitionMap, meta) { 26568 // e.g. `features: [NgOnChangesFeature]` 26569 const features = []; 26570 const providers = meta.providers; 26571 const viewProviders = meta.viewProviders; 26572 26573 if (providers || viewProviders) { 26574 const args = [providers || new LiteralArrayExpr([])]; 26575 26576 if (viewProviders) { 26577 args.push(viewProviders); 26578 } 26579 26580 features.push(importExpr(Identifiers.ProvidersFeature).callFn(args)); 26581 } 26582 26583 if (meta.usesInheritance) { 26584 features.push(importExpr(Identifiers.InheritDefinitionFeature)); 26585 } 26586 26587 if (meta.fullInheritance) { 26588 features.push(importExpr(Identifiers.CopyDefinitionFeature)); 26589 } 26590 26591 if (meta.lifecycle.usesOnChanges) { 26592 features.push(importExpr(Identifiers.NgOnChangesFeature)); 26593 } // TODO: better way of differentiating component vs directive metadata. 26594 26595 26596 if (meta.hasOwnProperty('template') && meta.isStandalone) { 26597 features.push(importExpr(Identifiers.StandaloneFeature)); 26598 } 26599 26600 if (features.length) { 26601 definitionMap.set('features', literalArr(features)); 26602 } 26603} 26604/** 26605 * Compile a directive for the render3 runtime as defined by the `R3DirectiveMetadata`. 26606 */ 26607 26608 26609function compileDirectiveFromMetadata(meta, constantPool, bindingParser) { 26610 const definitionMap = baseDirectiveFields(meta, constantPool, bindingParser); 26611 addFeatures(definitionMap, meta); 26612 const expression = importExpr(Identifiers.defineDirective).callFn([definitionMap.toLiteralMap()], undefined, true); 26613 const type = createDirectiveType(meta); 26614 return { 26615 expression, 26616 type, 26617 statements: [] 26618 }; 26619} 26620/** 26621 * Compile a component for the render3 runtime as defined by the `R3ComponentMetadata`. 26622 */ 26623 26624 26625function compileComponentFromMetadata(meta, constantPool, bindingParser) { 26626 const definitionMap = baseDirectiveFields(meta, constantPool, bindingParser); 26627 addFeatures(definitionMap, meta); 26628 const selector = meta.selector && CssSelector.parse(meta.selector); 26629 const firstSelector = selector && selector[0]; // e.g. `attr: ["class", ".my.app"]` 26630 // This is optional an only included if the first selector of a component specifies attributes. 26631 26632 if (firstSelector) { 26633 const selectorAttributes = firstSelector.getAttrs(); 26634 26635 if (selectorAttributes.length) { 26636 definitionMap.set('attrs', constantPool.getConstLiteral(literalArr(selectorAttributes.map(value => value != null ? literal(value) : literal(undefined))), 26637 /* forceShared */ 26638 true)); 26639 } 26640 } // e.g. `template: function MyComponent_Template(_ctx, _cm) {...}` 26641 26642 26643 const templateTypeName = meta.name; 26644 const templateName = templateTypeName ? `${templateTypeName}_Template` : null; 26645 const changeDetection = meta.changeDetection; 26646 const template = meta.template; 26647 const templateBuilder = new TemplateDefinitionBuilder(constantPool, BindingScope.createRootScope(), 0, templateTypeName, null, null, templateName, Identifiers.namespaceHTML, meta.relativeContextFilePath, meta.i18nUseExternalIds); 26648 const templateFunctionExpression = templateBuilder.buildTemplateFunction(template.nodes, []); // We need to provide this so that dynamically generated components know what 26649 // projected content blocks to pass through to the component when it is instantiated. 26650 26651 const ngContentSelectors = templateBuilder.getNgContentSelectors(); 26652 26653 if (ngContentSelectors) { 26654 definitionMap.set('ngContentSelectors', ngContentSelectors); 26655 } // e.g. `decls: 2` 26656 26657 26658 definitionMap.set('decls', literal(templateBuilder.getConstCount())); // e.g. `vars: 2` 26659 26660 definitionMap.set('vars', literal(templateBuilder.getVarCount())); // Generate `consts` section of ComponentDef: 26661 // - either as an array: 26662 // `consts: [['one', 'two'], ['three', 'four']]` 26663 // - or as a factory function in case additional statements are present (to support i18n): 26664 // `consts: function() { var i18n_0; if (ngI18nClosureMode) {...} else {...} return [i18n_0]; }` 26665 26666 const { 26667 constExpressions, 26668 prepareStatements 26669 } = templateBuilder.getConsts(); 26670 26671 if (constExpressions.length > 0) {
26672 let constsExpr = literalArr(constExpressions); // Prepare statements are present - turn `consts` into a function. 26673 26674 if (prepareStatements.length > 0) { 26675 constsExpr = fn([], [...prepareStatements, new ReturnStatement(constsExpr)]); 26676 } 26677 26678 definitionMap.set('consts', constsExpr); 26679 } 26680 26681 definitionMap.set('template', templateFunctionExpression); 26682 26683 if (meta.declarations.length > 0) { 26684 definitionMap.set('dependencies', compileDeclarationList(literalArr(meta.declarations.map(decl => decl.type)), meta.declarationListEmitMode)); 26685 } 26686 26687 if (meta.encapsulation === null) { 26688 meta.encapsulation = ViewEncapsulation.Emulated; 26689 } // e.g. `styles: [str1, str2]` 26690 26691 26692 if (meta.styles && meta.styles.length) { 26693 const styleValues = meta.encapsulation == ViewEncapsulation.Emulated ? compileStyles(meta.styles, CONTENT_ATTR, HOST_ATTR) : meta.styles; 26694 const styleNodes = styleValues.reduce((result, style) => { 26695 if (style.trim().length > 0) { 26696 result.push(constantPool.getConstLiteral(literal(style))); 26697 } 26698 26699 return result; 26700 }, []); 26701 26702 if (styleNodes.length > 0) { 26703 definitionMap.set('styles', literalArr(styleNodes)); 26704 } 26705 } else if (meta.encapsulation === ViewEncapsulation.Emulated) { 26706 // If there is no style, don't generate css selectors on elements 26707 meta.encapsulation = ViewEncapsulation.None; 26708 } // Only set view encapsulation if it's not the default value 26709 26710 26711 if (meta.encapsulation !== ViewEncapsulation.Emulated) { 26712 definitionMap.set('encapsulation', literal(meta.encapsulation)); 26713 } // e.g. `animation: [trigger('123', [])]` 26714 26715 26716 if (meta.animations !== null) { 26717 definitionMap.set('data', literalMap([{ 26718 key: 'animation', 26719 value: meta.animations, 26720 quoted: false 26721 }])); 26722 } // Only set the change detection flag if it's defined and it's not the default. 26723 26724 26725 if (changeDetection != null && changeDetection !== ChangeDetectionStrategy.Default) { 26726 definitionMap.set('changeDetection', literal(changeDetection)); 26727 } 26728 26729 const expression = importExpr(Identifiers.defineComponent).callFn([definitionMap.toLiteralMap()], undefined, true); 26730 const type = createComponentType(meta); 26731 return { 26732 expression, 26733 type, 26734 statements: [] 26735 }; 26736} 26737/** 26738 * Creates the type specification from the component meta. This type is inserted into .d.ts files 26739 * to be consumed by upstream compilations. 26740 */ 26741 26742 26743function createComponentType(meta) { 26744 const typeParams = createBaseDirectiveTypeParams(meta); 26745 typeParams.push(stringArrayAsType(meta.template.ngContentSelectors)); 26746 typeParams.push(expressionType(literal(meta.isStandalone))); 26747 return expressionType(importExpr(Identifiers.ComponentDeclaration, typeParams)); 26748} 26749/** 26750 * Compiles the array literal of declarations into an expression according to the provided emit 26751 * mode. 26752 */ 26753 26754 26755function compileDeclarationList(list, mode) { 26756 switch (mode) { 26757 case 0 26758 /* DeclarationListEmitMode.Direct */ 26759 : 26760 // directives: [MyDir], 26761 return list; 26762 26763 case 1 26764 /* DeclarationListEmitMode.Closure */ 26765 : 26766 // directives: function () { return [MyDir]; }
26767 return fn([], [new ReturnStatement(list)]); 26768 26769 case 2 26770 /* DeclarationListEmitMode.ClosureResolved */ 26771 : 26772 // directives: function () { return [MyDir].map(ng.resolveForwardRef); } 26773 const resolvedList = list.prop('map').callFn([importExpr(Identifiers.resolveForwardRef)]); 26774 return fn([], [new ReturnStatement(resolvedList)]); 26775 } 26776} 26777 26778function prepareQueryParams(query, constantPool) { 26779 const parameters = [getQueryPredicate(query, constantPool), literal(toQueryFlags(query))]; 26780 26781 if (query.read) { 26782 parameters.push(query.read); 26783 } 26784 26785 return parameters; 26786} 26787/** 26788 * Translates query flags into `TQueryFlags` type in packages/core/src/render3/interfaces/query.ts 26789 * @param query 26790 */ 26791 26792 26793function toQueryFlags(query) { 26794 return (query.descendants ? 1 26795 /* QueryFlags.descendants */ 26796 : 0 26797 /* QueryFlags.none */ 26798 ) | (query.static ? 2 26799 /* QueryFlags.isStatic */ 26800 : 0 26801 /* QueryFlags.none */ 26802 ) | (query.emitDistinctChangesOnly ? 4 26803 /* QueryFlags.emitDistinctChangesOnly */ 26804 : 0 26805 /* QueryFlags.none */ 26806 ); 26807} 26808 26809function convertAttributesToExpressions(attributes) { 26810 const values = []; 26811 26812 for (let key of Object.getOwnPropertyNames(attributes)) { 26813 const value = attributes[key]; 26814 values.push(literal(key), value); 26815 } 26816 26817 return values; 26818} // Define and update any content queries 26819 26820 26821function createContentQueriesFunction(queries, constantPool, name) { 26822 const createStatements = []; 26823 const updateStatements = []; 26824 const tempAllocator = temporaryAllocator(updateStatements, TEMPORARY_NAME); 26825 26826 for (const query of queries) { 26827 // creation, e.g. r3.contentQuery(dirIndex, somePredicate, true, null); 26828 createStatements.push(importExpr(Identifiers.contentQuery).callFn([variable('dirIndex'), ...prepareQueryParams(query, constantPool)]).toStmt()); // update, e.g. (r3.queryRefresh(tmp = r3.loadQuery()) && (ctx.someDir = tmp)); 26829 26830 const temporary = tempAllocator(); 26831 const getQueryList = importExpr(Identifiers.loadQuery).callFn([]); 26832 const refresh = importExpr(Identifiers.queryRefresh).callFn([temporary.set(getQueryList)]); 26833 const updateDirective = variable(CONTEXT_NAME).prop(query.propertyName).set(query.first ? temporary.prop('first') : temporary); 26834 updateStatements.push(refresh.and(updateDirective).toStmt()); 26835 } 26836 26837 const contentQueriesFnName = name ? `${name}_ContentQueries` : null; 26838 return fn([new FnParam(RENDER_FLAGS, NUMBER_TYPE), new FnParam(CONTEXT_NAME, null), new FnParam('dirIndex', null)], [renderFlagCheckIfStmt(1 26839 /* core.RenderFlags.Create */ 26840 , createStatements), renderFlagCheckIfStmt(2 26841 /* core.RenderFlags.Update */ 26842 , updateStatements)], INFERRED_TYPE, null, contentQueriesFnName); 26843} 26844 26845function stringAsType(str) { 26846 return expressionType(literal(str)); 26847} 26848 26849function stringMapAsType(map) { 26850 const mapValues = Object.keys(map).map(key => { 26851 const value = Array.isArray(map[key]) ? map[key][0] : map[key]; 26852 return { 26853 key, 26854 value: literal(value), 26855 quoted: true 26856 }; 26857 }); 26858 return expressionType(literalMap(mapValues)); 26859} 26860 26861function stringArrayAsType(arr) { 26862 return arr.length > 0 ? expressionType(literalArr(arr.map(value => literal(value)))) : NONE_TYPE; 26863} 26864 26865function createBaseDirectiveTypeParams(meta) { 26866 // On the type side, remove newlines from the selector as it will need to fit into a TypeScript 26867 // string literal, which must be on one line. 26868 const selectorForType = meta.selector !== null ? meta.selector.replace(/\n/g, '') : null; 26869 return [typeWithParameters(meta.type.type, meta.typeArgumentCount), selectorForType !== null ? stringAsType(selectorForType) : NONE_TYPE, meta.exportAs !== null ? stringArrayAsType(meta.exportAs) : NONE_TYPE, stringMapAsType(meta.inputs), stringMapAsType(meta.outputs), stringArrayAsType(meta.queries.map(q => q.propertyName))]; 26870} 26871/** 26872 * Creates the type specification from the directive meta. This type is inserted into .d.ts files 26873 * to be consumed by upstream compilations. 26874 */ 26875 26876 26877function createDirectiveType(meta) { 26878 const typeParams = createBaseDirectiveTypeParams(meta); // Directives have no NgContentSelectors slot, but instead express a `never` type 26879 // so that future fields align. 26880 26881 typeParams.push(NONE_TYPE); 26882 typeParams.push(expressionType(literal(meta.isStandalone))); 26883 return expressionType(importExpr(Identifiers.DirectiveDeclaration, typeParams)); 26884} // Define and update any view queries 26885 26886 26887function createViewQueriesFunction(viewQueries, constantPool, name) { 26888 const createStatements = []; 26889 const updateStatements = []; 26890 const tempAllocator = temporaryAllocator(updateStatements, TEMPORARY_NAME);
26891 viewQueries.forEach(query => { 26892 // creation, e.g. r3.viewQuery(somePredicate, true); 26893 const queryDefinition = importExpr(Identifiers.viewQuery).callFn(prepareQueryParams(query, constantPool)); 26894 createStatements.push(queryDefinition.toStmt()); // update, e.g. (r3.queryRefresh(tmp = r3.loadQuery()) && (ctx.someDir = tmp)); 26895 26896 const temporary = tempAllocator(); 26897 const getQueryList = importExpr(Identifiers.loadQuery).callFn([]); 26898 const refresh = importExpr(Identifiers.queryRefresh).callFn([temporary.set(getQueryList)]); 26899 const updateDirective = variable(CONTEXT_NAME).prop(query.propertyName).set(query.first ? temporary.prop('first') : temporary); 26900 updateStatements.push(refresh.and(updateDirective).toStmt()); 26901 }); 26902 const viewQueryFnName = name ? `${name}_Query` : null; 26903 return fn([new FnParam(RENDER_FLAGS, NUMBER_TYPE), new FnParam(CONTEXT_NAME, null)], [renderFlagCheckIfStmt(1 26904 /* core.RenderFlags.Create */ 26905 , createStatements), renderFlagCheckIfStmt(2 26906 /* core.RenderFlags.Update */ 26907 , updateStatements)], INFERRED_TYPE, null, viewQueryFnName); 26908} // Return a host binding function or null if one is not necessary. 26909 26910 26911function createHostBindingsFunction(hostBindingsMetadata, typeSourceSpan, bindingParser, constantPool, selector, name, definitionMap) { 26912 const bindingContext = variable(CONTEXT_NAME); 26913 const styleBuilder = new StylingBuilder(bindingContext); 26914 const { 26915 styleAttr, 26916 classAttr 26917 } = hostBindingsMetadata.specialAttributes; 26918 26919 if (styleAttr !== undefined) { 26920 styleBuilder.registerStyleAttr(styleAttr); 26921 } 26922 26923 if (classAttr !== undefined) { 26924 styleBuilder.registerClassAttr(classAttr); 26925 } 26926 26927 const createInstructions = []; 26928 const updateInstructions = []; 26929 const updateVariables = []; 26930 const hostBindingSourceSpan = typeSourceSpan; // Calculate host event bindings 26931 26932 const eventBindings = bindingParser.createDirectiveHostEventAsts(hostBindingsMetadata.listeners, hostBindingSourceSpan); 26933 26934 if (eventBindings && eventBindings.length) { 26935 createInstructions.push(...createHostListeners(eventBindings, name)); 26936 } // Calculate the host property bindings 26937 26938 26939 const bindings = bindingParser.createBoundHostProperties(hostBindingsMetadata.properties, hostBindingSourceSpan); 26940 const allOtherBindings = []; // We need to calculate the total amount of binding slots required by 26941 // all the instructions together before any value conversions happen. 26942 // Value conversions may require additional slots for interpolation and 26943 // bindings with pipes. These calculates happen after this block. 26944 26945 let totalHostVarsCount = 0;
26946 bindings && bindings.forEach(binding => { 26947 const stylingInputWasSet = styleBuilder.registerInputBasedOnName(binding.name, binding.expression, hostBindingSourceSpan); 26948 26949 if (stylingInputWasSet) { 26950 totalHostVarsCount += MIN_STYLING_BINDING_SLOTS_REQUIRED; 26951 } else { 26952 allOtherBindings.push(binding); 26953 totalHostVarsCount++; 26954 } 26955 }); 26956 let valueConverter; 26957 26958 const getValueConverter = () => { 26959 if (!valueConverter) { 26960 const hostVarsCountFn = numSlots => { 26961 const originalVarsCount = totalHostVarsCount; 26962 totalHostVarsCount += numSlots; 26963 return originalVarsCount; 26964 }; 26965 26966 valueConverter = new ValueConverter(constantPool, () => error('Unexpected node'), // new nodes are illegal here 26967 hostVarsCountFn, () => error('Unexpected pipe')); // pipes are illegal here 26968 } 26969 26970 return valueConverter; 26971 }; 26972 26973 const propertyBindings = []; 26974 const attributeBindings = []; 26975 const syntheticHostBindings = []; 26976 26977 for (const binding of allOtherBindings) { 26978 // resolve literal arrays and literal objects 26979 const value = binding.expression.visit(getValueConverter()); 26980 const bindingExpr = bindingFn(bindingContext, value); 26981 const { 26982 bindingName, 26983 instruction, 26984 isAttribute 26985 } = getBindingNameAndInstruction(binding); 26986 const securityContexts = bindingParser.calcPossibleSecurityContexts(selector, bindingName, isAttribute).filter(context => context !== SecurityContext.NONE); 26987 let sanitizerFn = null; 26988 26989 if (securityContexts.length) { 26990 if (securityContexts.length === 2 && securityContexts.indexOf(SecurityContext.URL) > -1 && securityContexts.indexOf(SecurityContext.RESOURCE_URL) > -1) { 26991 // Special case for some URL attributes (such as "src" and "href") that may be a part 26992 // of different security contexts. In this case we use special sanitization function and 26993 // select the actual sanitizer at runtime based on a tag name that is provided while 26994 // invoking sanitization function. 26995 sanitizerFn = importExpr(Identifiers.sanitizeUrlOrResourceUrl); 26996 } else { 26997 sanitizerFn = resolveSanitizationFn(securityContexts[0], isAttribute); 26998 } 26999 } 27000 27001 const instructionParams = [literal(bindingName), bindingExpr.currValExpr]; 27002 27003 if (sanitizerFn) { 27004 instructionParams.push(sanitizerFn); 27005 } else { 27006 // If there was no sanitization function found based on the security context 27007 // of an attribute/property binding - check whether this attribute/property is 27008 // one of the security-sensitive <iframe> attributes. 27009 // Note: for host bindings defined on a directive, we do not try to find all 27010 // possible places where it can be matched, so we can not determine whether 27011 // the host element is an <iframe>. In this case, if an attribute/binding 27012 // name is in the `IFRAME_SECURITY_SENSITIVE_ATTRS` set - append a validation 27013 // function, which would be invoked at runtime and would have access to the 27014 // underlying DOM element, check if it's an <iframe> and if so - runs extra checks. 27015 if (isIframeSecuritySensitiveAttr(bindingName)) { 27016 instructionParams.push(importExpr(Identifiers.validateIframeAttribute)); 27017 } 27018 } 27019 27020 updateVariables.push(...bindingExpr.stmts); 27021 27022 if (instruction === Identifiers.hostProperty) { 27023 propertyBindings.push(instructionParams); 27024 } else if (instruction === Identifiers.attribute) { 27025 attributeBindings.push(instructionParams); 27026 } else if (instruction === Identifiers.syntheticHostProperty) { 27027 syntheticHostBindings.push(instructionParams); 27028 } else { 27029 updateInstructions.push({ 27030 reference: instruction, 27031 paramsOrFn: instructionParams, 27032 span: null 27033 }); 27034 } 27035 } 27036 27037 for (const bindingParams of propertyBindings) { 27038 updateInstructions.push({ 27039 reference: Identifiers.hostProperty, 27040 paramsOrFn: bindingParams, 27041 span: null 27042 }); 27043 } 27044 27045 for (const bindingParams of attributeBindings) { 27046 updateInstructions.push({ 27047 reference: Identifiers.attribute, 27048 paramsOrFn: bindingParams, 27049 span: null 27050 }); 27051 } 27052 27053 for (const bindingParams of syntheticHostBindings) { 27054 updateInstructions.push({ 27055 reference: Identifiers.syntheticHostProperty, 27056 paramsOrFn: bindingParams, 27057 span: null 27058 }); 27059 } // since we're dealing with directives/components and both have hostBinding 27060 // functions, we need to generate a special hostAttrs instruction that deals 27061 // with both the assignment of styling as well as static attributes to the host 27062 // element. The instruction below will instruct all initial styling (styling 27063 // that is inside of a host binding within a directive/component) to be attached 27064 // to the host element alongside any of the provided host attributes that were 27065 // collected earlier. 27066 27067 27068 const hostAttrs = convertAttributesToExpressions(hostBindingsMetadata.attributes); 27069 styleBuilder.assignHostAttrs(hostAttrs, definitionMap); 27070 27071 if (styleBuilder.hasBindings) { 27072 // finally each binding that was registered in the statement above will need to be added to 27073 // the update block of a component/directive templateFn/hostBindingsFn so that the bindings 27074 // are evaluated and updated for the element. 27075 styleBuilder.buildUpdateLevelInstructions(getValueConverter()).forEac
27075h(instruction => { 27076 for (const call of instruction.calls) { 27077 // we subtract a value of `1` here because the binding slot was already allocated 27078 // at the top of this method when all the input bindings were counted. 27079 totalHostVarsCount += Math.max(call.allocateBindingSlots - MIN_STYLING_BINDING_SLOTS_REQUIRED, 0); 27080 updateInstructions.push({ 27081 reference: instruction.reference, 27082 paramsOrFn: convertStylingCall(call, bindingContext, bindingFn), 27083 span: null 27084 }); 27085 } 27086 }); 27087 } 27088 27089 if (totalHostVarsCount) { 27090 definitionMap.set('hostVars', literal(totalHostVarsCount)); 27091 } 27092 27093 if (createInstructions.length > 0 || updateInstructions.length > 0) { 27094 const hostBindingsFnName = name ? `${name}_HostBindings` : null; 27095 const statements = []; 27096 27097 if (createInstructions.length > 0) { 27098 statements.push(renderFlagCheckIfStmt(1 27099 /* core.RenderFlags.Create */ 27100 , getInstructionStatements(createInstructions))); 27101 } 27102 27103 if (updateInstructions.length > 0) { 27104 statements.push(renderFlagCheckIfStmt(2 27105 /* core.RenderFlags.Update */ 27106 , updateVariables.concat(getInstructionStatements(updateInstructions)))); 27107 } 27108 27109 return fn([new FnParam(RENDER_FLAGS, NUMBER_TYPE), new FnParam(CONTEXT_NAME, null)], statements, INFERRED_TYPE, null, hostBindingsFnName); 27110 } 27111 27112 return null; 27113} 27114 27115function bindingFn(implicit, value) { 27116 return convertPropertyBinding(null, implicit, value, 'b'); 27117} 27118 27119function convertStylingCall(call, bindingContext, bindingFn) { 27120 return call.params(value => bindingFn(bindingContext, value).currValExpr); 27121} 27122 27123function getBindingNameAndInstruction(binding) { 27124 let bindingName = binding.name; 27125 let instruction; // Check to see if this is an attr binding or a property binding 27126 27127 const attrMatches = bindingName.match(ATTR_REGEX); 27128 27129 if (attrMatches) { 27130 bindingName = attrMatches[1]; 27131 instruction = Identifiers.attribute; 27132 } else { 27133 if (binding.isAnimation) { 27134 bindingName = prepareSyntheticPropertyName(bindingName); // host bindings that have a synthetic property (e.g. @foo) should always be rendered 27135 // in the context of the component and not the parent. Therefore there is a special 27136 // compatibility instruction available for this purpose. 27137 27138 instruction = Identifiers.syntheticHostProperty; 27139 } else { 27140 instruction = Identifiers.hostProperty; 27141 } 27142 } 27143 27144 return { 27145 bindingName, 27146 instruction, 27147 isAttribute: !!attrMatches 27148 }; 27149} 27150 27151function createHostListeners(eventBindings, name) { 27152 const listenerParams = []; 27153 const syntheticListenerParams = []; 27154 const instructions = []; 27155 27156 for (const binding of eventBindings) { 27157 let bindingName = binding.name && sanitizeIdentifier(binding.name); 27158 const bindingFnName = binding.type === 1 27159 /* ParsedEventType.Animation */ 27160 ? prepareSyntheticListenerFunctionName(bindingName, binding.targetOrPhase) : bindingName; 27161 const handlerName = name && bindingName ? `${name}_${bindingFnName}_HostBindingHandler` : null; 27162 const params = prepareEventListenerParameters(BoundEvent.fromParsedEvent(binding), handlerName); 27163 27164 if (binding.type == 1 27165 /* ParsedEventType.Animation */ 27166 ) { 27167 syntheticListenerParams.push(params); 27168 } else { 27169 listenerParams.push(params); 27170 } 27171 } 27172 27173 for (const params of syntheticListenerParams) { 27174 instructions.push({ 27175 reference: Identifiers.syntheticHostListener, 27176 paramsOrFn: params, 27177 span: null 27178 }); 27179 } 27180 27181 for (const params of listenerParams) { 27182 instructions.push({ 27183 reference: Identifiers.listener, 27184 paramsOrFn: params, 27185 span: null 27186 }); 27187 } 27188 27189 return instructions; 27190} 27191 27192const HOST_REG_EXP = /^(?:\[([^\]]+)\])|(?:\(([^\)]+)\))$/; 27193 27194function parseHostBindings(host) { 27195 const attributes = {}; 27196 const listeners = {}; 27197 const properties = {}; 27198 const specialAttributes = {}; 27199 27200 for (const key of Object.keys(host)) { 27201 const value = host[key]; 27202 const matches = key.match(HOST_REG_EXP); 27203 27204 if (matches === null) { 27205 switch (key) { 27206 case 'class': 27207 if (typeof value !== 'string') { 27208 // TODO(alxhub): make this a diagnostic. 27209 throw new Error(`Class binding must be string`); 27210 } 27211 27212 specialAttributes.classAttr = value; 27213 break; 27214 27215 case 'style': 27216 if (typeof value !== 'string') { 27217 // TODO(alxhub): make this a diagnostic. 27218 throw new Error(`Style binding must be string`); 27219 } 27220 27221 specialAttributes.styleAttr = value; 27222 break; 27223 27224 default: 27225 if (typeof value === 'string') { 27226 attributes[key] = literal(value); 27227 } else { 27228 attributes[key] = value; 27229 } 27230 27231 } 27232 } else if (matches[1 27233 /* HostBindingGroup.Binding */ 27234 ] != null) { 27235 if (typeof value !== 'string') { 27236 // TODO(alxhub): make this a diagnostic. 27237 throw new Error(`Property binding must be string`); 27238 } // synthetic properties (the ones that have a `@` as a prefix) 27239 // are still treated the same as regular properties. Therefore 27240 // there is no point in storing them in a separate map. 27241 27242 27243 properties[matches[1 27244 /* HostBindingGroup.Binding */ 27245 ]] = value; 27246 } else if (matches[2 27247 /* HostBindingGroup.Event */ 27248 ] != null) { 27249 if (typeof value !== 'string') { 27250 // TODO(alxhub): make this a diagnostic. 27251 throw new Error(`Event binding must be string`); 27252 } 27253 27254 listeners[matches[2 27255 /* HostBindingGroup.Event */ 27256 ]] = value; 27257 } 27258 } 27259 27260 return { 27261 attributes, 27262 listeners, 27263 properties, 27264 specialAttributes 27265 }; 27266} 27267/** 27268 * Verifies host bindings and returns the list of errors (if any). Empty array indicates that a 27269 * given set of host bindings has no errors. 27270 * 27271 * @param bindings set of host bindings to verify. 27272 * @param sourceSpan source span where host bindings were defined. 27273 * @returns array of errors associated with a given set of host bindings. 27274 */ 27275 27276 27277function verifyHostBindings(bindings, sourceSpan) { 27278 // TODO: abstract out host bindings verification logic and use it instead of 27279 // creating events and properties ASTs to detect errors (FW-996) 27280 const bindingParser = makeBindingParser(); 27281 bindingParser.createDirectiveHostEventAsts(bindings.listeners, sourceSpan); 27282 bindingParser.createBoundHostProperties(bindings.properties, sourceSpan); 27283 return bindingParser.errors; 27284} 27285 27286function compileStyles(styles, selector, hostSelector) { 27287 const shadowCss = new ShadowCss(); 27288 return styles.map(style => { 27289 return shadowCss.shimCssText(style, selector, hostSelector); 27290 }); 27291} 27292/** 27293 * @license 27294 * Copyright Google LLC All Rights Reserved. 27295 * 27296 * Use of this source code is governed by an MIT-style license that can be 27297 * found in the LICENSE file at https://angular.io/license 27298 */ 27299 27300/** 27301 * An interface for retrieving documents by URL that the compiler uses to 27302 * load templates. 27303 * 27304 * This is an abstract class, rather than an interface, so that it can be used 27305 * as injection token. 27306 */ 27307 27308 27309class ResourceLoader {} 27310/** 27311 * @license 27312 * Copyright Google LLC All Rights Reserved. 27313 * 27314 * Use of this source code is governed by an MIT-style license that can be 27315 * found in the LICENSE file at https://angular.io/license 27316 */ 27317 27318 27319class CompilerFacadeImpl {
27320 constructor(jitEvaluator = new JitEvaluator()) { 27321 this.jitEvaluator = jitEvaluator; 27322 this.FactoryTarget = FactoryTarget$1; 27323 this.ResourceLoader = ResourceLoader; 27324 this.elementSchemaRegistry = new DomElementSchemaRegistry(); 27325 } 27326 27327 compilePipe(angularCoreEnv, sourceMapUrl, facade) { 27328 const metadata = { 27329 name: facade.name, 27330 type: wrapReference(facade.type), 27331 internalType: new WrappedNodeExpr(facade.type), 27332 typeArgumentCount: 0, 27333 deps: null, 27334 pipeName: facade.pipeName, 27335 pure: facade.pure, 27336 isStandalone: facade.isStandalone 27337 }; 27338 const res = compilePipeFromMetadata(metadata); 27339 return this.jitExpression(res.expression, angularCoreEnv, sourceMapUrl, []); 27340 } 27341 27342 compilePipeDeclaration(angularCoreEnv, sourceMapUrl, declaration) { 27343 const meta = convertDeclarePipeFacadeToMetadata(declaration); 27344 const res = compilePipeFromMetadata(meta); 27345 return this.jitExpression(res.expression, angularCoreEnv, sourceMapUrl, []); 27346 } 27347 27348 compileInjectable(angularCoreEnv, sourceMapUrl, facade) { 27349 const { 27350 expression, 27351 statements 27352 } = compileInjectable({ 27353 name: facade.name, 27354 type: wrapReference(facade.type), 27355 internalType: new WrappedNodeExpr(facade.type), 27356 typeArgumentCount: facade.typeArgumentCount, 27357 providedIn: computeProvidedIn(facade.providedIn), 27358 useClass: convertToProviderExpression(facade, 'useClass'), 27359 useFactory: wrapExpression(facade, 'useFactory'), 27360 useValue: convertToProviderExpression(facade, 'useValue'), 27361 useExisting: convertToProviderExpression(facade, 'useExisting'), 27362 deps: facade.deps?.map(convertR3DependencyMetadata) 27363 }, 27364 /* resolveForwardRefs */ 27365 true); 27366 return this.jitExpression(expression, angularCoreEnv, sourceMapUrl, statements); 27367 } 27368 27369 compileInjectableDeclaration(angularCoreEnv, sourceMapUrl, facade) { 27370 const { 27371 expression, 27372 statements 27373 } = compileInjectable({ 27374 name: facade.type.name, 27375 type: wrapReference(facade.type), 27376 internalType: new WrappedNodeExpr(facade.type), 27377 typeArgumentCount: 0, 27378 providedIn: computeProvidedIn(facade.providedIn), 27379 useClass: convertToProviderExpression(facade, 'useClass'), 27380 useFactory: wrapExpression(facade, 'useFactory'), 27381 useValue: convertToProviderExpression(facade, 'useValue'), 27382 useExisting: convertToProviderExpression(facade, 'useExisting'), 27383 deps: facade.deps?.map(convertR3DeclareDependencyMetadata) 27384 }, 27385 /* resolveForwardRefs */ 27386 true); 27387 return this.jitExpression(expression, angularCoreEnv, sourceMapUrl, statements); 27388 } 27389 27390 compileInjector(angularCoreEnv, sourceMapUrl, facade) { 27391 const meta = { 27392 name: facade.name, 27393 type: wrapReference(facade.type), 27394 internalType: new WrappedNodeExpr(facade.type), 27395 providers: facade.providers && facade.providers.length > 0 ? new WrappedNodeExpr(facade.providers) : null, 27396 imports: facade.imports.map(i => new WrappedNodeExpr(i)) 27397 }; 27398 const res = compileInjector(meta); 27399 return this.jitExpression(res.expression, angularCoreEnv, sourceMapUrl, []); 27400 } 27401 27402 compileInjectorDeclaration(angularCoreEnv, sourceMapUrl, declaration) { 27403 const meta = convertDeclareInjectorFacadeToMetadata(declaration); 27404 const res = compileInjector(meta); 27405 return this.jitExpression(res.expression, angularCoreEnv, sourceMapUrl, []); 27406 } 27407 27408 compileNgModule(angularCoreEnv, sourceMapUrl, facade) { 27409 const meta = { 27410 type: wrapReference(facade.type), 27411 internalType: new WrappedNodeExpr(facade.type), 27412 adjacentType: new WrappedNodeExpr(facade.type), 27413 bootstrap: facade.bootstrap.map(wrapReference), 27414 declarations: facade.declarations.map(wrapReference), 27415 publicDeclarationTypes: null, 27416 imports: facade.imports.map(wrapReference), 27417 includeImportTypes: true, 27418 exports: facade.exports.map(wrapReference), 27419 selectorScopeMode: R3SelectorScopeMode.Inline, 27420 containsForwardDecls: false, 27421 schemas: facade.schemas ? facade.schemas.map(wrapReference) : null, 27422 id: facade.id ? new WrappedNodeExpr(facade.id) : null 27423 }; 27424 const res = compileNgModule(meta); 27425 return this.jitExpression(res.expression, angularCoreEnv, sourceMapUrl, []); 27426 } 27427 27428 compileNgModuleDeclaration(angularCoreEnv, sourceMapUrl, declaration) { 27429 const expression = compileNgModuleDeclarationExpression(declaration); 27430 return this.jitExpression(expression, angularCoreEnv, sourceMapUrl, []); 27431 } 27432 27433 compileDirective(angularCoreEnv, sourceMapUrl, facade) { 27434 const meta = convertDirectiveFacadeToMetadata(facade); 27435 return this.compileDirectiveFromMeta(angularCoreEnv, sourceMapUrl, meta); 27436 } 27437 27438 compileDirectiveDeclaration(angularCoreEnv, sourceMapUrl, declaration) { 27439 const typeSourceSpan = this.createParseSourceSpan('Directive', declaration.type.name, sourceMapUrl); 27440 const meta = convertDeclareDirectiveFacadeToMetadata(declaration, typeSourceSpan); 27441 return this.compileDirectiveFromMeta(angularCoreEnv, sourceMapUrl, meta); 27442 } 27443 27444 compileDirectiveFromMeta(angularCoreEnv, sourceMapUrl, meta) { 27445 const constantPool = new ConstantPool(); 27446 const bindingParser = makeBindingParser(); 27447 const res = compileDirectiveFromMetadata(meta, constantPool, bindingParser); 27448 return this.jitExpression(res.expression, angularCoreEnv, sourceMapUrl, constantPool.statements); 27449 } 27450 27451 compileComponent(angularCoreEnv, sourceMapUrl, facade) { 27452 // Parse the template and check for errors. 27453 const { 27454 template, 27455 interpolation 27456 } = parseJitTemplate(facade.template, facade.name, sourceMapUrl, facade.preserveWhitespace
27456s, facade.interpolation); // Compile the component metadata, including template, into an expression. 27457 27458 const meta = { ...facade, 27459 ...convertDirectiveFacadeToMetadata(facade), 27460 selector: facade.selector || this.elementSchemaRegistry.getDefaultComponentElementName(), 27461 template, 27462 declarations: facade.declarations.map(convertDeclarationFacadeToMetadata), 27463 declarationListEmitMode: 0 27464 /* DeclarationListEmitMode.Direct */ 27465 , 27466 styles: [...facade.styles, ...template.styles], 27467 encapsulation: facade.encapsulation, 27468 interpolation, 27469 changeDetection: facade.changeDetection, 27470 animations: facade.animations != null ? new WrappedNodeExpr(facade.animations) : null, 27471 viewProviders: facade.viewProviders != null ? new WrappedNodeExpr(facade.viewProviders) : null, 27472 relativeContextFilePath: '', 27473 i18nUseExternalIds: true 27474 }; 27475 const jitExpressionSourceMap = `ng:///${facade.name}.js`; 27476 return this.compileComponentFromMeta(angularCoreEnv, jitExpressionSourceMap, meta); 27477 } 27478 27479 compileComponentDeclaration(angularCoreEnv, sourceMapUrl, declaration) { 27480 const typeSourceSpan = this.createParseSourceSpan('Component', declaration.type.name, sourceMapUrl); 27481 const meta = convertDeclareComponentFacadeToMetadata(declaration, typeSourceSpan, sourceMapUrl); 27482 return this.compileComponentFromMeta(angularCoreEnv, sourceMapUrl, meta); 27483 } 27484 27485 compileComponentFromMeta(angularCoreEnv, sourceMapUrl, meta) { 27486 const constantPool = new ConstantPool(); 27487 const bindingParser = makeBindingParser(meta.interpolation); 27488 const res = compileComponentFromMetadata(meta, constantPool, bindingParser); 27489 return this.jitExpression(res.expression, angularCoreEnv, sourceMapUrl, constantPool.statements); 27490 } 27491 27492 compileFactory(angularCoreEnv, sourceMapUrl, meta) { 27493 const factoryRes = compileFactoryFunction({ 27494 name: meta.name, 27495 type: wrapReference(meta.type), 27496 internalType: new WrappedNodeExpr(meta.type), 27497 typeArgumentCount: meta.typeArgumentCount, 27498 deps: convertR3DependencyMetadataArray(meta.deps), 27499 target: meta.target 27500 }); 27501 return this.jitExpression(factoryRes.expression, angularCoreEnv, sourceMapUrl, factoryRes.statements); 27502 } 27503 27504 compileFactoryDeclaration(angularCoreEnv, sourceMapUrl, meta) { 27505 const factoryRes = compileFactoryFunction({ 27506 name: meta.type.name, 27507 type: wrapReference(meta.type), 27508 internalType: new WrappedNodeExpr(meta.type), 27509 typeArgumentCount: 0, 27510 deps: Array.isArray(meta.deps) ? meta.deps.map(convertR3DeclareDependencyMetadata) : meta.deps, 27511 target: meta.target 27512 }); 27513 return this.jitExpression(factoryRes.expression, angularCoreEnv, sourceMapUrl, factoryRes.statements); 27514 } 27515 27516 createParseSourceSpan(kind, typeName, sourceUrl) { 27517 return r3JitTypeSourceSpan(kind, typeName, sourceUrl); 27518 } 27519 /** 27520 * JIT compiles an expression and returns the result of executing that expression. 27521 * 27522 * @param def the definition which will be compiled and executed to get the value to patch 27523 * @param context an object map of @angular/core symbol names to symbols which will be available 27524 * in the context of the compiled expression 27525 * @param sourceUrl a URL to use for the source map of the compiled expression 27526 * @param preStatements a collection of statements that should be evaluated before the expression. 27527 */ 27528 27529 27530 jitExpression(def, context, sourceUrl, preStatements) { 27531 // The ConstantPool may contain Statements which declare variables used in the final expression. 27532 // Therefore, its statements need to precede the actual JIT operation. The final statement is a 27533 // declaration of $def which is set to the expression being compiled. 27534 const statements = [...preStatements, new DeclareVarStmt('$def', def, undefined, StmtModifier.Exported)]; 27535 const res = this.jitEvaluator.evaluateStatements(sourceUrl, statements, new R3JitReflector(context), 27536 /* enableSourceMaps */ 27537 true); 27538 return res['$def']; 27539 } 27540 27541} 27542 27543function convertToR3QueryMetadata(facade) { 27544 return { ...facade, 27545 predicate: convertQueryPredicate(facade.predicate), 27546 read: facade.read ? new WrappedNodeExpr(facade.read) : null, 27547 static: facade.static, 27548 emitDistinctChangesOnly: facade.emitDistinctChangesOnly 27549 }; 27550} 27551 27552function convertQueryDeclarationToMetadata(declaration) { 27553 return { 27554 propertyName: declaration.propertyName, 27555 first: declaration.first ?? false, 27556 predicate: convertQueryPredicate(declaration.predicate), 27557 descendants: declaration.descendants ?? false, 27558 read: declaration.read ? new WrappedNodeExpr(declaration.read) : null, 27559 static: declaration.static ?? false, 27560 emitDistinctChangesOnly: declaration.emitDistinctChangesOnly ?? true 27561 }; 27562} 27563 27564function convertQueryPredicate(predicate) { 27565 return Array.isArray(predicate) ? // The predicate is an array of str
27565ings so pass it through. 27566 predicate : // The predicate is a type - assume that we will need to unwrap any `forwardRef()` calls. 27567 createMayBeForwardRefExpression(new WrappedNodeExpr(predicate), 1 27568 /* ForwardRefHandling.Wrapped */ 27569 ); 27570} 27571 27572function convertDirectiveFacadeToMetadata(facade) { 27573 const inputsFromMetadata = parseInputOutputs(facade.inputs || []); 27574 const outputsFromMetadata = parseInputOutputs(facade.outputs || []); 27575 const propMetadata = facade.propMetadata; 27576 const inputsFromType = {}; 27577 const outputsFromType = {}; 27578 27579 for (const field in propMetadata) { 27580 if (propMetadata.hasOwnProperty(field)) { 27581 propMetadata[field].forEach(ann => { 27582 if (isInput(ann)) { 27583 inputsFromType[field] = ann.bindingPropertyName ? [ann.bindingPropertyName, field] : field; 27584 } else if (isOutput(ann)) { 27585 outputsFromType[field] = ann.bindingPropertyName || field; 27586 } 27587 }); 27588 } 27589 } 27590 27591 return { ...facade, 27592 typeArgumentCount: 0, 27593 typeSourceSpan: facade.typeSourceSpan, 27594 type: wrapReference(facade.type), 27595 internalType: new WrappedNodeExpr(facade.type), 27596 deps: null, 27597 host: extractHostBindings(facade.propMetadata, facade.typeSourceSpan, facade.host), 27598 inputs: { ...inputsFromMetadata, 27599 ...inputsFromType 27600 }, 27601 outputs: { ...outputsFromMetadata, 27602 ...outputsFromType 27603 }, 27604 queries: facade.queries.map(convertToR3QueryMetadata), 27605 providers: facade.providers != null ? new WrappedNodeExpr(facade.providers) : null, 27606 viewQueries: facade.viewQueries.map(convertToR3QueryMetadata), 27607 fullInheritance: false 27608 }; 27609} 27610 27611function convertDeclareDirectiveFacadeToMetadata(declaration, typeSourceSpan) { 27612 return { 27613 name: declaration.type.name, 27614 type: wrapReference(declaration.type), 27615 typeSourceSpan, 27616 internalType: new WrappedNodeExpr(declaration.type), 27617 selector: declaration.selector ?? null, 27618 inputs: declaration.inputs ?? {}, 27619 outputs: declaration.outputs ?? {}, 27620 host: convertHostDeclarationToMetadata(declaration.host), 27621 queries: (declaration.queries ?? []).map(convertQueryDeclarationToMetadata), 27622 viewQueries: (declaration.viewQueries ?? []).map(convertQueryDeclarationToMetadata), 27623 providers: declaration.providers !== undefined ? new WrappedNodeExpr(declaration.providers) : null, 27624 exportAs: declaration.exportAs ?? null, 27625 usesInheritance: declaration.usesInheritance ?? false, 27626 lifecycle: { 27627 usesOnChanges: declaration.usesOnChanges ?? false 27628 }, 27629 deps: null, 27630 typeArgumentCount: 0, 27631 fullInheritance: false, 27632 isStandalone: declaration.isStandalone ?? false 27633 }; 27634} 27635 27636function convertHostDeclarationToMetadata(host = {}) { 27637 return { 27638 attributes: convertOpaqueValuesToExpressions(host.attributes ?? {}), 27639 listeners: host.listeners ?? {}, 27640 properties: host.properties ?? {}, 27641 specialAttributes: { 27642 classAttr: host.classAttribute, 27643 styleAttr: host.styleAttribute 27644 } 27645 }; 27646} 27647 27648function convertOpaqueValuesToExpressions(obj) { 27649 const result = {}; 27650 27651 for (const key of Object.keys(obj)) { 27652 result[key] = new WrappedNodeExpr(obj[key]); 27653 } 27654 27655 return result; 27656} 27657 27658function convertDeclareComponentFacadeToMetadata(decl, typeSourceSpan, sourceMapUrl) { 27659 const { 27660 template, 27661 interpolation 27662 } = parseJitTemplate(decl.template, decl.type.name, sourceMapUrl, decl.preserveWhitespaces ?? false, decl.interpolation); 27663 const declarations = []; 27664 27665 if (decl.dependencies) { 27666 for (const innerDep of decl.dependencies) { 27667 switch (innerDep.kind) { 27668 case 'directive': 27669 case 'component': 27670 declarations.push(convertDirectiveDeclarationToMetadata(innerDep)); 27671 break; 27672 27673 case 'pipe': 27674 declarations.push(convertPipeDeclarationToMetadata(innerDep)); 27675 break; 27676 } 27677 } 27678 } else if (decl.components || decl.directives || decl.pipes) { 27679 // Existing declarations on NPM may not be using the new `dependencies` merged field, and may 27680 // have separate fields for dependencies instead. Unify them for JIT compilation. 27681 decl.components && declarations.push(...decl.components.map(dir => convertDirectiveDeclarationToMetadata(dir, 27682 /* isComponent */ 27683 true))); 27684 decl.directives && declarations.push(...decl.directives.map(dir => convertDirectiveDeclarationToMetadata(dir))); 27685 decl.pipes && declarations.push(...convertPipeMapToMetadata(decl.pipes)); 27686 } 27687 27688 return { ...convertDeclareDirectiveFacadeToMetadata(decl, typeSourceSpan), 27689 template, 27690 styles: decl.styles ?? [], 27691 declarations, 27692 viewProviders: decl.viewProviders !== undefined ? new WrappedNodeExpr(decl.viewProviders) : null, 27693 animations: decl.animations !== undefined ? new WrappedNodeExpr(decl.animations) : null, 27694 changeDetection: decl.changeDetection ?? ChangeDetectionStrategy.Default, 27695 encapsulation: decl.encapsulation ?? ViewEncapsulation.Emulated, 27696 interpolation, 27697 declarationListEmitMode: 2 27698 /* DeclarationListEmitMode.ClosureResolved */ 27699 , 27700 relativeContextFilePath: '', 27701 i18nUseExternalIds: true 27702 }; 27703} 27704 27705function convertDeclarationFacadeToMetadata(declaration) { 27706 return { ...declaration, 27707 type: new WrappedNodeExpr(declaration.type) 27708 }; 27709} 27710 27711function convertDirectiveDeclarationToMetadata(declaration, isComponent = null) { 27712 return { 27713 kind: R3TemplateDependencyKind.Directive, 27714 isComponent: isComponent || declaration.kind === 'component', 27715 selector: declaration.selector, 27716 type: new WrappedNodeExpr(declaration.type), 27717 inputs: declaration.inputs ?? [], 27718 outputs: declaration.outputs ?? [], 27719 exportAs: declaration.exportAs ?? null 27720 }; 27721} 27722 27723function convertPipeMapToMetadata(pipes) { 27724 if (!pipes) { 27725 return []; 27726 } 27727 27728 return Object.keys(pipes).map(name => { 27729 return { 27730 kind: R3TemplateDependencyKind.Pipe, 27731 name, 27732 type: new WrappedNodeExpr(pipes[name]) 27733 }; 27734 }); 27735} 27736 27737function convertPipeDeclarationToMetadata(pipe) { 27738 return { 27739 kind: R3TemplateDependencyKind.Pipe, 27740 name: pipe.name, 27741 type: new WrappedNodeExpr(pipe.type) 27742 }; 27743} 27744 27745function parseJitTemplate(template, typeName, sourceMapUrl, preserveWhitespace
27745s, interpolation) { 27746 const interpolationConfig = interpolation ? InterpolationConfig.fromArray(interpolation) : DEFAULT_INTERPOLATION_CONFIG; // Parse the template and check for errors. 27747 27748 const parsed = parseTemplate(template, sourceMapUrl, { 27749 preserveWhitespaces, 27750 interpolationConfig 27751 }); 27752 27753 if (parsed.errors !== null) { 27754 const errors = parsed.errors.map(err => err.toString()).join(', '); 27755 throw new Error(`Errors during JIT compilation of template for ${typeName}: ${errors}`); 27756 } 27757 27758 return { 27759 template: parsed, 27760 interpolation: interpolationConfig 27761 }; 27762} 27763/** 27764 * Convert the expression, if present to an `R3ProviderExpression`. 27765 * 27766 * In JIT mode we do not want the compiler to wrap the expression in a `forwardRef()` call because, 27767 * if it is referencing a type that has not yet been defined, it will have already been wrapped in 27768 * a `forwardRef()` - either by the application developer or during partial-compilation. Thus we can 27769 * use `ForwardRefHandling.None`. 27770 */ 27771 27772 27773function convertToProviderExpression(obj, property) { 27774 if (obj.hasOwnProperty(property)) { 27775 return createMayBeForwardRefExpression(new WrappedNodeExpr(obj[property]), 0 27776 /* ForwardRefHandling.None */ 27777 ); 27778 } else { 27779 return undefined; 27780 } 27781} 27782 27783function wrapExpression(obj, property) { 27784 if (obj.hasOwnProperty(property)) { 27785 return new WrappedNodeExpr(obj[property]); 27786 } else { 27787 return undefined; 27788 } 27789} 27790 27791function computeProvidedIn(providedIn) { 27792 const expression = typeof providedIn === 'function' ? new WrappedNodeExpr(providedIn) : new LiteralExpr(providedIn ?? null); // See `convertToProviderExpression()` for why this uses `ForwardRefHandling.None`. 27793 27794 return createMayBeForwardRefExpression(expression, 0 27795 /* ForwardRefHandling.None */ 27796 ); 27797} 27798 27799function convertR3DependencyMetadataArray(facades) { 27800 return facades == null ? null : facades.map(convertR3DependencyMetadata); 27801} 27802 27803function convertR3DependencyMetadata(facade) { 27804 const isAttributeDep = facade.attribute != null; // both `null` and `undefined` 27805 27806 const rawToken = facade.token === null ? null : new WrappedNodeExpr(facade.token); // In JIT mode, if the dep is an `@Attribute()` then we use the attribute name given in 27807 // `attribute` rather than the `token`. 27808 27809 const token = isAttributeDep ? new WrappedNodeExpr(facade.attribute) : rawToken; 27810 return createR3DependencyMetadata(token, isAttributeDep, facade.host, facade.optional, facade.self, facade.skipSelf); 27811} 27812 27813function convertR3DeclareDependencyMetadata(facade) { 27814 const isAttributeDep = facade.attribute ?? false; 27815 const token = facade.token === null ? null : new WrappedNodeExpr(facade.token); 27816 return createR3DependencyMetadata(token, isAttributeDep, facade.host ?? false, facade.optional ?? false, facade.self ?? false, facade.skipSelf ?? false); 27817} 27818 27819function createR3DependencyMetadata(token, isAttributeDep, host, optional, self, skipSelf) { 27820 // If the dep is an `@Attribute()` the `attributeNameType` ought to be the `unknown` type. 27821 // But types are not available at runtime so we just use a literal `"<unknown>"` string as a dummy 27822 // marker. 27823 const attributeNameType = isAttributeDep ? literal('unknown') : null; 27824 return { 27825 token, 27826 attributeNameType, 27827 host, 27828 optional, 27829 self, 27830 skipSelf 27831 }; 27832} 27833 27834function extractHostBindings(propMetadata, sourceSpan, host) { 27835 // First parse the declarations from the metadata. 27836 const bindings = parseHostBindings(host || {}); // After that check host bindings for errors 27837 27838 const errors = verifyHostBindings(bindings, sourceSpan); 27839 27840 if (errors.length) { 27841 throw new Error(errors.map(error => error.msg).join('\n')); 27842 } // Next, loop over the properties of the object, looking for @HostBinding and @HostListener. 27843 27844 27845 for (const field in propMetadata) { 27846 if (propMetadata.hasOwnProperty(field)) { 27847 propMetadata[field].forEach(ann => { 27848 if (isHostBinding(ann)) { 27849 // Since this is a decorator, we know that the value is a class member. Always access it 27850 // through `this` so that further down the line it can't be confused for a literal value 27851 // (e.g. if there's a property called `true`). 27852 bindings.properties[ann.hostPropertyName || field] = getSafePropertyAccessString('this', field); 27853 } else if (isHostListener(ann)) { 27854 bindings.listeners[ann.eventName || field] = `${field}(${(ann.args || []).join(',')})`; 27855 } 27856 }); 27857 } 27858 } 27859 27860 return bindings; 27861} 27862 27863function isHostBinding(value) { 27864 return value.ngMetadataName === 'HostBinding'; 27865} 27866 27867function isHostListener(value) { 27868 return value.ngMetadataName === 'HostListener'; 27869} 27870 27871function isInput(value) { 27872 return value.ngMetadataName === 'Input'; 27873} 27874 27875function isOutput(value) { 27876 return value.ngMetadataName === 'Output'; 27877} 27878 27879function parseInputOutputs(values) { 27880 return values.reduce((results, value) => { 27881 const [field, property] = value.split(':', 2).map(str => str.trim()); 27882 results[field] = property || field; 27883 return results; 27884 }, {}); 27885} 27886 27887function convertDeclarePipeFacadeToMetadata(declaration) { 27888 return { 27889 name: declaration.type.name, 27890 type: wrapReference(declaration.type), 27891 internalType: new WrappedNodeExpr(declaration.type), 27892 typeArgumentCount: 0, 27893 pipeName: declaration.name, 27894 deps: null, 27895 pure: declaration.pure ?? true, 27896 isStandalone: declaration.isStandalone ?? false 27897 }; 27898} 27899 27900function convertDeclareInjectorFacadeToMetadata(declaration) { 27901 return { 27902 name: declaration.type.name, 27903 type: wrapReference(declaration.type), 27904 internalType: new WrappedNodeExpr(declaration.type), 27905 providers: declaration.providers !== undefined && declaration.providers.length > 0 ? new WrappedNodeExpr(declaration.providers) : null, 27906 imports: declaration.imports !== undefined ? declaration.imports.map(i => new WrappedNodeExpr(i)) : [] 27907 }; 27908} 27909 27910function publishFacade(global) { 27911 const ng = global.ng || (global.ng = {}); 27912 ng.ɵcompilerFacade = new CompilerFacadeImpl(); 27913} 27914/** 27915 * @license 27916 * Copyright Google LLC All Rights Reserved. 27917 * 27918 * Use of this source code is governed by an MIT-style license that can be 27919 * found in the LICENSE file at https://angular.io/license 27920 */ 27921 27922 27923const VERSION = new Version('14.2.12'); 27924/** 27925 * @license 27926 * Copyright Google LLC All Rights Reserved. 27927 * 27928 * Use of this source code is governed by an MIT-style license that can be 27929 * found in the LICENSE file at https://angular.io/license 27930 */ 27931 27932class CompilerConfig { 27933 constructor({ 27934 defaultEncapsulation = ViewEncapsulation.Emulated, 27935 useJit = true, 27936 jitDevMode = false, 27937 missingTranslation = null,
27938 preserveWhitespaces, 27939 strictInjectionParameters 27940 } = {}) { 27941 this.defaultEncapsulation = defaultEncapsulation; 27942 this.useJit = !!useJit; 27943 this.jitDevMode = !!jitDevMode; 27944 this.missingTranslation = missingTranslation; 27945 this.preserveWhitespaces = preserveWhitespacesDefault(noUndefined(preserveWhitespaces)); 27946 this.strictInjectionParameters = strictInjectionParameters === true; 27947 } 27948 27949} 27950 27951function preserveWhitespacesDefault(preserveWhitespacesOption, defaultSetting = false) { 27952 return preserveWhitespacesOption === null ? defaultSetting : preserveWhitespacesOption; 27953} 27954/** 27955 * @license 27956 * Copyright Google LLC All Rights Reserved. 27957 * 27958 * Use of this source code is governed by an MIT-style license that can be 27959 * found in the LICENSE file at https://angular.io/license 27960 */ 27961 27962 27963const _I18N_ATTR = 'i18n'; 27964const _I18N_ATTR_PREFIX = 'i18n-'; 27965const _I18N_COMMENT_PREFIX_REGEXP = /^i18n:?/; 27966const MEANING_SEPARATOR = '|'; 27967const ID_SEPARATOR = '@@'; 27968let i18nCommentsWarned = false; 27969/** 27970 * Extract translatable messages from an html AST 27971 */ 27972 27973function extractMessages(nodes, interpolationConfig, implicitTags, implicitAttrs) { 27974 const visitor = new _Visitor(implicitTags, implicitAttrs); 27975 return visitor.extract(nodes, interpolationConfig); 27976} 27977 27978function mergeTranslations(nodes, translations, interpolationConfig, implicitTags, implicitAttrs) { 27979 const visitor = new _Visitor(implicitTags, implicitAttrs); 27980 return visitor.merge(nodes, translations, interpolationConfig); 27981} 27982 27983class ExtractionResult { 27984 constructor(messages, errors) { 27985 this.messages = messages; 27986 this.errors = errors; 27987 } 27988 27989} 27990 27991var _VisitorMode; 27992 27993(function (_VisitorMode) { 27994 _VisitorMode[_VisitorMode["Extract"] = 0] = "Extract"; 27995 _VisitorMode[_VisitorMode["Merge"] = 1] = "Merge"; 27996})(_VisitorMode || (_VisitorMode = {})); 27997/** 27998 * This Visitor is used: 27999 * 1. to extract all the translatable strings from an html AST (see `extract()`), 28000 * 2. to replace the translatable strings with the actual translations (see `merge()`) 28001 * 28002 * @internal 28003 */ 28004 28005 28006class _Visitor { 28007 constructor(_implicitTags, _implicitAttrs) { 28008 this._implicitTags = _implicitTags; 28009 this._implicitAttrs = _implicitAttrs; 28010 } 28011 /** 28012 * Extracts the messages from the tree 28013 */ 28014 28015 28016 extract(nodes, interpolationConfig) { 28017 this._init(_VisitorMode.Extract, interpolationConfig); 28018 28019 nodes.forEach(node => node.visit(this, null)); 28020 28021 if (this._inI18nBlock) { 28022 this._reportError(nodes[nodes.length - 1], 'Unclosed block'); 28023 } 28024 28025 return new ExtractionResult(this._messages, this._errors); 28026 } 28027 /** 28028 * Returns a tree where all translatable nodes are translated 28029 */ 28030 28031 28032 merge(nodes, translations, interpolationConfig) { 28033 this._init(_VisitorMode.Merge, interpolationConfig); 28034 28035 this._translations = translations; // Construct a single fake root element 28036 28037 const wrapper = new Element('wrapper', [], nodes, undefined, undefined, undefined); 28038 const translatedNode = wrapper.visit(this, null); 28039 28040 if (this._inI18nBlock) { 28041 this._reportError(nodes[nodes.length - 1], 'Unclosed block'); 28042 } 28043 28044 return new ParseTreeResult(translatedNode.children, this._errors); 28045 } 28046 28047 visitExpansionCase(icuCase, context) { 28048 // Parse cases for translatable html attributes 28049 const expression = visitAll(this, icuCase.expression, context); 28050 28051 if (this._mode === _VisitorMode.Merge) { 28052 return new ExpansionCase(icuCase.value, expression, icuCase.sourceSpan, icuCase.valueSourceSpan, icuCase.expSourceSpan); 28053 } 28054 } 28055 28056 visitExpansion(icu, context) { 28057 this._mayBeAddBlockChildren(icu); 28058 28059 const wasInIcu = this._inIcu; 28060 28061 if (!this._inIcu) { 28062 // nested ICU messages should not be extracted but top-level translated as a whole 28063 if (this._isInTranslatableSection) { 28064 this._addMessage([icu]); 28065 } 28066 28067 this._inIcu = true; 28068 } 28069 28070 const cases = visitAll(this, icu.cases, context); 28071 28072 if (this._mode === _VisitorMode.Merge) { 28073 icu = new Expansion(icu.switchValue, icu.type, cases, icu.sourceSpan, icu.switchValueSourceSpan); 28074 } 28075 28076 this._inIcu = wasInIcu; 28077 return icu; 28078 } 28079 28080 visitComment(comment, context) { 28081 const isOpening = _isOpeningComment(comment); 28082 28083 if (isOpening && this._isInTranslatableSection) { 28084 this._reportError(comment, 'Could not start a block inside a translatable section'); 28085 28086 return; 28087 } 28088 28089 const isClosing = _isClosingComment(comment); 28090 28091 if (isClosing && !this._inI18nBlock) { 28092 this._reportError(comment, 'Trying to close an unopened block'); 28093 28094 return; 28095 } 28096 28097 if (!this._inI18nNode && !this._inIcu) { 28098 if (!this._inI18nBlock) { 28099 if (isOpening) { 28100 // deprecated from v5 you should use <ng-container i18n> instead of i18n comments 28101 if (!i18nCommentsWarned && console && console.warn) { 28102 i18nCommentsWarned = true; 28103 const details = comment.sourceSpan.details ? `, ${comment.sourceSpan.details}` : ''; // TODO(ocombe): use a log service once there is a public one available 28104 28105 console.warn(`I18n comments are deprecated, use an <ng-container> element instead (${comment.sourceSpan.start}${details})`); 28106 } 28107 28108 this._inI18nBlock = true; 28109 this._blockStartDepth = this._depth; 28110 this._blockChildren = []; 28111 this._blockMeaningAndDesc = comment.value.replace(_I18N_COMMENT_PREFIX_REGEXP, '').trim(); 28112 28113 this._openTranslatableSection(comment); 28114 } 28115 } else { 28116 if (isClosing) { 28117 if (this._depth == this._blockStartDepth) { 28118 this._closeTranslatableSection(comment, this._blockChildren); 28119 28120 this._inI18nBlock = false;
28121 28122 const message = this._addMessage(this._blockChildren, this._blockMeaningAndDesc); // merge attributes in sections 28123 28124 28125 const nodes = this._translateMessage(comment, message); 28126 28127 return visitAll(this, nodes); 28128 } else { 28129 this._reportError(comment, 'I18N blocks should not cross element boundaries'); 28130 28131 return; 28132 } 28133 } 28134 } 28135 } 28136 } 28137 28138 visitText(text, context) { 28139 if (this._isInTranslatableSection) { 28140 this._mayBeAddBlockChildren(text); 28141 } 28142 28143 return text; 28144 } 28145 28146 visitElement(el, context) { 28147 this._mayBeAddBlockChildren(el); 28148 28149 this._depth++; 28150 const wasInI18nNode = this._inI18nNode; 28151 const wasInImplicitNode = this._inImplicitNode; 28152 let childNodes = []; 28153 let translatedChildNodes = undefined; // Extract: 28154 // - top level nodes with the (implicit) "i18n" attribute if not already in a section 28155 // - ICU messages 28156 28157 const i18nAttr = _getI18nAttr(el); 28158 28159 const i18nMeta = i18nAttr ? i18nAttr.value : ''; 28160 const isImplicit = this._implicitTags.some(tag => el.name === tag) && !this._inIcu && !this._isInTranslatableSection; 28161 const isTopLevelImplicit = !wasInImplicitNode && isImplicit; 28162 this._inImplicitNode = wasInImplicitNode || isImplicit; 28163 28164 if (!this._isInTranslatableSection && !this._inIcu) { 28165 if (i18nAttr || isTopLevelImplicit) { 28166 this._inI18nNode = true; 28167 28168 const message = this._addMessage(el.children, i18nMeta); 28169 28170 translatedChildNodes = this._translateMessage(el, message); 28171 } 28172 28173 if (this._mode == _VisitorMode.Extract) { 28174 const isTranslatable = i18nAttr || isTopLevelImplicit; 28175 if (isTranslatable) this._openTranslatableSection(el); 28176 visitAll(this, el.children); 28177 if (isTranslatable) this._closeTranslatableSection(el, el.children); 28178 } 28179 } else { 28180 if (i18nAttr || isTopLevelImplicit) { 28181 this._reportError(el, 'Could not mark an element as translatable inside a translatable section'); 28182 } 28183 28184 if (this._mode == _VisitorMode.Extract) { 28185 // Descend into child nodes for extraction 28186 visitAll(this, el.children); 28187 } 28188 } 28189 28190 if (this._mode === _VisitorMode.Merge) { 28191 const visitNodes = translatedChildNodes || el.children; 28192 visitNodes.forEach(child => { 28193 const visited = child.visit(this, context); 28194 28195 if (visited && !this._isInTranslatableSection) { 28196 // Do not add the children from translatable sections (= i18n blocks here) 28197 // They will be added later in this loop when the block closes (i.e. on `<!-- /i18n -->`) 28198 childNodes = childNodes.concat(visited); 28199 } 28200 }); 28201 } 28202 28203 this._visitAttributesOf(el); 28204 28205 this._depth--; 28206 this._inI18nNode = wasInI18nNode; 28207 this._inImplicitNode = wasInImplicitNode; 28208 28209 if (this._mode === _VisitorMode.Merge) { 28210 const translatedAttrs = this._translateAttributes(el); 28211 28212 return new Element(el.name, translatedAttrs, childNodes, el.sourceSpan, el.startSourceSpan, el.endSourceSpan); 28213 } 28214 28215 return null; 28216 } 28217 28218 visitAttribute(attribute, context) { 28219 throw new Error('unreachable code'); 28220 } 28221 28222 _init(mode, interpolationConfig) { 28223 this._mode = mode; 28224 this._inI18nBlock = false; 28225 this._inI18nNode = false; 28226 this._depth = 0; 28227 this._inIcu = false; 28228 this._msgCountAtSectionStart = undefined; 28229 this._errors = []; 28230 this._messages = []; 28231 this._inImplicitNode = false; 28232 this._createI18nMessage = createI18nMessageFactory(interpolationConfig); 28233 } // looks for translatable attributes 28234 28235 28236 _visitAttributesOf(el) { 28237 const explicitAttrNameToValue = {}; 28238 const implicitAttrNames = this._implicitAttrs[el.name] || []; 28239 el.attrs.filter(attr => attr.name.startsWith(_I18N_ATTR_PREFIX)).forEach(attr => explicitAttrNameToValue[attr.name.slice(_I18N_ATTR_PREFIX.length)] = attr.value); 28240 el.attrs.forEach(attr => { 28241 if (attr.name in explicitAttrNameToValue) { 28242 this._addMessage([attr], explicitAttrNameToValue[attr.name]); 28243 } else if (implicitAttrNames.some(name => attr.name === name)) { 28244 this._addMessage([attr]); 28245 } 28246 }); 28247 } // add a translatable message 28248 28249 28250 _addMessage(ast, msgMeta) { 28251 if (ast.length == 0 || ast.length == 1 && ast[0] instanceof Attribute && !ast[0].value) {
28252 // Do not create empty messages 28253 return null; 28254 } 28255 28256 const { 28257 meaning, 28258 description, 28259 id 28260 } = _parseMessageMeta(msgMeta); 28261 28262 const message = this._createI18nMessage(ast, meaning, description, id); 28263 28264 this._messages.push(message); 28265 28266 return message; 28267 } // Translates the given message given the `TranslationBundle` 28268 // This is used for translating elements / blocks - see `_translateAttributes` for attributes 28269 // no-op when called in extraction mode (returns []) 28270 28271 28272 _translateMessage(el, message) { 28273 if (message && this._mode === _VisitorMode.Merge) { 28274 const nodes = this._translations.get(message); 28275 28276 if (nodes) { 28277 return nodes; 28278 } 28279 28280 this._reportError(el, `Translation unavailable for message id="${this._translations.digest(message)}"`); 28281 } 28282 28283 return []; 28284 } // translate the attributes of an element and remove i18n specific attributes 28285 28286 28287 _translateAttributes(el) { 28288 const attributes = el.attrs; 28289 const i18nParsedMessageMeta = {}; 28290 attributes.forEach(attr => { 28291 if (attr.name.startsWith(_I18N_ATTR_PREFIX)) { 28292 i18nParsedMessageMeta[attr.name.slice(_I18N_ATTR_PREFIX.length)] = _parseMessageMeta(attr.value); 28293 } 28294 }); 28295 const translatedAttributes = []; 28296 attributes.forEach(attr => { 28297 if (attr.name === _I18N_ATTR || attr.name.startsWith(_I18N_ATTR_PREFIX)) { 28298 // strip i18n specific attributes 28299 return; 28300 } 28301 28302 if (attr.value && attr.value != '' && i18nParsedMessageMeta.hasOwnProperty(attr.name)) { 28303 const { 28304 meaning, 28305 description, 28306 id 28307 } = i18nParsedMessageMeta[attr.name]; 28308 28309 const message = this._createI18nMessage([attr], meaning, description, id); 28310 28311 const nodes = this._translations.get(message); 28312 28313 if (nodes) { 28314 if (nodes.length == 0) { 28315 translatedAttributes.push(new Attribute(attr.name, '', attr.sourceSpan, undefined 28316 /* keySpan */ 28317 , undefined 28318 /* valueSpan */ 28319 , undefined 28320 /* valueTokens */ 28321 , undefined 28322 /* i18n */ 28323 )); 28324 } else if (nodes[0] instanceof Text) { 28325 const value = nodes[0].value; 28326 translatedAttributes.push(new Attribute(attr.name, value, attr.sourceSpan, undefined 28327 /* keySpan */ 28328 , undefined 28329 /* valueSpan */ 28330 , undefined 28331 /* valueTokens */ 28332 , undefined 28333 /* i18n */ 28334 )); 28335 } else { 28336 this._reportError(el, `Unexpected translation for attribute "${attr.name}" (id="${id || this._translations.digest(message)}")`); 28337 } 28338 } else { 28339 this._reportError(el, `Translation unavailable for attribute "${attr.name}" (id="${id || this._translations.digest(message)}")`); 28340 } 28341 } else { 28342 translatedAttributes.push(attr); 28343 } 28344 }); 28345 return translatedAttributes; 28346 } 28347 /** 28348 * Add the node as a child of the block when: 28349 * - we are in a block, 28350 * - we are not inside a ICU message (those are handled separately), 28351 * - the node is a "direct child" of the block 28352 */ 28353 28354 28355 _mayBeAddBlockChildren(node) { 28356 if (this._inI18nBlock && !this._inIcu && this._depth == this._blockStartDepth) { 28357 this._blockChildren.push(node); 28358 } 28359 } 28360 /** 28361 * Marks the start of a section, see `_closeTranslatableSection` 28362 */ 28363 28364 28365 _openTranslatableSection(node) { 28366 if (this._isInTranslatableSection) { 28367 this._reportError(node, 'Unexpected section start'); 28368 } else { 28369 this._msgCountAtSectionStart = this._messages.length; 28370 } 28371 } 28372 /** 28373 * A translatable section could be: 28374 * - the content of translatable element, 28375 * - nodes between `<!-- i18n -->` and `<!-- /i18n -->` comments 28376 */ 28377 28378 28379 get _isInTranslatableSection() { 28380 return this._msgCountAtSectionStart !== void 0; 28381 } 28382 /** 28383 * Terminates a section. 28384 * 28385 * If a section has only one significant children (comments not significant) then we should not 28386 * keep the message from this children: 28387 * 28388 * `<p i18n="meaning|description">{ICU message}</p>` would produce two messages: 28389 * - one for the <p> content with meaning and description, 28390 * - another one for the ICU message. 28391 * 28392 * In this case the last message is discarded as it contains less information (the AST is 28393 * otherwise identical). 28394 * 28395 * Note that we should still keep messages extracted from attributes inside the section (ie in the 28396 * ICU message here) 28397 */ 28398 28399 28400 _closeTranslatableSection(node, directChildren) { 28401 if (!this._isInTranslatableSection) { 28402 this._reportError(node, 'Unexpected section end'); 28403 28404 return; 28405 } 28406 28407 const startIndex = this._msgCountAtSectionStart; 28408 const significantChildren = directChildren.reduce((count, node) => count + (node instanceof Comment ? 0 : 1), 0); 28409 28410 if (significantChildren == 1) { 28411 for (let i = this._messages.length - 1; i >= startIndex; i--) { 28412 const ast = this._messages[i].nodes; 28413 28414 if (!(ast.length == 1 && ast[0] instanceof Text$2)) { 28415 this._messages.splice(i, 1); 28416 28417 break; 28418 } 28419 } 28420 } 28421 28422 this._msgCountAtSectionStart = undefined; 28423 } 28424 28425 _reportError(node, msg) { 28426 this._errors.push(new I18nError(node.sourceSpan, msg)); 28427 } 28428 28429} 28430 28431function _isOpeningComment(n) { 28432 return !!(n instanceof Comment && n.value && n.value.startsWith('i18n')); 28433} 28434 28435function _isClosingComment(n) { 28436 return !!(n instanceof Comment && n.value && n.value === '/i18n'); 28437} 28438 28439function _getI18nAttr(p) { 28440 return p.attrs.find(attr => attr.name === _I18N_ATTR) || null; 28441} 28442 28443function _parseMessageMeta(i18n) { 28444 if (!i18n) return { 28445 meaning: '', 28446 description: '', 28447 id: '' 28448 }; 28449 const idIndex = i18n.indexOf(ID_SEPARATOR); 28450 const descIndex = i18n.indexOf(MEANING_SEPARATOR); 28451 const [meaningAndDesc, id] = idIndex > -1 ? [i18n.slice(0, idIndex), i18n.slice(idIndex + 2)] : [i18n, '']; 28452 const [meaning, description] = descIndex > -1 ? [meaningAndDesc.slice(0, descIndex), meaningAndDesc.slice(descIndex + 1)] : ['', meaningAndDesc]; 28453 return { 28454 meaning, 28455 description, 28456 id: id.trim() 28457 }; 28458} 28459/** 28460 * @license 28461 * Copyright Google LLC All Rights Reserved. 28462 * 28463 * Use of this source code is governed by an MIT-style license that can be 28464 * found in the LICENSE file at https://angular.io/license 28465 */ 28466 28467 28468class XmlTagDefinition { 28469 constructor() { 28470 this.closedByParent = false;
28471 this.isVoid = false; 28472 this.ignoreFirstLf = false; 28473 this.canSelfClose = true; 28474 this.preventNamespaceInheritance = false; 28475 } 28476 28477 requireExtraParent(currentParent) { 28478 return false; 28479 } 28480 28481 isClosedByChild(name) { 28482 return false; 28483 } 28484 28485 getContentType() { 28486 return TagContentType.PARSABLE_DATA; 28487 } 28488 28489} 28490 28491const _TAG_DEFINITION = new XmlTagDefinition(); 28492 28493function getXmlTagDefinition(tagName) { 28494 return _TAG_DEFINITION; 28495} 28496/** 28497 * @license 28498 * Copyright Google LLC All Rights Reserved. 28499 * 28500 * Use of this source code is governed by an MIT-style license that can be 28501 * found in the LICENSE file at https://angular.io/license 28502 */ 28503 28504 28505class XmlParser extends Parser { 28506 constructor() { 28507 super(getXmlTagDefinition); 28508 } 28509 28510 parse(source, url, options) { 28511 return super.parse(source, url, options); 28512 } 28513 28514} 28515/** 28516 * @license 28517 * Copyright Google LLC All Rights Reserved. 28518 * 28519 * Use of this source code is governed by an MIT-style license that can be 28520 * found in the LICENSE file at https://angular.io/license 28521 */ 28522 28523 28524const _VERSION$1 = '1.2'; 28525const _XMLNS$1 = 'urn:oasis:names:tc:xliff:document:1.2'; // TODO(vicb): make this a param (s/_/-/) 28526 28527const _DEFAULT_SOURCE_LANG$1 = 'en'; 28528const _PLACEHOLDER_TAG$2 = 'x'; 28529const _MARKER_TAG$1 = 'mrk'; 28530const _FILE_TAG = 'file'; 28531const _SOURCE_TAG$1 = 'source'; 28532const _SEGMENT_SOURCE_TAG = 'seg-source'; 28533const _ALT_TRANS_TAG = 'alt-trans'; 28534const _TARGET_TAG$1 = 'target'; 28535const _UNIT_TAG$1 = 'trans-unit'; 28536const _CONTEXT_GROUP_TAG = 'context-group'; 28537const _CONTEXT_TAG = 'context'; // https://docs.oasis-open.org/xliff/v1.2/os/xliff-core.html 28538// https://docs.oasis-open.org/xliff/v1.2/xliff-profile-html/xliff-profile-html-1.2.html 28539 28540class Xliff extends Serializer { 28541 write(messages, locale) { 28542 const visitor = new _WriteVisitor$1(); 28543 const transUnits = []; 28544 messages.forEach(message => { 28545 let contextTags = []; 28546 message.sources.forEach(source => { 28547 let contextGroupTag = new Tag(_CONTEXT_GROUP_TAG, { 28548 purpose: 'location' 28549 }); 28550 contextGroupTag.children.push(new CR(10), new Tag(_CONTEXT_TAG, { 28551 'context-type': 'sourcefile' 28552 }, [new Text$1(source.filePath)]), new CR(10), new Tag(_CONTEXT_TAG, { 28553 'context-type': 'linenumber' 28554 }, [new Text$1(`${source.startLine}`)]), new CR(8)); 28555 contextTags.push(new CR(8), contextGroupTag); 28556 }); 28557 const transUnit = new Tag(_UNIT_TAG$1, { 28558 id: message.id, 28559 datatype: 'html' 28560 }); 28561 transUnit.children.push(new CR(8), new Tag(_SOURCE_TAG$1, {}, visitor.serialize(message.nodes)), ...contextTags); 28562 28563 if (message.description) { 28564 transUnit.children.push(new CR(8), new Tag('note', { 28565 priority: '1', 28566 from: 'description' 28567 }, [new Text$1(message.description)])); 28568 } 28569 28570 if (message.meaning) { 28571 transUnit.children.push(new CR(8), new Tag('note', { 28572 priority: '1', 28573 from: 'meaning' 28574 }, [new Text$1(message.meaning)])); 28575 } 28576 28577 transUnit.children.push(new CR(6)); 28578 transUnits.push(new CR(6), transUnit); 28579 }); 28580 const body = new Tag('body', {}, [...transUnits, new CR(4)]); 28581 const file = new Tag('file', { 28582 'source-language': locale || _DEFAULT_SOURCE_LANG$1, 28583 datatype: 'plaintext', 28584 original: 'ng2.template' 28585 }, [new CR(4), body, new CR(2)]); 28586 const xliff = new Tag('xliff', { 28587 version: _VERSION$1, 28588 xmlns: _XMLNS$1 28589 }, [new CR(2), file, new CR()]); 28590 return serialize([new Declaration({ 28591 version: '1.0', 28592 encoding: 'UTF-8' 28593 }), new CR(), xliff, new CR()]); 28594 } 28595 28596 load(content, url) { 28597 // xliff to xml nodes 28598 const xliffParser = new XliffParser(); 28599 const { 28600 locale, 28601 msgIdToHtml, 28602 errors 28603 } = xliffParser.parse(content, url); // xml nodes to i18n nodes 28604 28605 const i18nNodesByMsgId = {}; 28606 const converter = new XmlToI18n$2();
28607 Object.keys(msgIdToHtml).forEach(msgId => { 28608 const { 28609 i18nNodes, 28610 errors: e 28611 } = converter.convert(msgIdToHtml[msgId], url); 28612 errors.push(...e); 28613 i18nNodesByMsgId[msgId] = i18nNodes; 28614 }); 28615 28616 if (errors.length) { 28617 throw new Error(`xliff parse errors:\n${errors.join('\n')}`); 28618 } 28619 28620 return { 28621 locale: locale, 28622 i18nNodesByMsgId 28623 }; 28624 } 28625 28626 digest(message) { 28627 return digest$1(message); 28628 } 28629 28630} 28631 28632class _WriteVisitor$1 { 28633 visitText(text, context) { 28634 return [new Text$1(text.value)]; 28635 } 28636 28637 visitContainer(container, context) { 28638 const nodes = []; 28639 container.children.forEach(node => nodes.push(...node.visit(this))); 28640 return nodes; 28641 } 28642 28643 visitIcu(icu, context) { 28644 const nodes = [new Text$1(`{${icu.expressionPlaceholder}, ${icu.type}, `)]; 28645 Object.keys(icu.cases).forEach(c => { 28646 nodes.push(new Text$1(`${c} {`), ...icu.cases[c].visit(this), new Text$1(`} `)); 28647 }); 28648 nodes.push(new Text$1(`}`)); 28649 return nodes; 28650 } 28651 28652 visitTagPlaceholder(ph, context) { 28653 const ctype = getCtypeForTag(ph.tag); 28654 28655 if (ph.isVoid) { 28656 // void tags have no children nor closing tags 28657 return [new Tag(_PLACEHOLDER_TAG$2, { 28658 id: ph.startName, 28659 ctype, 28660 'equiv-text': `<${ph.tag}/>` 28661 })]; 28662 } 28663 28664 const startTagPh = new Tag(_PLACEHOLDER_TAG$2, { 28665 id: ph.startName, 28666 ctype, 28667 'equiv-text': `<${ph.tag}>` 28668 }); 28669 const closeTagPh = new Tag(_PLACEHOLDER_TAG$2, { 28670 id: ph.closeName, 28671 ctype, 28672 'equiv-text': `</${ph.tag}>` 28673 }); 28674 return [startTagPh, ...this.serialize(ph.children), closeTagPh]; 28675 } 28676 28677 visitPlaceholder(ph, context) { 28678 return [new Tag(_PLACEHOLDER_TAG$2, { 28679 id: ph.name, 28680 'equiv-text': `{{${ph.value}}}` 28681 })]; 28682 } 28683 28684 visitIcuPlaceholder(ph, context) { 28685 const equivText = `{${ph.value.expression}, ${ph.value.type}, ${Object.keys(ph.value.cases).map(value => value + ' {...}').join(' ')}}`; 28686 return [new Tag(_PLACEHOLDER_TAG$2, { 28687 id: ph.name, 28688 'equiv-text': equivText 28689 })]; 28690 } 28691 28692 serialize(nodes) { 28693 return [].concat(...nodes.map(node => node.visit(this))); 28694 } 28695 28696} // TODO(vicb): add error management (structure) 28697// Extract messages as xml nodes from the xliff file 28698 28699 28700class XliffParser { 28701 constructor() { 28702 this._locale = null; 28703 } 28704 28705 parse(xliff, url) { 28706 this._unitMlString = null; 28707 this._msgIdToHtml = {}; 28708 const xml = new XmlParser().parse(xliff, url); 28709 this._errors = xml.errors; 28710 visitAll(this, xml.rootNodes, null); 28711 return { 28712 msgIdToHtml: this._msgIdToHtml, 28713 errors: this._errors, 28714 locale: this._locale 28715 }; 28716 } 28717 28718 visitElement(element, context) { 28719 switch (element.name) { 28720 case _UNIT_TAG$1: 28721 this._unitMlString = null; 28722 const idAttr = element.attrs.find(attr => attr.name === 'id'); 28723 28724 if (!idAttr) { 28725 this._addError(element, `<${_UNIT_TAG$1}> misses the "id" attribute`); 28726 } else { 28727 const id = idAttr.value; 28728 28729 if (this._msgIdToHtml.hasOwnProperty(id)) { 28730 this._addError(element, `Duplicated translations for msg ${id}`); 28731 } else { 28732 visitAll(this, element.children, null); 28733 28734 if (typeof this._unitMlString === 'string') { 28735 this._msgIdToHtml[id] = this._unitMlString; 28736 } else { 28737 this._addError(element, `Message ${id} misses a translation`); 28738 } 28739 } 28740 } 28741 28742 break; 28743 // ignore those tags 28744 28745 case _SOURCE_TAG$1: 28746 case _SEGMENT_SOURCE_TAG: 28747 case _ALT_TRANS_TAG: 28748 break; 28749 28750 case _TARGET_TAG$1: 28751 const innerTextStart = element.startSourceSpan.end.offset; 28752 const innerTextEnd = element.endSourceSpan.start.offset; 28753 const content = element.startSourceSpan.start.file.content; 28754 const innerText = content.slice(innerTextStart, innerTextEnd); 28755 this._unitMlString = innerText; 28756 break; 28757 28758 case _FILE_TAG: 28759 const localeAttr = element.attrs.find(attr => attr.name === 'target-language'); 28760 28761 if (localeAttr) { 28762 this._locale = localeAttr.value; 28763 } 28764 28765 visitAll(this, element.children, null); 28766 break; 28767 28768 default: 28769 // TODO(vicb): assert file structure, xliff version 28770 // For now only recurse on unhandled nodes 28771 visitAll(this, element.children, null); 28772 } 28773 } 28774 28775 visitAttribute(attribute, context) {} 28776 28777 visitText(text, context) {} 28778 28779 visitComment(comment, context) {} 28780 28781 visitExpansion(expansion, context) {} 28782 28783 visitExpansionCase(expansionCase, context) {} 28784 28785 _addError(node, message) { 28786 this._errors.push(new I18nError(node.sourceSpan, message)); 28787 } 28788 28789} // Convert ml nodes (xliff syntax) to i18n nodes 28790 28791 28792class XmlToI18n$2 { 28793 convert(message, url) { 28794 const xmlIcu = new XmlParser().parse(message, url, { 28795 tokenizeExpansionForms: true 28796 }); 28797 this._errors = xmlIcu.errors; 28798 const i18nNodes = this._errors.length > 0 || xmlIcu.rootNodes.length == 0 ? [] : [].concat(...visitAll(this, xmlIcu.rootNodes)); 28799 return { 28800 i18nNodes: i18nNodes, 28801 errors: this._errors 28802 }; 28803 } 28804 28805 visitText(text, context) { 28806 return new Text$2(text.value, text.sourceSpan); 28807 } 28808 28809 visitElement(el, context) { 28810 if (el.name === _PLACEHOLDER_TAG$2) { 28811 const nameAttr = el.attrs.find(attr => attr.name === 'id'); 28812 28813 if (nameAttr) { 28814 return new Placeholder('', nameAttr.value, el.sourceSpan); 28815 } 28816 28817 this._addError(el, `<${_PLACEHOLDER_TAG$2}> misses the "id" attribute`); 28818 28819 return null; 28820 } 28821 28822 if (el.name === _MARKER_TAG$1) { 28823 return [].concat(...visitAll(this, el.children)); 28824 } 28825 28826 this._addError(el, `Unexpected tag`); 28827 28828 return null; 28829 } 28830 28831 visitExpansion(icu, context) { 28832 const caseMap = {};
28833 visitAll(this, icu.cases).forEach(c => { 28834 caseMap[c.value] = new Container(c.nodes, icu.sourceSpan); 28835 }); 28836 return new Icu(icu.switchValue, icu.type, caseMap, icu.sourceSpan); 28837 } 28838 28839 visitExpansionCase(icuCase, context) { 28840 return { 28841 value: icuCase.value, 28842 nodes: visitAll(this, icuCase.expression) 28843 }; 28844 } 28845 28846 visitComment(comment, context) {} 28847 28848 visitAttribute(attribute, context) {} 28849 28850 _addError(node, message) { 28851 this._errors.push(new I18nError(node.sourceSpan, message)); 28852 } 28853 28854} 28855 28856function getCtypeForTag(tag) { 28857 switch (tag.toLowerCase()) { 28858 case 'br': 28859 return 'lb'; 28860 28861 case 'img': 28862 return 'image'; 28863 28864 default: 28865 return `x-${tag}`; 28866 } 28867} 28868/** 28869 * @license 28870 * Copyright Google LLC All Rights Reserved. 28871 * 28872 * Use of this source code is governed by an MIT-style license that can be 28873 * found in the LICENSE file at https://angular.io/license 28874 */ 28875 28876 28877const _VERSION = '2.0'; 28878const _XMLNS = 'urn:oasis:names:tc:xliff:document:2.0'; // TODO(vicb): make this a param (s/_/-/) 28879 28880const _DEFAULT_SOURCE_LANG = 'en'; 28881const _PLACEHOLDER_TAG$1 = 'ph'; 28882const _PLACEHOLDER_SPANNING_TAG = 'pc'; 28883const _MARKER_TAG = 'mrk'; 28884const _XLIFF_TAG = 'xliff'; 28885const _SOURCE_TAG = 'source'; 28886const _TARGET_TAG = 'target'; 28887const _UNIT_TAG = 'unit'; // https://docs.oasis-open.org/xliff/xliff-core/v2.0/os/xliff-core-v2.0-os.html 28888 28889class Xliff2 extends Serializer { 28890 write(messages, locale) { 28891 const visitor = new _WriteVisitor(); 28892 const units = []; 28893 messages.forEach(message => { 28894 const unit = new Tag(_UNIT_TAG, { 28895 id: message.id 28896 }); 28897 const notes = new Tag('notes'); 28898 28899 if (message.description || message.meaning) { 28900 if (message.description) { 28901 notes.children.push(new CR(8), new Tag('note', { 28902 category: 'description' 28903 }, [new Text$1(message.description)])); 28904 } 28905 28906 if (message.meaning) { 28907 notes.children.push(new CR(8), new Tag('note', { 28908 category: 'meaning' 28909 }, [new Text$1(message.meaning)])); 28910 } 28911 } 28912 28913 message.sources.forEach(source => { 28914 notes.children.push(new CR(8), new Tag('note', { 28915 category: 'location' 28916 }, [new Text$1(`${source.filePath}:${source.startLine}${source.endLine !== source.startLine ? ',' + source.endLine : ''}`)])); 28917 }); 28918 notes.children.push(new CR(6)); 28919 unit.children.push(new CR(6), notes); 28920 const segment = new Tag('segment'); 28921 segment.children.push(new CR(8), new Tag(_SOURCE_TAG, {}, visitor.serialize(message.nodes)), new CR(6)); 28922 unit.children.push(new CR(6), segment, new CR(4)); 28923 units.push(new CR(4), unit); 28924 }); 28925 const file = new Tag('file', { 28926 'original': 'ng.template', 28927 id: 'ngi18n' 28928 }, [...units, new CR(2)]); 28929 const xliff = new Tag(_XLIFF_TAG, { 28930 version: _VERSION, 28931 xmlns: _XMLNS, 28932 srcLang: locale || _DEFAULT_SOURCE_LANG 28933 }, [new CR(2), file, new CR()]); 28934 return serialize([new Declaration({ 28935 version: '1.0', 28936 encoding: 'UTF-8' 28937 }), new CR(), xliff, new CR()]); 28938 } 28939 28940 load(content, url) { 28941 // xliff to xml nodes 28942 const xliff2Parser = new Xliff2Parser(); 28943 const { 28944 locale, 28945 msgIdToHtml, 28946 errors 28947 } = xliff2Parser.parse(content, url); // xml nodes to i18n nodes 28948 28949 const i18nNodesByMsgId = {}; 28950 const converter = new XmlToI18n$1(); 28951 Object.keys(msgIdToHtml).forEach(msgId => { 28952 const { 28953 i18nNodes, 28954 errors: e 28955 } = converter.convert(msgIdToHtml[msgId], url); 28956 errors.push(...e); 28957 i18nNodesByMsgId[msgId] = i18nNodes; 28958 }); 28959 28960 if (errors.length) { 28961 throw new Error(`xliff2 parse errors:\n${errors.join('\n')}`); 28962 } 28963 28964 return { 28965 locale: locale, 28966 i18nNodesByMsgId 28967 }; 28968 } 28969 28970 digest(message) { 28971 return decimalDigest(message); 28972 } 28973 28974} 28975 28976class _WriteVisitor { 28977 visitText(text, context) { 28978 return [new Text$1(text.value)]; 28979 } 28980 28981 visitContainer(container, context) { 28982 const nodes = []; 28983 container.children.forEach(node => nodes.push(...node.visit(this))); 28984 return nodes; 28985 } 28986 28987 visitIcu(icu, context) { 28988 const nodes = [new Text$1(`{${icu.expressionPlaceholder}, ${icu.type}, `)];
28989 Object.keys(icu.cases).forEach(c => { 28990 nodes.push(new Text$1(`${c} {`), ...icu.cases[c].visit(this), new Text$1(`} `)); 28991 }); 28992 nodes.push(new Text$1(`}`)); 28993 return nodes; 28994 } 28995 28996 visitTagPlaceholder(ph, context) { 28997 const type = getTypeForTag(ph.tag); 28998 28999 if (ph.isVoid) { 29000 const tagPh = new Tag(_PLACEHOLDER_TAG$1, { 29001 id: (this._nextPlaceholderId++).toString(), 29002 equiv: ph.startName, 29003 type: type, 29004 disp: `<${ph.tag}/>` 29005 }); 29006 return [tagPh]; 29007 } 29008 29009 const tagPc = new Tag(_PLACEHOLDER_SPANNING_TAG, { 29010 id: (this._nextPlaceholderId++).toString(), 29011 equivStart: ph.startName, 29012 equivEnd: ph.closeName, 29013 type: type, 29014 dispStart: `<${ph.tag}>`, 29015 dispEnd: `</${ph.tag}>` 29016 }); 29017 const nodes = [].concat(...ph.children.map(node => node.visit(this))); 29018 29019 if (nodes.length) { 29020 nodes.forEach(node => tagPc.children.push(node)); 29021 } else { 29022 tagPc.children.push(new Text$1('')); 29023 } 29024 29025 return [tagPc]; 29026 } 29027 29028 visitPlaceholder(ph, context) { 29029 const idStr = (this._nextPlaceholderId++).toString(); 29030 return [new Tag(_PLACEHOLDER_TAG$1, { 29031 id: idStr, 29032 equiv: ph.name, 29033 disp: `{{${ph.value}}}` 29034 })]; 29035 } 29036 29037 visitIcuPlaceholder(ph, context) { 29038 const cases = Object.keys(ph.value.cases).map(value => value + ' {...}').join(' '); 29039 const idStr = (this._nextPlaceholderId++).toString(); 29040 return [new Tag(_PLACEHOLDER_TAG$1, { 29041 id: idStr, 29042 equiv: ph.name, 29043 disp: `{${ph.value.expression}, ${ph.value.type}, ${cases}}` 29044 })]; 29045 } 29046 29047 serialize(nodes) { 29048 this._nextPlaceholderId = 0; 29049 return [].concat(...nodes.map(node => node.visit(this))); 29050 } 29051 29052} // Extract messages as xml nodes from the xliff file 29053 29054 29055class Xliff2Parser { 29056 constructor() { 29057 this._locale = null; 29058 } 29059 29060 parse(xliff, url) { 29061 this._unitMlString = null; 29062 this._msgIdToHtml = {}; 29063 const xml = new XmlParser().parse(xliff, url); 29064 this._errors = xml.errors; 29065 visitAll(this, xml.rootNodes, null); 29066 return { 29067 msgIdToHtml: this._msgIdToHtml, 29068 errors: this._errors, 29069 locale: this._locale 29070 }; 29071 } 29072 29073 visitElement(element, context) { 29074 switch (element.name) { 29075 case _UNIT_TAG: 29076 this._unitMlString = null; 29077 const idAttr = element.attrs.find(attr => attr.name === 'id'); 29078 29079 if (!idAttr) { 29080 this._addError(element, `<${_UNIT_TAG}> misses the "id" attribute`); 29081 } else { 29082 const id = idAttr.value; 29083 29084 if (this._msgIdToHtml.hasOwnProperty(id)) { 29085 this._addError(element, `Duplicated translations for msg ${id}`); 29086 } else { 29087 visitAll(this, element.children, null); 29088 29089 if (typeof this._unitMlString === 'string') { 29090 this._msgIdToHtml[id] = this._unitMlString; 29091 } else { 29092 this._addError(element, `Message ${id} misses a translation`); 29093 } 29094 } 29095 } 29096 29097 break; 29098 29099 case _SOURCE_TAG: 29100 // ignore source message 29101 break; 29102 29103 case _TARGET_TAG: 29104 const innerTextStart = element.startSourceSpan.end.offset; 29105 const innerTextEnd = element.endSourceSpan.start.offset; 29106 const content = element.startSourceSpan.start.file.content; 29107 const innerText = content.slice(innerTextStart, innerTextEnd); 29108 this._unitMlString = innerText; 29109 break; 29110 29111 case _XLIFF_TAG: 29112 const localeAttr = element.attrs.find(attr => attr.name === 'trgLang'); 29113 29114 if (localeAttr) { 29115 this._locale = localeAttr.value; 29116 } 29117 29118 const versionAttr = element.attrs.find(attr => attr.name === 'version'); 29119 29120 if (versionAttr) { 29121 const version = versionAttr.value; 29122 29123 if (version !== '2.0') { 29124 this._addError(element, `The XLIFF file version ${version} is not compatible with XLIFF 2.0 serializer`); 29125 } else { 29126 visitAll(this, element.children, null); 29127 } 29128 } 29129 29130 break; 29131 29132 default: 29133 visitAll(this, element.children, null); 29134 } 29135 } 29136 29137 visitAttribute(attribute, context) {} 29138 29139 visitText(text, context) {} 29140 29141 visitComment(comment, context) {} 29142 29143 visitExpansion(expansion, context) {} 29144 29145 visitExpansionCase(expansionCase, context) {} 29146 29147 _addError(node, message) { 29148 this._errors.push(new I18nError(node.sourceSpan, message)); 29149 } 29150 29151} // Convert ml nodes (xliff syntax) to i18n nodes 29152 29153 29154class XmlToI18n$1 { 29155 convert(message, url) { 29156 const xmlIcu = new XmlParser().parse(message, url, { 29157 tokenizeExpansionForms: true 29158 }); 29159 this._errors = xmlIcu.errors; 29160 const i18nNodes = this._errors.length > 0 || xmlIcu.rootNodes.length == 0 ? [] : [].concat(...visitAll(this, xmlIcu.rootNodes)); 29161 return { 29162 i18nNodes, 29163 errors: this._errors 29164 }; 29165 } 29166 29167 visitText(text, context) { 29168 return new Text$2(text.value, text.sourceSpan); 29169 } 29170 29171 visitElement(el, context) { 29172 switch (el.name) { 29173 case _PLACEHOLDER_TAG$1: 29174 const nameAttr = el.attrs.find(attr => attr.name === 'equiv'); 29175 29176 if (nameAttr) { 29177 return [new Placeholder('', nameAttr.value, el.sourceSpan)]; 29178 } 29179 29180 this._addError(el, `<${_PLACEHOLDER_TAG$1}> misses the "equiv" attribute`); 29181 29182 break; 29183 29184 case _PLACEHOLDER_SPANNING_TAG: 29185 const startAttr = el.attrs.find(attr => attr.name === 'equivStart'); 29186 const endAttr = el.attrs.find(attr => attr.name === 'equivEnd'); 29187 29188 if (!startAttr) { 29189 this._addError(el, `<${_PLACEHOLDER_TAG$1}> misses the "equivStart" attribute`); 29190 } else if (!endAttr) { 29191 this._addError(el, `<${_PLACEHOLDER_TAG$1}> misses the "equivEnd" attribute`); 29192 } else { 29193 const startId = startAttr.value; 29194 const endId = endAttr.value; 29195 const nodes = []; 29196 return nodes.concat(new Placeholder('', startId, el.sourceSpan), ...el.children.map(node =>
29196 node.visit(this, null)), new Placeholder('', endId, el.sourceSpan)); 29197 } 29198 29199 break; 29200 29201 case _MARKER_TAG: 29202 return [].concat(...visitAll(this, el.children)); 29203 29204 default: 29205 this._addError(el, `Unexpected tag`); 29206 29207 } 29208 29209 return null; 29210 } 29211 29212 visitExpansion(icu, context) { 29213 const caseMap = {}; 29214 visitAll(this, icu.cases).forEach(c => { 29215 caseMap[c.value] = new Container(c.nodes, icu.sourceSpan); 29216 }); 29217 return new Icu(icu.switchValue, icu.type, caseMap, icu.sourceSpan); 29218 } 29219 29220 visitExpansionCase(icuCase, context) { 29221 return { 29222 value: icuCase.value, 29223 nodes: [].concat(...visitAll(this, icuCase.expression)) 29224 }; 29225 } 29226 29227 visitComment(comment, context) {} 29228 29229 visitAttribute(attribute, context) {} 29230 29231 _addError(node, message) { 29232 this._errors.push(new I18nError(node.sourceSpan, message)); 29233 } 29234 29235} 29236 29237function getTypeForTag(tag) { 29238 switch (tag.toLowerCase()) { 29239 case 'br': 29240 case 'b': 29241 case 'i': 29242 case 'u': 29243 return 'fmt'; 29244 29245 case 'img': 29246 return 'image'; 29247 29248 case 'a': 29249 return 'link'; 29250 29251 default: 29252 return 'other'; 29253 } 29254} 29255/** 29256 * @license 29257 * Copyright Google LLC All Rights Reserved. 29258 * 29259 * Use of this source code is governed by an MIT-style license that can be 29260 * found in the LICENSE file at https://angular.io/license 29261 */ 29262 29263 29264const _TRANSLATIONS_TAG = 'translationbundle'; 29265const _TRANSLATION_TAG = 'translation'; 29266const _PLACEHOLDER_TAG = 'ph'; 29267 29268class Xtb extends Serializer { 29269 write(messages, locale) { 29270 throw new Error('Unsupported'); 29271 } 29272 29273 load(content, url) { 29274 // xtb to xml nodes 29275 const xtbParser = new XtbParser(); 29276 const { 29277 locale, 29278 msgIdToHtml, 29279 errors 29280 } = xtbParser.parse(content, url); // xml nodes to i18n nodes 29281 29282 const i18nNodesByMsgId = {}; 29283 const converter = new XmlToI18n(); // Because we should be able to load xtb files that rely on features not supported by angular, 29284 // we need to delay the conversion of html to i18n nodes so that non angular messages are not 29285 // converted 29286 29287 Object.keys(msgIdToHtml).forEach(msgId => { 29288 const valueFn = function () { 29289 const { 29290 i18nNodes, 29291 errors 29292 } = converter.convert(msgIdToHtml[msgId], url); 29293 29294 if (errors.length) { 29295 throw new Error(`xtb parse errors:\n${errors.join('\n')}`); 29296 } 29297 29298 return i18nNodes; 29299 }; 29300 29301 createLazyProperty(i18nNodesByMsgId, msgId, valueFn); 29302 }); 29303 29304 if (errors.length) { 29305 throw new Error(`xtb parse errors:\n${errors.join('\n')}`); 29306 } 29307 29308 return { 29309 locale: locale, 29310 i18nNodesByMsgId 29311 }; 29312 } 29313 29314 digest(message) { 29315 return digest(message); 29316 } 29317 29318 createNameMapper(message) { 29319 return new SimplePlaceholderMapper(message, toPublicName); 29320 } 29321 29322} 29323 29324function createLazyProperty(messages, id, valueFn) { 29325 Object.defineProperty(messages, id, { 29326 configurable: true, 29327 enumerable: true, 29328 get: function () { 29329 const value = valueFn(); 29330 Object.defineProperty(messages, id, { 29331 enumerable: true, 29332 value 29333 }); 29334 return value; 29335 }, 29336 set: _ => { 29337 throw new Error('Could not overwrite an XTB translation'); 29338 } 29339 }); 29340} // Extract messages as xml nodes from the xtb file 29341 29342 29343class XtbParser { 29344 constructor() { 29345 this._locale = null; 29346 } 29347 29348 parse(xtb, url) { 29349 this._bundleDepth = 0; 29350 this._msgIdToHtml = {}; // We can not parse the ICU messages at this point as some messages might not originate 29351 // from Angular that could not be lex'd. 29352 29353 const xml = new XmlParser().parse(xtb, url); 29354 this._errors = xml.errors; 29355 visitAll(this, xml.rootNodes); 29356 return { 29357 msgIdToHtml: this._msgIdToHtml, 29358 errors: this._errors, 29359 locale: this._locale 29360 }; 29361 } 29362 29363 visitElement(element, context) { 29364 switch (element.name) { 29365 case _TRANSLATIONS_TAG: 29366 this._bundleDepth++; 29367 29368 if (this._bundleDepth > 1) { 29369 this._addError(element, `<${_TRANSLATIONS_TAG}> elements can not be nested`); 29370 } 29371 29372 const langAttr = element.attrs.find(attr => attr.name === 'lang'); 29373 29374 if (langAttr) { 29375 this._locale = langAttr.value; 29376 } 29377 29378 visitAll(this, element.children, null); 29379 this._bundleDepth--; 29380 break; 29381 29382 case _TRANSLATION_TAG: 29383 const idAttr = element.attrs.find(attr => attr.name === 'id'); 29384 29385 if (!idAttr) { 29386 this._addError(element, `<${_TRANSLATION_TAG}> misses the "id" attribute`); 29387 } else { 29388 const id = idAttr.value; 29389 29390 if (this._msgIdToHtml.hasOwnProperty(id)) { 29391 this._addError(element, `Duplicated translations for msg ${id}`); 29392 } else { 29393 const innerTextStart = element.startSourceSpan.end.offset; 29394 const innerTextEnd = element.endSourceSpan.start.offset; 29395 const content = element.startSourceSpan.start.file.content; 29396 const innerText = content.slice(innerTextStart, innerTextEnd); 29397 this._msgIdToHtml[id] = innerText; 29398 } 29399 } 29400 29401 break; 29402 29403 default: 29404 this._addError(element, 'Unexpected tag'); 29405 29406 } 29407 } 29408 29409 visitAttribute(attribute, context) {} 29410 29411 visitText(text, context) {} 29412 29413 visitComment(comment, context) {} 29414 29415 visitExpansion(expansion, context) {} 29416 29417 visitExpansionCase(expansionCase, context) {} 29418 29419 _addError(node, message) { 29420 this._errors.push(new I18nError(node.sourceSpan, message)); 29421 } 29422 29423} // Convert ml nodes (xtb syntax) to i18n nodes 29424 29425 29426class XmlToI18n { 29427 convert(message, url) { 29428 const xmlIcu = new XmlParser().parse(message, url, { 29429 tokenizeExpansionForms: true 29430 }); 29431 this._errors = xmlIcu.errors; 29432 const i18nNodes = this._errors.length > 0 || xmlIcu.rootNodes.length == 0 ? [] : visitAll(this, xmlIcu.rootNodes); 29433 return { 29434 i18nNodes, 29435 errors: this._errors 29436 }; 29437 } 29438 29439 visitText(text, context) { 29440 return new Text$2(text.value, text.sourceSpan); 29441 } 29442 29443 visitExpansion(icu, context) { 29444 const caseMap = {};
29445 visitAll(this, icu.cases).forEach(c => { 29446 caseMap[c.value] = new Container(c.nodes, icu.sourceSpan); 29447 }); 29448 return new Icu(icu.switchValue, icu.type, caseMap, icu.sourceSpan); 29449 } 29450 29451 visitExpansionCase(icuCase, context) { 29452 return { 29453 value: icuCase.value, 29454 nodes: visitAll(this, icuCase.expression) 29455 }; 29456 } 29457 29458 visitElement(el, context) { 29459 if (el.name === _PLACEHOLDER_TAG) { 29460 const nameAttr = el.attrs.find(attr => attr.name === 'name'); 29461 29462 if (nameAttr) { 29463 return new Placeholder('', nameAttr.value, el.sourceSpan); 29464 } 29465 29466 this._addError(el, `<${_PLACEHOLDER_TAG}> misses the "name" attribute`); 29467 } else { 29468 this._addError(el, `Unexpected tag`); 29469 } 29470 29471 return null; 29472 } 29473 29474 visitComment(comment, context) {} 29475 29476 visitAttribute(attribute, context) {} 29477 29478 _addError(node, message) { 29479 this._errors.push(new I18nError(node.sourceSpan, message)); 29480 } 29481 29482} 29483/** 29484 * @license 29485 * Copyright Google LLC All Rights Reserved. 29486 * 29487 * Use of this source code is governed by an MIT-style license that can be 29488 * found in the LICENSE file at https://angular.io/license 29489 */ 29490 29491/** 29492 * A container for translated messages 29493 */ 29494 29495 29496class TranslationBundle { 29497 constructor(_i18nNodesByMsgId = {}, locale, digest, mapperFactory, missingTranslationStrategy = MissingTranslationStrategy.Warning, console) { 29498 this._i18nNodesByMsgId = _i18nNodesByMsgId; 29499 this.digest = digest; 29500 this.mapperFactory = mapperFactory; 29501 this._i18nToHtml = new I18nToHtmlVisitor(_i18nNodesByMsgId, locale, digest, mapperFactory, missingTranslationStrategy, console); 29502 } // Creates a `TranslationBundle` by parsing the given `content` with the `serializer`. 29503 29504 29505 static load(content, url, serializer, missingTranslationStrategy, console) { 29506 const { 29507 locale, 29508 i18nNodesByMsgId 29509 } = serializer.load(content, url); 29510 29511 const digestFn = m => serializer.digest(m); 29512 29513 const mapperFactory = m => serializer.createNameMapper(m); 29514 29515 return new TranslationBundle(i18nNodesByMsgId, locale, digestFn, mapperFactory, missingTranslationStrategy, console); 29516 } // Returns the translation as HTML nodes from the given source message. 29517 29518 29519 get(srcMsg) { 29520 const html = this._i18nToHtml.convert(srcMsg); 29521 29522 if (html.errors.length) { 29523 throw new Error(html.errors.join('\n')); 29524 } 29525 29526 return html.nodes; 29527 } 29528 29529 has(srcMsg) { 29530 return this.digest(srcMsg) in this._i18nNodesByMsgId; 29531 } 29532 29533} 29534 29535class I18nToHtmlVisitor { 29536 constructor(_i18nNodesByMsgId = {}, _locale, _digest, _mapperFactory, _missingTranslationStrategy, _console) { 29537 this._i18nNodesByMsgId = _i18nNodesByMsgId; 29538 this._locale = _locale; 29539 this._digest = _digest; 29540 this._mapperFactory = _mapperFactory; 29541 this._missingTranslationStrategy = _missingTranslationStrategy; 29542 this._console = _console; 29543 this._contextStack = []; 29544 this._errors = []; 29545 } 29546 29547 convert(srcMsg) { 29548 this._contextStack.length = 0; 29549 this._errors.length = 0; // i18n to text 29550 29551 const text = this._convertToText(srcMsg); // text to html 29552 29553 29554 const url = srcMsg.nodes[0].sourceSpan.start.file.url; 29555 const html = new HtmlParser().parse(text, url, { 29556 tokenizeExpansionForms: true 29557 }); 29558 return { 29559 nodes: html.rootNodes, 29560 errors: [...this._errors, ...html.errors] 29561 }; 29562 } 29563 29564 visitText(text, context) { 29565 // `convert()` uses an `HtmlParser` to return `html.Node`s 29566 // we should then make sure that any special characters are escaped 29567 return escapeXml(text.value); 29568 } 29569 29570 visitContainer(container, context) { 29571 return container.children.map(n => n.visit(this)).join(''); 29572 } 29573 29574 visitIcu(icu, context) { 29575 const cases = Object.keys(icu.cases).map(k => `${k} {${icu.cases[k].visit(this)}}`); // TODO(vicb): Once all format switch to using expression placeholders 29576 // we should throw when the placeholder is not in the source message 29577 29578 const exp = this._srcMsg.placeholders.hasOwnProperty(icu.expression) ? this._srcMsg.placeholders[icu.expression].text : icu.expression; 29579 return `{${exp}, ${icu.type}, ${cases.join(' ')}}`; 29580 } 29581 29582 visitPlaceholder(ph, context) { 29583 const phName = this._mapper(ph.name); 29584 29585 if (this._srcMsg.placeholders.hasOwnProperty(phName)) { 29586 return this._srcMsg.placeholders[phName].text; 29587 } 29588 29589 if (this._srcMsg.placeholderToMessage.hasOwnProperty(phName)) { 29590 return this._convertToText(this._srcMsg.placeholderToMessage[phName]); 29591 } 29592 29593 this._addError(ph, `Unknown placeholder "${ph.name}"`); 29594 29595 return ''; 29596 } // Loaded message contains only placeholders (vs tag and icu placeholders). 29597 // However when a translation can not be found, we need to serialize the source message 29598 // which can contain tag placeholders 29599 29600 29601 visitTagPlaceholder(ph, context) { 29602 const tag = `${ph.tag}`; 29603 const attrs = Object.keys(ph.attrs).map(name => `${name}="${ph.attrs[name]}"`).join(' '); 29604 29605 if (ph.isVoid) { 29606 return `<${tag} ${attrs}/>`; 29607 } 29608 29609 const children = ph.children.map(c => c.visit(this)).join(''); 29610 return `<${tag} ${attrs}>${children}</${tag}>`; 29611 } // Loaded message contains only placeholders (vs tag and icu placeholders). 29612 // However when a translation can not be found, we need to serialize the source message 29613 // which can contain tag placeholders 29614 29615 29616 visitIcuPlaceholder(ph, context) { 29617 // An ICU placeholder references the source message to be serialized 29618 return this._convertToText(this._srcMsg.placeholderToMessage[ph.name]); 29619 } 29620 /**
29621 * Convert a source message to a translated text string: 29622 * - text nodes are replaced with their translation, 29623 * - placeholders are replaced with their content, 29624 * - ICU nodes are converted to ICU expressions. 29625 */ 29626 29627 29628 _convertToText(srcMsg) { 29629 const id = this._digest(srcMsg); 29630 29631 const mapper = this._mapperFactory ? this._mapperFactory(srcMsg) : null; 29632 let nodes; 29633 29634 this._contextStack.push({ 29635 msg: this._srcMsg, 29636 mapper: this._mapper 29637 }); 29638 29639 this._srcMsg = srcMsg; 29640 29641 if (this._i18nNodesByMsgId.hasOwnProperty(id)) { 29642 // When there is a translation use its nodes as the source 29643 // And create a mapper to convert serialized placeholder names to internal names 29644 nodes = this._i18nNodesByMsgId[id]; 29645 29646 this._mapper = name => mapper ? mapper.toInternalName(name) : name; 29647 } else { 29648 // When no translation has been found 29649 // - report an error / a warning / nothing, 29650 // - use the nodes from the original message 29651 // - placeholders are already internal and need no mapper 29652 if (this._missingTranslationStrategy === MissingTranslationStrategy.Error) { 29653 const ctx = this._locale ? ` for locale "${this._locale}"` : ''; 29654 29655 this._addError(srcMsg.nodes[0], `Missing translation for message "${id}"${ctx}`); 29656 } else if (this._console && this._missingTranslationStrategy === MissingTranslationStrategy.Warning) { 29657 const ctx = this._locale ? ` for locale "${this._locale}"` : ''; 29658 29659 this._console.warn(`Missing translation for message "${id}"${ctx}`); 29660 } 29661 29662 nodes = srcMsg.nodes; 29663 29664 this._mapper = name => name; 29665 } 29666 29667 const text = nodes.map(node => node.visit(this)).join(''); 29668 29669 const context = this._contextStack.pop(); 29670 29671 this._srcMsg = context.msg; 29672 this._mapper = context.mapper; 29673 return text; 29674 } 29675 29676 _addError(el, msg) { 29677 this._errors.push(new I18nError(el.sourceSpan, msg)); 29678 } 29679 29680} 29681/** 29682 * @license 29683 * Copyright Google LLC All Rights Reserved. 29684 * 29685 * Use of this source code is governed by an MIT-style license that can be 29686 * found in the LICENSE file at https://angular.io/license 29687 */ 29688 29689 29690class I18NHtmlParser { 29691 constructor(_htmlParser, translations, translationsFormat, missingTranslation = MissingTranslationStrategy.Warning, console) { 29692 this._htmlParser = _htmlParser; 29693 29694 if (translations) { 29695 const serializer = createSerializer(translationsFormat); 29696 this._translationBundle = TranslationBundle.load(translations, 'i18n', serializer, missingTranslation, console); 29697 } else { 29698 this._translationBundle = new TranslationBundle({}, null, digest$1, undefined, missingTranslation, console); 29699 } 29700 } 29701 29702 parse(source, url, options = {}) { 29703 const interpolationConfig = options.interpolationConfig || DEFAULT_INTERPOLATION_CONFIG; 29704 29705 const parseResult = this._htmlParser.parse(source, url, { 29706 interpolationConfig, 29707 ...options 29708 }); 29709 29710 if (parseResult.errors.length) { 29711 return new ParseTreeResult(parseResult.rootNodes, parseResult.errors); 29712 } 29713 29714 return mergeTranslations(parseResult.rootNodes, this._translationBundle, interpolationConfig, [], {}); 29715 } 29716 29717} 29718 29719function createSerializer(format) { 29720 format = (format || 'xlf').toLowerCase(); 29721 29722 switch (format) { 29723 case 'xmb': 29724 return new Xmb(); 29725 29726 case 'xtb': 29727 return new Xtb(); 29728 29729 case 'xliff2': 29730 case 'xlf2': 29731 return new Xliff2(); 29732 29733 case 'xliff': 29734 case 'xlf': 29735 default: 29736 return new Xliff(); 29737 } 29738} 29739/** 29740 * @license 29741 * Copyright Google LLC All Rights Reserved. 29742 * 29743 * Use of this source code is governed by an MIT-style license that can be 29744 * found in the LICENSE file at https://angular.io/license 29745 */ 29746 29747/** 29748 * A container for message extracted from the templates. 29749 */ 29750 29751 29752class MessageBundle { 29753 constructor(_htmlParser, _implicitTags, _implicitAttrs, _locale = null) { 29754 this._htmlParser = _htmlParser; 29755 this._implicitTags = _implicitTags; 29756 this._implicitAttrs = _implicitAttrs; 29757 this._locale = _locale; 29758 this._messages = []; 29759 } 29760 29761 updateFromTemplate(html, url, interpolationConfig) { 29762 const htmlParserResult = this._htmlParser.parse(html, url, { 29763 tokenizeExpansionForms: true, 29764 interpolationConfig 29765 }); 29766 29767 if (htmlParserResult.errors.length) { 29768 return htmlParserResult.errors; 29769 } 29770 29771 const i18nParserResult = extractMessages(htmlParserResult.rootNodes, interpolationConfig, this._implicitTags, this._implicitAttrs); 29772 29773 if (i18nParserResult.errors.length) { 29774 return i18nParserResult.errors; 29775 } 29776 29777 this._messages.push(...i18nParserResult.messages); 29778 29779 return []; 29780 } // Return the message in the internal format 29781 // The public (serialized) format might be different, see the `write` method. 29782 29783 29784 getMessages() { 29785 return this._messages; 29786 } 29787
29788 write(serializer, filterSources) { 29789 const messages = {}; 29790 const mapperVisitor = new MapPlaceholderNames(); // Deduplicate messages based on their ID 29791 29792 this._messages.forEach(message => { 29793 const id = serializer.digest(message); 29794 29795 if (!messages.hasOwnProperty(id)) { 29796 messages[id] = message; 29797 } else { 29798 messages[id].sources.push(...message.sources); 29799 } 29800 }); // Transform placeholder names using the serializer mapping 29801 29802 29803 const msgList = Object.keys(messages).map(id => { 29804 const mapper = serializer.createNameMapper(messages[id]); 29805 const src = messages[id]; 29806 const nodes = mapper ? mapperVisitor.convert(src.nodes, mapper) : src.nodes; 29807 let transformedMessage = new Message(nodes, {}, {}, src.meaning, src.description, id); 29808 transformedMessage.sources = src.sources; 29809 29810 if (filterSources) { 29811 transformedMessage.sources.forEach(source => source.filePath = filterSources(source.filePath)); 29812 } 29813 29814 return transformedMessage; 29815 }); 29816 return serializer.write(msgList, this._locale); 29817 } 29818 29819} // Transform an i18n AST by renaming the placeholder nodes with the given mapper 29820 29821 29822class MapPlaceholderNames extends CloneVisitor { 29823 convert(nodes, mapper) { 29824 return mapper ? nodes.map(n => n.visit(this, mapper)) : nodes; 29825 } 29826 29827 visitTagPlaceholder(ph, mapper) { 29828 const startName = mapper.toPublicName(ph.startName); 29829 const closeName = ph.closeName ? mapper.toPublicName(ph.closeName) : ph.closeName; 29830 const children = ph.children.map(n => n.visit(this, mapper)); 29831 return new TagPlaceholder(ph.tag, ph.attrs, startName, closeName, children, ph.isVoid, ph.sourceSpan, ph.startSourceSpan, ph.endSourceSpan); 29832 } 29833 29834 visitPlaceholder(ph, mapper) { 29835 return new Placeholder(ph.value, mapper.toPublicName(ph.name), ph.sourceSpan); 29836 } 29837 29838 visitIcuPlaceholder(ph, mapper) { 29839 return new IcuPlaceholder(ph.value, mapper.toPublicName(ph.name), ph.sourceSpan); 29840 } 29841 29842} 29843/** 29844 * @license 29845 * Copyright Google LLC All Rights Reserved. 29846 * 29847 * Use of this source code is governed by an MIT-style license that can be 29848 * found in the LICENSE file at https://angular.io/license 29849 */ 29850 29851 29852var FactoryTarget; 29853 29854(function (FactoryTarget) { 29855 FactoryTarget[FactoryTarget["Directive"] = 0] = "Directive"; 29856 FactoryTarget[FactoryTarget["Component"] = 1] = "Component"; 29857 FactoryTarget[FactoryTarget["Injectable"] = 2] = "Injectable"; 29858 FactoryTarget[FactoryTarget["Pipe"] = 3] = "Pipe"; 29859 FactoryTarget[FactoryTarget["NgModule"] = 4] = "NgModule"; 29860})(FactoryTarget || (FactoryTarget = {})); 29861/** 29862 * @license 29863 * Copyright Google LLC All Rights Reserved. 29864 * 29865 * Use of this source code is governed by an MIT-style license that can be 29866 * found in the LICENSE file at https://angular.io/license 29867 */ 29868 29869/** 29870 * @license 29871 * Copyright Google LLC All Rights Reserved. 29872 * 29873 * Use of this source code is governed by an MIT-style license that can be 29874 * found in the LICENSE file at https://angular.io/license 29875 */ 29876 29877/** 29878 * Processes `Target`s with a given set of directives and performs a binding operation, which 29879 * returns an object similar to TypeScript's `ts.TypeChecker` that contains knowledge about the 29880 * target. 29881 */ 29882 29883 29884class R3TargetBinder { 29885 constructor(directiveMatcher) { 29886 this.directiveMatcher = directiveMatcher; 29887 } 29888 /** 29889 * Perform a binding operation on the given `Target` and return a `BoundTarget` which contains 29890 * metadata about the types referenced in the template. 29891 */ 29892 29893 29894 bind(target) { 29895 if (!target.template) { 29896 // TODO(alxhub): handle targets which contain things like HostBindings, etc. 29897 throw new Error('Binding without a template not yet supported'); 29898 } // First, parse the template into a `Scope` structure. This operation captures the syntactic 29899 // scopes in the template and makes them available for later use. 29900 29901 29902 const scope = Scope.apply(target.template); // Use the `Scope` to extract the entities present at every level of the template. 29903 29904 const templateEntities = extractTemplateEntities(scope); // Next, perform directive matching on the template using the `DirectiveBinder`. This returns: 29905 // - directives: Map of nodes (elements & ng-templates) to the directives on them. 29906 // - bindings: Map of inputs, outputs, and attributes to the directive/element that claims 29907 // them. TODO(alxhub): handle multiple directives claiming an input/output/etc. 29908 // - references: Map of #references to their targets. 29909 29910 const { 29911 directives, 29912 bindings, 29913 references 29914 } = DirectiveBinder.apply(target.template, this.directiveMatcher); // Finally, run the TemplateBinder to bind references, variables, and other entities within the 29915 // template. This extracts all the metadata that doesn't depend on directive matching. 29916 29917 const { 29918 expressions, 29919 symbols, 29920 nestingLevel, 29921 usedPipes 29922 } = TemplateBinder.applyWithScope(target.template, scope); 29923 return new R3BoundTarget(target, directives, bindings, references, expressions, symbols, nestingLevel, templateEntities, usedPipes); 29924 } 29925 29926} 29927/** 29928 * Represents a binding scope within a template. 29929 * 29930 * Any variables, references, or other named entities declared within the template will 29931 * be captured and available by name in `namedEntities`. Additionally, child templates will 29932 * be analyzed and have their child `Scope`s available in `childScopes`. 29933 */ 29934 29935 29936class Scope { 29937 constructor(parentScope, template) { 29938 this.parentScope = parentScope; 29939 this.template = template; 29940 /** 29941 * Named members of the `Scope`, such as `Reference`s or `Variable`s. 29942 */ 29943 29944 this.namedEntities = new Map(); 29945 /** 29946 * Child `Scope`s for immediately nested `Template`s. 29947 */ 29948 29949 this.childScopes = new Map(); 29950 } 29951 29952 static newRootScope() { 29953 return new Scope(null, null); 29954 } 29955 /** 29956 * Process a template (either as a `Template` sub-template with variables, or a plain array of 29957 * template `Node`s) and construct its `Scope`. 29958 */ 29959 29960 29961 static apply(template) { 29962 const scope = Scope.newRootScope();
29963 scope.ingest(template); 29964 return scope; 29965 } 29966 /** 29967 * Internal method to process the template and populate the `Scope`. 29968 */ 29969 29970 29971 ingest(template) { 29972 if (template instanceof Template) { 29973 // Variables on an <ng-template> are defined in the inner scope. 29974 template.variables.forEach(node => this.visitVariable(node)); // Process the nodes of the template. 29975 29976 template.children.forEach(node => node.visit(this)); 29977 } else { 29978 // No overarching `Template` instance, so process the nodes directly. 29979 template.forEach(node => node.visit(this)); 29980 } 29981 } 29982 29983 visitElement(element) { 29984 // `Element`s in the template may have `Reference`s which are captured in the scope. 29985 element.references.forEach(node => this.visitReference(node)); // Recurse into the `Element`'s children. 29986 29987 element.children.forEach(node => node.visit(this)); 29988 } 29989 29990 visitTemplate(template) { 29991 // References on a <ng-template> are defined in the outer scope, so capture them before 29992 // processing the template's child scope. 29993 template.references.forEach(node => this.visitReference(node)); // Next, create an inner scope and process the template within it. 29994 29995 const scope = new Scope(this, template); 29996 scope.ingest(template); 29997 this.childScopes.set(template, scope); 29998 } 29999 30000 visitVariable(variable) { 30001 // Declare the variable if it's not already. 30002 this.maybeDeclare(variable); 30003 } 30004 30005 visitReference(reference) { 30006 // Declare the variable if it's not already. 30007 this.maybeDeclare(reference); 30008 } // Unused visitors. 30009 30010 30011 visitContent(content) {} 30012 30013 visitBoundAttribute(attr) {} 30014 30015 visitBoundEvent(event) {} 30016 30017 visitBoundText(text) {} 30018 30019 visitText(text) {} 30020 30021 visitTextAttribute(attr) {} 30022 30023 visitIcu(icu) {} 30024 30025 maybeDeclare(thing) { 30026 // Declare something with a name, as long as that name isn't taken. 30027 if (!this.namedEntities.has(thing.name)) { 30028 this.namedEntities.set(thing.name, thing); 30029 } 30030 } 30031 /** 30032 * Look up a variable within this `Scope`. 30033 * 30034 * This can recurse into a parent `Scope` if it's available. 30035 */ 30036 30037 30038 lookup(name) { 30039 if (this.namedEntities.has(name)) { 30040 // Found in the local scope. 30041 return this.namedEntities.get(name); 30042 } else if (this.parentScope !== null) { 30043 // Not in the local scope, but there's a parent scope so check there. 30044 return this.parentScope.lookup(name); 30045 } else { 30046 // At the top level and it wasn't found. 30047 return null; 30048 } 30049 } 30050 /** 30051 * Get the child scope for a `Template`. 30052 * 30053 * This should always be defined. 30054 */ 30055 30056 30057 getChildScope(template) { 30058 const res = this.childScopes.get(template); 30059 30060 if (res === undefined) { 30061 throw new Error(`Assertion error: child scope for ${template} not found`); 30062 } 30063 30064 return res; 30065 } 30066 30067} 30068/** 30069 * Processes a template and matches directives on nodes (elements and templates). 30070 * 30071 * Usually used via the static `apply()` method. 30072 */ 30073 30074 30075class DirectiveBinder { 30076 constructor(matcher, directives, bindings, references) { 30077 this.matcher = matcher; 30078 this.directives = directives; 30079 this.bindings = bindings; 30080 this.references = references; 30081 } 30082 /** 30083 * Process a template (list of `Node`s) and perform directive matching against each node. 30084 * 30085 * @param template the list of template `Node`s to match (recursively). 30086 * @param selectorMatcher a `SelectorMatcher` containing the directives that are in scope for 30087 * this template. 30088 * @returns three maps which contain information about directives in the template: the 30089 * `directives` map which lists directives matched on each node, the `bindings` map which 30090 * indicates which directives claimed which bindings (inputs, outputs, etc), and the `references` 30091 * map which resolves #references (`Reference`s) within the template to the named directive or 30092 * template node. 30093 */ 30094 30095 30096 static apply(template, selectorMatcher) { 30097 const directives = new Map(); 30098 const bindings = new Map(); 30099 const references = new Map(); 30100 const matcher = new DirectiveBinder(selectorMatcher, directives, bindings, references); 30101 matcher.ingest(template); 30102 return { 30103 directives, 30104 bindings, 30105 references 30106 }; 30107 } 30108 30109 ingest(template) { 30110 template.forEach(node =>
30110 node.visit(this)); 30111 } 30112 30113 visitElement(element) { 30114 this.visitElementOrTemplate(element.name, element); 30115 } 30116 30117 visitTemplate(template) { 30118 this.visitElementOrTemplate('ng-template', template); 30119 } 30120 30121 visitElementOrTemplate(elementName, node) { 30122 // First, determine the HTML shape of the node for the purpose of directive matching. 30123 // Do this by building up a `CssSelector` for the node. 30124 const cssSelector = createCssSelector(elementName, getAttrsForDirectiveMatching(node)); // Next, use the `SelectorMatcher` to get the list of directives on the node. 30125 30126 const directives = []; 30127 this.matcher.match(cssSelector, (_, directive) => directives.push(directive)); 30128 30129 if (directives.length > 0) { 30130 this.directives.set(node, directives); 30131 } // Resolve any references that are created on this node. 30132 30133 30134 node.references.forEach(ref => { 30135 let dirTarget = null; // If the reference expression is empty, then it matches the "primary" directive on the node 30136 // (if there is one). Otherwise it matches the host node itself (either an element or 30137 // <ng-template> node). 30138 30139 if (ref.value.trim() === '') { 30140 // This could be a reference to a component if there is one. 30141 dirTarget = directives.find(dir => dir.isComponent) || null; 30142 } else { 30143 // This should be a reference to a directive exported via exportAs. 30144 dirTarget = directives.find(dir => dir.exportAs !== null && dir.exportAs.some(value => value === ref.value)) || null; // Check if a matching directive was found. 30145 30146 if (dirTarget === null) { 30147 // No matching directive was found - this reference points to an unknown target. Leave it 30148 // unmapped. 30149 return; 30150 } 30151 } 30152 30153 if (dirTarget !== null) { 30154 // This reference points to a directive. 30155 this.references.set(ref, { 30156 directive: dirTarget, 30157 node 30158 }); 30159 } else { 30160 // This reference points to the node itself. 30161 this.references.set(ref, node); 30162 } 30163 }); 30164 30165 const setAttributeBinding = (attribute, ioType) => { 30166 const dir = directives.find(dir => dir[ioType].hasBindingPropertyName(attribute.name)); 30167 const binding = dir !== undefined ? dir : node; 30168 this.bindings.set(attribute, binding); 30169 }; // Node inputs (bound attributes) and text attributes can be bound to an 30170 // input on a directive. 30171 30172 30173 node.inputs.forEach(input => setAttributeBinding(input, 'inputs')); 30174 node.attributes.forEach(attr => setAttributeBinding(attr, 'inputs')); 30175 30176 if (node instanceof Template) { 30177 node.templateAttrs.forEach(attr => setAttributeBinding(attr, 'inputs')); 30178 } // Node outputs (bound events) can be bound to an output on a directive. 30179 30180 30181 node.outputs.forEach(output => setAttributeBinding(output, 'outputs')); // Recurse into the node's children. 30182 30183 node.children.forEach(child => child.visit(this)); 30184 } // Unused visitors. 30185 30186 30187 visitContent(content) {} 30188 30189 visitVariable(variable) {} 30190 30191 visitReference(reference) {} 30192 30193 visitTextAttribute(attribute) {} 30194 30195 visitBoundAttribute(attribute) {} 30196 30197 visitBoundEvent(attribute) {} 30198 30199 visitBoundAttributeOrEvent(node) {} 30200 30201 visitText(text) {} 30202 30203 visitBoundText(text) {} 30204 30205 visitIcu(icu) {} 30206 30207} 30208/** 30209 * Processes a template and extract metadata about expressions and symbols within. 30210 * 30211 * This is a companion to the `DirectiveBinder` that doesn't require knowledge of directives matched 30212 * within the template in order to operate. 30213 * 30214 * Expressions are visited by the superclass `RecursiveAstVisitor`, with custom logic provided 30215 * by overridden methods from that visitor. 30216 */ 30217 30218 30219class TemplateBinder extends RecursiveAstVisitor { 30220 constructor(bindings, symbols, usedPipes, nestingLevel, scope, template, level) { 30221 super(); 30222 this.bindings = bindings; 30223 this.symbols = symbols; 30224 this.usedPipes = usedPipes; 30225 this.nestingLevel = nestingLevel; 30226 this.scope = scope; 30227 this.template = template; 30228 this.level = level; 30229 this.pipesUsed = []; // Save a bit of processing time by constructing this closure in advance. 30230 30231 this.visitNode = node =>
30231 node.visit(this); 30232 } // This method is defined to reconcile the type of TemplateBinder since both 30233 // RecursiveAstVisitor and Visitor define the visit() method in their 30234 // interfaces. 30235 30236 30237 visit(node, context) { 30238 if (node instanceof AST) { 30239 node.visit(this, context); 30240 } else { 30241 node.visit(this); 30242 } 30243 } 30244 /** 30245 * Process a template and extract metadata about expressions and symbols within. 30246 * 30247 * @param template the nodes of the template to process 30248 * @param scope the `Scope` of the template being processed. 30249 * @returns three maps which contain metadata about the template: `expressions` which interprets 30250 * special `AST` nodes in expressions as pointing to references or variables declared within the 30251 * template, `symbols` which maps those variables and references to the nested `Template` which 30252 * declares them, if any, and `nestingLevel` which associates each `Template` with a integer 30253 * nesting level (how many levels deep within the template structure the `Template` is), starting 30254 * at 1. 30255 */ 30256 30257 30258 static applyWithScope(template, scope) { 30259 const expressions = new Map(); 30260 const symbols = new Map(); 30261 const nestingLevel = new Map(); 30262 const usedPipes = new Set(); // The top-level template has nesting level 0. 30263 30264 const binder = new TemplateBinder(expressions, symbols, usedPipes, nestingLevel, scope, template instanceof Template ? template : null, 0); 30265 binder.ingest(template); 30266 return { 30267 expressions, 30268 symbols, 30269 nestingLevel, 30270 usedPipes 30271 }; 30272 } 30273 30274 ingest(template) { 30275 if (template instanceof Template) { 30276 // For <ng-template>s, process only variables and child nodes. Inputs, outputs, templateAttrs, 30277 // and references were all processed in the scope of the containing template.
30278 template.variables.forEach(this.visitNode); 30279 template.children.forEach(this.visitNode); // Set the nesting level. 30280 30281 this.nestingLevel.set(template, this.level); 30282 } else { 30283 // Visit each node from the top-level template. 30284 template.forEach(this.visitNode); 30285 } 30286 } 30287 30288 visitElement(element) { 30289 // Visit the inputs, outputs, and children of the element. 30290 element.inputs.forEach(this.visitNode); 30291 element.outputs.forEach(this.visitNode); 30292 element.children.forEach(this.visitNode); 30293 } 30294 30295 visitTemplate(template) { 30296 // First, visit inputs, outputs and template attributes of the template node. 30297 template.inputs.forEach(this.visitNode); 30298 template.outputs.forEach(this.visitNode); 30299 template.templateAttrs.forEach(this.visitNode); // References are also evaluated in the outer context. 30300 30301 template.references.forEach(this.visitNode); // Next, recurse into the template using its scope, and bumping the nesting level up by one. 30302 30303 const childScope = this.scope.getChildScope(template); 30304 const binder = new TemplateBinder(this.bindings, this.symbols, this.usedPipes, this.nestingLevel, childScope, template, this.level + 1); 30305 binder.ingest(template); 30306 } 30307 30308 visitVariable(variable) { 30309 // Register the `Variable` as a symbol in the current `Template`. 30310 if (this.template !== null) { 30311 this.symbols.set(variable, this.template); 30312 } 30313 } 30314 30315 visitReference(reference) { 30316 // Register the `Reference` as a symbol in the current `Template`. 30317 if (this.template !== null) { 30318 this.symbols.set(reference, this.template); 30319 } 30320 } // Unused template visitors 30321 30322 30323 visitText(text) {} 30324 30325 visitContent(content) {} 30326 30327 visitTextAttribute(attribute) {} 30328 30329 visitIcu(icu) { 30330 Object.keys(icu.vars).forEach(key => icu.vars[key].visit(this)); 30331 Object.keys(icu.placeholders).forEach(key => icu.placeholders[key].visit(this)); 30332 } // The remaining visitors are concerned with processing AST expressions within template bindings 30333 30334 30335 visitBoundAttribute(attribute) { 30336 attribute.value.visit(this); 30337 } 30338 30339 visitBoundEvent(event) { 30340 event.handler.visit(this); 30341 } 30342 30343 visitBoundText(text) { 30344 text.value.visit(this); 30345 } 30346 30347 visitPipe(ast, context) { 30348 this.usedPipes.add(ast.name); 30349 return super.visitPipe(ast, context); 30350 } // These five types of AST expressions can refer to expression roots, which could be variables 30351 // or references in the current scope. 30352 30353 30354 visitPropertyRead(ast, context) { 30355 this.maybeMap(context, ast, ast.name); 30356 return super.visitPropertyRead(ast, context); 30357 } 30358 30359 visitSafePropertyRead(ast, context) { 30360 this.maybeMap(context, ast, ast.name); 30361 return super.visitSafePropertyRead(ast, context); 30362 } 30363 30364 visitPropertyWrite(ast, context) { 30365 this.maybeMap(context, ast, ast.name); 30366 return super.visitPropertyWrite(ast, context); 30367 } 30368 30369 maybeMap(scope, ast, name) { 30370 // If the receiver of the expression isn't the `ImplicitReceiver`, this isn't the root of an 30371 // `AST` expression that maps to a `Variable` or `Reference`. 30372 if (!(ast.receiver instanceof ImplicitReceiver)) { 30373 return; 30374 } // Check whether the name exists in the current scope. If so, map it. Otherwise, the name is 30375 // probably a property on the top-level component context. 30376 30377 30378 let target = this.scope.lookup(name); 30379 30380 if (target !== null) { 30381 this.bindings.set(ast, target); 30382 } 30383 } 30384 30385} 30386/** 30387 * Metadata container for a `Target` that allows queries for specific bits of metadata. 30388 * 30389 * See `BoundTarget` for documentation on the individual methods. 30390 */ 30391 30392 30393class R3BoundTarget { 30394 constructor(target, directives, bindings, references, exprTargets, symbols, nestingLevel, templateEntities, usedPipes) { 30395 this.target = target; 30396 this.directives = directives; 30397 this.bindings = bindings; 30398 this.references = references; 30399 this.exprTargets = exprTargets; 30400 this.symbols = symbols; 30401 this.nestingLevel = nestingLevel; 30402 this.templateEntities = templateEntities; 30403 this.usedPipes = usedPipes; 30404 } 30405 30406 getEntitiesInTemplateScope(template) { 30407 return this.templateEntities.get(template) ?? new Set(); 30408 } 30409 30410 getDirectivesOfNode(node) { 30411 return this.directives.get(node) || null; 30412 } 30413 30414 getReferenceTarget(ref) { 30415 return this.references.get(ref) || null; 30416 } 30417 30418 getConsumerOfBinding(binding) { 30419 return this.bindings.get(binding) || null; 30420 } 30421 30422 getExpressionTarget(expr) { 30423 return this.exprTargets.get(expr) || null; 30424 } 30425 30426 getTemplateOfSymbol(symbol) { 30427 return this.symbols.get(symbol) || null; 30428 } 30429 30430 getNestingLevel(template) { 30431 return this.nestingLevel.get(template) || 0; 30432 } 30433 30434 getUsedDirectives() { 30435 const set = new Set();
30436 this.directives.forEach(dirs => dirs.forEach(dir => set.add(dir))); 30437 return Array.from(set.values()); 30438 } 30439 30440 getUsedPipes() { 30441 return Array.from(this.usedPipes); 30442 } 30443 30444} 30445 30446function extractTemplateEntities(rootScope) { 30447 const entityMap = new Map(); 30448 30449 function extractScopeEntities(scope) { 30450 if (entityMap.has(scope.template)) { 30451 return entityMap.get(scope.template); 30452 } 30453 30454 const currentEntities = scope.namedEntities; 30455 let templateEntities; 30456 30457 if (scope.parentScope !== null) { 30458 templateEntities = new Map([...extractScopeEntities(scope.parentScope), ...currentEntities]); 30459 } else { 30460 templateEntities = new Map(currentEntities); 30461 } 30462 30463 entityMap.set(scope.template, templateEntities); 30464 return templateEntities; 30465 } 30466 30467 const scopesToProcess = [rootScope]; 30468 30469 while (scopesToProcess.length > 0) { 30470 const scope = scopesToProcess.pop(); 30471 30472 for (const childScope of scope.childScopes.values()) { 30473 scopesToProcess.push(childScope); 30474 } 30475 30476 extractScopeEntities(scope); 30477 } 30478 30479 const templateEntities = new Map(); 30480 30481 for (const [template, entities] of entityMap) { 30482 templateEntities.set(template, new Set(entities.values())); 30483 } 30484 30485 return templateEntities; 30486} 30487/** 30488 * @license 30489 * Copyright Google LLC All Rights Reserved. 30490 * 30491 * Use of this source code is governed by an MIT-style license that can be 30492 * found in the LICENSE file at https://angular.io/license 30493 */ 30494 30495 30496function compileClassMetadata(metadata) { 30497 // Generate an ngDevMode guarded call to setClassMetadata with the class identifier and its 30498 // metadata. 30499 const fnCall = importExpr(Identifiers.setClassMetadata).callFn([metadata.type, metadata.decorators, metadata.ctorParameters ?? literal(null), metadata.propDecorators ?? literal(null)]); 30500 const iife = fn([], [devOnlyGuardedExpression(fnCall).toStmt()]); 30501 return iife.callFn([]); 30502} 30503/** 30504 * @license 30505 * Copyright Google LLC All Rights Reserved. 30506 * 30507 * Use of this source code is governed by an MIT-style license that can be 30508 * found in the LICENSE file at https://angular.io/license 30509 */ 30510 30511/** 30512 * Every time we make a breaking change to the declaration interface or partial-linker behavior, we 30513 * must update this constant to prevent old partial-linkers from incorrectly processing the 30514 * declaration. 30515 * 30516 * Do not include any prerelease in these versions as they are ignored. 30517 */ 30518 30519 30520const MINIMUM_PARTIAL_LINKER_VERSION$6 = '12.0.0'; 30521 30522function compileDeclareClassMetadata(metadata) { 30523 const definitionMap = new DefinitionMap(); 30524 definitionMap.set('minVersion', literal(MINIMUM_PARTIAL_LINKER_VERSION$6)); 30525 definitionMap.set('version', literal('14.2.12')); 30526 definitionMap.set('ngImport', importExpr(Identifiers.core)); 30527 definitionMap.set('type', metadata.type); 30528 definitionMap.set('decorators', metadata.decorators); 30529 definitionMap.set('ctorParameters', metadata.ctorParameters); 30530 definitionMap.set('propDecorators', metadata.propDecorators); 30531 return importExpr(Identifiers.declareClassMetadata).callFn([definitionMap.toLiteralMap()]); 30532} 30533/** 30534 * @license 30535 * Copyright Google LLC All Rights Reserved. 30536 * 30537 * Use of this source code is governed by an MIT-style license that can be 30538 * found in the LICENSE file at https://angular.io/license 30539 */ 30540 30541/** 30542 * Creates an array literal expression from the given array, mapping all values to an expression 30543 * using the provided mapping function. If the array is empty or null, then null is returned. 30544 * 30545 * @param values The array to transfer into literal array expression. 30546 * @param mapper The logic to use for creating an expression for the array's values. 30547 * @returns An array literal expression representing `values`, or null if `values` is empty or 30548 * is itself null. 30549 */ 30550 30551 30552function toOptionalLiteralArray(values, mapper) { 30553 if (values === null || values.length === 0) { 30554 return null; 30555 } 30556 30557 return literalArr(values.map(value => mapper(value))); 30558} 30559/** 30560 * Creates an object literal expression from the given object, mapping all values to an expression 30561 * using the provided mapping function. If the object has no keys, then null is returned. 30562 * 30563 * @param object The object to transfer into an object literal expression. 30564 * @param mapper The logic to use for creating an expression for the object's values. 30565 * @returns An object literal expression representing `object`, or null if `object` does not have 30566 * any keys. 30567 */ 30568 30569 30570function toOptionalLiteralMap(object, mapper) { 30571 const entries = Object.keys(object).map(key => { 30572 const value = object[key]; 30573 return { 30574 key, 30575 value: mapper(value), 30576 quoted: true 30577 }; 30578 }); 30579 30580 if (entries.length > 0) { 30581 return literalMap(entries); 30582 } else { 30583 return null; 30584 } 30585} 30586 30587function compileDependencies(deps) {
30588 if (deps === 'invalid') { 30589 // The `deps` can be set to the string "invalid" by the `unwrapConstructorDependencies()` 30590 // function, which tries to convert `ConstructorDeps` into `R3DependencyMetadata[]`. 30591 return literal('invalid'); 30592 } else if (deps === null) { 30593 return literal(null); 30594 } else { 30595 return literalArr(deps.map(compileDependency)); 30596 } 30597} 30598 30599function compileDependency(dep) { 30600 const depMeta = new DefinitionMap(); 30601 depMeta.set('token', dep.token); 30602 30603 if (dep.attributeNameType !== null) { 30604 depMeta.set('attribute', literal(true)); 30605 } 30606 30607 if (dep.host) { 30608 depMeta.set('host', literal(true)); 30609 } 30610 30611 if (dep.optional) { 30612 depMeta.set('optional', literal(true)); 30613 } 30614 30615 if (dep.self) { 30616 depMeta.set('self', literal(true)); 30617 } 30618 30619 if (dep.skipSelf) { 30620 depMeta.set('skipSelf', literal(true)); 30621 } 30622 30623 return depMeta.toLiteralMap(); 30624} 30625/** 30626 * @license 30627 * Copyright Google LLC All Rights Reserved. 30628 * 30629 * Use of this source code is governed by an MIT-style license that can be 30630 * found in the LICENSE file at https://angular.io/license 30631 */ 30632 30633/** 30634 * Every time we make a breaking change to the declaration interface or partial-linker behavior, we 30635 * must update this constant to prevent old partial-linkers from incorrectly processing the 30636 * declaration. 30637 * 30638 * Do not include any prerelease in these versions as they are ignored. 30639 */ 30640 30641 30642const MINIMUM_PARTIAL_LINKER_VERSION$5 = '14.0.0'; 30643/** 30644 * Compile a directive declaration defined by the `R3DirectiveMetadata`. 30645 */ 30646 30647function compileDeclareDirectiveFromMetadata(meta) { 30648 const definitionMap = createDirectiveDefinitionMap(meta); 30649 const expression = importExpr(Identifiers.declareDirective).callFn([definitionMap.toLiteralMap()]); 30650 const type = createDirectiveType(meta); 30651 return { 30652 expression, 30653 type, 30654 statements: [] 30655 }; 30656} 30657/** 30658 * Gathers the declaration fields for a directive into a `DefinitionMap`. This allows for reusing 30659 * this logic for components, as they extend the directive metadata. 30660 */ 30661 30662 30663function createDirectiveDefinitionMap(meta) { 30664 const definitionMap = new DefinitionMap(); 30665 definitionMap.set('minVersion', literal(MINIMUM_PARTIAL_LINKER_VERSION$5)); 30666 definitionMap.set('version', literal('14.2.12')); // e.g. `type: MyDirective` 30667 30668 definitionMap.set('type', meta.internalType); 30669 30670 if (meta.isStandalone) { 30671 definitionMap.set('isStandalone', literal(meta.isStandalone)); 30672 } // e.g. `selector: 'some-dir'` 30673 30674 30675 if (meta.selector !== null) { 30676 definitionMap.set('selector', literal(meta.selector)); 30677 } 30678 30679 definitionMap.set('inputs', conditionallyCreateMapObjectLiteral(meta.inputs, true)); 30680 definitionMap.set('outputs', conditionallyCreateMapObjectLiteral(meta.outputs)); 30681 definitionMap.set('host', compileHostMetadata(meta.host)); 30682 definitionMap.set('providers', meta.providers); 30683 30684 if (meta.queries.length > 0) { 30685 definitionMap.set('queries', literalArr(meta.queries.map(compileQuery))); 30686 } 30687 30688 if (meta.viewQueries.length > 0) { 30689 definitionMap.set('viewQueries', literalArr(meta.viewQueries.map(compileQuery))); 30690 } 30691 30692 if (meta.exportAs !== null) { 30693 definitionMap.set('exportAs', asLiteral(meta.exportAs)); 30694 } 30695 30696 if (meta.usesInheritance) { 30697 definitionMap.set('usesInheritance', literal(true)); 30698 } 30699 30700 if (meta.lifecycle.usesOnChanges) { 30701 definitionMap.set('usesOnChanges', literal(true)); 30702 } 30703 30704 definitionMap.set('ngImport', importExpr(Identifiers.core)); 30705 return definitionMap; 30706} 30707/** 30708 * Compiles the metadata of a single query into its partial declaration form as declared 30709 * by `R3DeclareQueryMetadata`. 30710 */ 30711 30712 30713function compileQuery(query) { 30714 const meta = new DefinitionMap(); 30715 meta.set('propertyName', literal(query.propertyName)); 30716 30717 if (query.first) { 30718 meta.set('first', literal(true)); 30719 } 30720 30721 meta.set('predicate', Array.isArray(query.predicate) ? asLiteral(query.predicate) : convertFromMaybeForwardRefExpression(query.predicate)); 30722 30723 if (!query.emitDistinctChangesOnly) { 30724 // `emitDistinctChangesOnly` is special because we expect it to be `true`. 30725 // Therefore we explicitly emit the field, and explicitly place it only when it's `false`. 30726 meta.set('emitDistinctChangesOnly', literal(false)); 30727 } else {// The linker will assume that an absent `emitDistinctChangesOnly` flag is by default `true`. 30728 } 30729 30730 if (query.descendants) { 30731 meta.set('descendants', literal(true)); 30732 } 30733 30734 meta.set('read', query.read); 30735 30736 if (query.static) { 30737 meta.set('static', literal(true)); 30738 } 30739 30740 return meta.toLiteralMap(); 30741} 30742/** 30743 * Compiles the host metadata into its partial declaration form as declared 30744 * in `R3DeclareDirectiveMetadata['host']` 30745 */ 30746 30747 30748function compileHostMetadata(meta) { 30749 const hostMetadata = new DefinitionMap(); 30750 hostMetadata.set('attributes', toOptionalLiteralMap(meta.attributes, expression => expression)); 30751 hostMetadata.set('listeners', toOptionalLiteralMap(meta.listeners, literal)); 30752 hostMetadata.set('properties', toOptionalLiteralMap(meta.properties, literal)); 30753 30754 if (meta.specialAttributes.styleAttr) { 30755 hostMetadata.set('styleAttribute', literal(meta.specialAttributes.styleAttr)); 30756 } 30757 30758 if (meta.specialAttributes.classAttr) { 30759 hostMetadata.set('classAttribute', literal(meta.specialAttributes.classAttr)); 30760 } 30761 30762 if (hostMetadata.values.length > 0) { 30763 return hostMetadata.toLiteralMap(); 30764 } else { 30765 return null; 30766 } 30767} 30768/** 30769 * @license 30770 * Copyright Google LLC All Rights Reserved. 30771 * 30772 * Use of this source code is governed by an MIT-style license that can be 30773 * found in the LICENSE file at https://angular.io/license 30774 */ 30775 30776/** 30777 * Compile a component declaration defined by the `R3ComponentMetadata`. 30778 */ 30779 30780 30781function compileDeclareComponentFromMetadata(meta, template, additionalTemplateInfo) { 30782 const definitionMap = createComponentDefinitionMap(meta, template, additionalTemplateInfo); 30783 const expression = importExpr(Identifiers.declareComponent).callFn([definitionMap.toLiteralMap()]); 30784 const type = createComponentType(meta); 30785 return { 30786 expression, 30787 type, 30788 statements: [] 30789 }; 30790} 30791/** 30792 * Gathers the declaration fields for a component into a `DefinitionMap`. 30793 */ 30794 30795 30796function createComponentDefinitionMap(meta, template, templateInfo) { 30797 const definitionMap = createDirectiveDefinitionMap(meta); 30798 definitionMap.set('template', getTemplateExpression(template, templateInfo)); 30799 30800 if (templateInfo.isInline) { 30801 definitionMap.set('isInline', literal(true)); 30802 } 30803 30804 definitionMap.set('styles', toOptionalLiteralArray(meta.styles, literal)); 30805 definitionMap.set('dependencies', compileUsedDependenciesMetadata(meta)); 30806 definitionMap.set('viewProviders', meta.viewProviders); 30807 definitionMap.set('animations', meta.animations); 30808 30809 if (meta.changeDetection !== undefined) { 30810 definitionMap.set('changeDetection', importExpr(Identifiers.ChangeDetectionStrategy).prop(ChangeDetectionStrategy[meta.changeDetection])); 30811 } 30812 30813 if (meta.encapsulation !== ViewEncapsulation.Emulated) { 30814 definitionMap.set('encapsulation', importExpr(Identifiers.ViewEncapsulation).prop(ViewEncapsulation[meta.encapsulation])); 30815 } 30816 30817 if (meta.interpolation !== DEFAULT_INTERPOLATION_CONFIG) { 30818 definitionMap.set('interpolation', literalArr([literal(meta.interpolation.start), literal(meta.interpolation.end)])); 30819 } 30820
30821 if (template.preserveWhitespaces === true) { 30822 definitionMap.set('preserveWhitespaces', literal(true)); 30823 } 30824 30825 return definitionMap; 30826} 30827 30828function getTemplateExpression(template, templateInfo) { 30829 // If the template has been defined using a direct literal, we use that expression directly 30830 // without any modifications. This is ensures proper source mapping from the partially 30831 // compiled code to the source file declaring the template. Note that this does not capture 30832 // template literals referenced indirectly through an identifier. 30833 if (templateInfo.inlineTemplateLiteralExpression !== null) { 30834 return templateInfo.inlineTemplateLiteralExpression; 30835 } // If the template is defined inline but not through a literal, the template has been resolved 30836 // through static interpretation. We create a literal but cannot provide any source span. Note 30837 // that we cannot use the expression defining the template because the linker expects the template 30838 // to be defined as a literal in the declaration. 30839 30840 30841 if (templateInfo.isInline) { 30842 return literal(templateInfo.content, null, null); 30843 } // The template is external so we must synthesize an expression node with 30844 // the appropriate source-span. 30845 30846 30847 const contents = templateInfo.content; 30848 const file = new ParseSourceFile(contents, templateInfo.sourceUrl); 30849 const start = new ParseLocation(file, 0, 0, 0); 30850 const end = computeEndLocation(file, contents); 30851 const span = new ParseSourceSpan(start, end); 30852 return literal(contents, null, span); 30853} 30854 30855function computeEndLocation(file, contents) { 30856 const length = contents.length; 30857 let lineStart = 0; 30858 let lastLineStart = 0; 30859 let line = 0; 30860 30861 do { 30862 lineStart = contents.indexOf('\n', lastLineStart); 30863 30864 if (lineStart !== -1) { 30865 lastLineStart = lineStart + 1; 30866 line++; 30867 } 30868 } while (lineStart !== -1); 30869 30870 return new ParseLocation(file, length, line, length - lastLineStart); 30871} 30872 30873function compileUsedDependenciesMetadata(meta) { 30874 const wrapType = meta.declarationListEmitMode !== 0 30875 /* DeclarationListEmitMode.Direct */ 30876 ? generateForwardRef : expr => expr; 30877 return toOptionalLiteralArray(meta.declarations, decl => { 30878 switch (decl.kind) { 30879 case R3TemplateDependencyKind.Directive: 30880 const dirMeta = new DefinitionMap(); 30881 dirMeta.set('kind', literal(decl.isComponent ? 'component' : 'directive')); 30882 dirMeta.set('type', wrapType(decl.type)); 30883 dirMeta.set('selector', literal(decl.selector)); 30884 dirMeta.set('inputs', toOptionalLiteralArray(decl.inputs, literal)); 30885 dirMeta.set('outputs', toOptionalLiteralArray(decl.outputs, literal)); 30886 dirMeta.set('exportAs', toOptionalLiteralArray(decl.exportAs, literal)); 30887 return dirMeta.toLiteralMap(); 30888 30889 case R3TemplateDependencyKind.Pipe: 30890 const pipeMeta = new DefinitionMap(); 30891 pipeMeta.set('kind', literal('pipe')); 30892 pipeMeta.set('type', wrapType(decl.type)); 30893 pipeMeta.set('name', literal(decl.name)); 30894 return pipeMeta.toLiteralMap(); 30895 30896 case R3TemplateDependencyKind.NgModule: 30897 const ngModuleMeta = new DefinitionMap(); 30898 ngModuleMeta.set('kind', literal('ngmodule')); 30899 ngModuleMeta.set('type', wrapType(decl.type)); 30900 return ngModuleMeta.toLiteralMap(); 30901 } 30902 }); 30903} 30904/** 30905 * @license 30906 * Copyright Google LLC All Rights Reserved. 30907 * 30908 * Use of this source code is governed by an MIT-style license that can be 30909 * found in the LICENSE file at https://angular.io/license 30910 */ 30911 30912/** 30913 * Every time we make a breaking change to the declaration interface or partial-linker behavior, we 30914 * must update this constant to prevent old partial-linkers from incorrectly processing the 30915 * declaration. 30916 * 30917 * Do not include any prerelease in these versions as they are ignored. 30918 */ 30919 30920 30921const MINIMUM_PARTIAL_LINKER_VERSION$4 = '12.0.0'; 30922 30923function compileDeclareFactoryFunction(meta) { 30924 const definitionMap = new DefinitionMap(); 30925 definitionMap.set('minVersion', literal(MINIMUM_PARTIAL_LINKER_VERSION$4)); 30926 definitionMap.set('version', literal('14.2.12')); 30927 definitionMap.set('ngImport', importExpr(Identifiers.core)); 30928 definitionMap.set('type', meta.internalType); 30929 definitionMap.set('deps', compileDependencies(meta.deps)); 30930 definitionMap.set('target', importExpr(Identifiers.FactoryTarget).prop(FactoryTarget$1[meta.target])); 30931 return { 30932 expression: importExpr(Identifiers.declareFactory).callFn([definitionMap.toLiteralMap()]), 30933 statements: [], 30934 type: createFactoryType(meta) 30935 }; 30936} 30937/** 30938 * @license 30939 * Copyright Google LLC All Rights Reserved. 30940 * 30941 * Use of this source code is governed by an MIT-style license that can be 30942 * found in the LICENSE file at https://angular.io/license 30943 */ 30944 30945/** 30946 * Every time we make a breaking change to the declaration interface or partial-linker behavior, we 30947 * must update this constant to prevent old partial-linkers from incorrectly processing the 30948 * declaration. 30949 * 30950 * Do not include any prerelease in these versions as they are ignored. 30951 */ 30952 30953 30954const MINIMUM_PARTIAL_LINKER_VERSION$3 = '12.0.0'; 30955/** 30956 * Compile a Injectable declaration defined by the `R3InjectableMetadata`. 30957 */ 30958 30959function compileDeclareInjectableFromMetadata(meta) { 30960 const definitionMap = createInjectableDefinitionMap(meta); 30961 const expression = importExpr(Identifiers.declareInjectable).callFn([definitionMap.toLiteralMap()]); 30962 const type = createInjectableType(meta); 30963 return { 30964 expression, 30965 type, 30966 statements: [] 30967 }; 30968} 30969/** 30970 * Gathers the declaration fields for a Injectable into a `DefinitionMap`. 30971 */ 30972 30973 30974function createInjectableDefinitionMap(meta) { 30975 const definitionMap = new DefinitionMap(); 30976 definitionMap.set('minVersion', literal(MINIMUM_PARTIAL_LINKER_VERSION$3)); 30977 definitionMap.set('version', literal('14.2.12')); 30978 definitionMap.set('ngImport', importExpr(Identifiers.core)); 30979 definitionMap.set('type', meta.internalType); // Only generate providedIn property if it has a non-null value 30980 30981 if (meta.providedIn !== undefined) { 30982 const providedIn = convertFromMaybeForwardRefExpression(meta.providedIn); 30983 30984 if (providedIn.value !== null) { 30985 definitionMap.set('providedIn', providedIn); 30986 } 30987 } 30988 30989 if (meta.useClass !== undefined) { 30990 definitionMap.set('useClass', convertFromMaybeForwardRefExpression(meta.useClass)); 30991 } 30992 30993 if (meta.useExisting !== undefined) { 30994 definitionMap.set('useExisting', convertFromMaybeForwardRefExpression(meta.useExisting)); 30995 } 30996 30997 if (meta.useValue !== undefined) { 30998 definitionMap.set('useValue', convertFromMaybeForwardRefExpression(meta.useValue)); 30999 } // Factories do not contain `ForwardRef`s since any types are already wrapped in a function call 31000 // so the types will not be eagerly evaluated. Therefore we do not need to process this expression 31001 // with `convertFromProviderExpression()`. 31002 31003 31004 if (meta.useFactory !== undefined) { 31005 definitionMap.set('useFactory', meta.useFactory); 31006 } 31007 31008 if (meta.deps !== undefined) { 31009 definitionMap.set('deps', literalArr(meta.deps.map(compileDependency))); 31010 } 31011 31012 return definitionMap; 31013} 31014/** 31015 * @license 31016 * Copyright Google LLC All Rights Reserved. 31017 * 31018 * Use of this source code is governed by an MIT-style license that can be 31019 * found in the LICENSE file at https://angular.io/license 31020 */ 31021 31022/** 31023 * Every time we make a breaking change to the declaration interface or partial-linker behavior, we 31024 * must update this constant to prevent old partial-linkers from incorrectly processing the 31025 * declaration. 31026 * 31027 * Do not include any prerelease in these versions as they are ignored. 31028 */ 31029 31030 31031const MINIMUM_PARTIAL_LINKER_VERSION$2 = '12.0.0'; 31032 31033function compileDeclareInjectorFromMetadata(meta) { 31034 const definitionMap = createInjectorDefinitionMap(meta); 31035 const expression = importExpr(Identifiers.declareInjector).callFn([definitionMap.toLiteralMap()]); 31036 const type = createInjectorType(meta); 31037 return { 31038 expression, 31039 type, 31040 statements: [] 31041 }; 31042} 31043/** 31044 * Gathers the declaration fields for an Injector into a `DefinitionMap`. 31045 */ 31046 31047 31048function createInjectorDefinitionMap(meta) { 31049 const definitionMap = new DefinitionMap(); 31050 definitionMap.set('minVersion', literal(MINIMUM_PARTIAL_LINKER_VERSION$2)); 31051 definitionMap.set('version', literal('14.2.12')); 31052 definitionMap.set('ngImport', importExpr(Identifiers.core)); 31053 definitionMap.set('type', meta.internalType); 31054 definitionMap.set('providers', meta.providers); 31055 31056 if (meta.imports.length > 0) { 31057 definitionMap.set('imports', literalArr(meta.imports)); 31058 } 31059 31060 return definitionMap; 31061} 31062/** 31063 * @license 31064 * Copyright Google LLC All Rights Reserved. 31065 * 31066 * Use of this source code is governed by an MIT-style license that can be 31067 * found in the LICENSE file at https://angular.io/license 31068 */ 31069 31070/** 31071 * Every time we make a breaking change to the declaration interface or partial-linker behavior, we 31072 * must update this constant to prevent old partial-linkers from incorrectly processing the 31073 * declaration. 31074 * 31075 * Do not include any prerelease in these versions as they are ignored. 31076 */ 31077 31078 31079const MINIMUM_PARTIAL_LINKER_VERSION$1 = '14.0.0'; 31080 31081function compileDeclareNgModuleFromMetadata(meta) { 31082 const definitionMap = createNgModuleDefinitionMap(meta); 31083 const expression = importExpr(Identifiers.declareNgModule).callFn([definitionMap.toLiteralMap()]); 31084 const type = createNgModuleType(meta); 31085 return { 31086 expression, 31087 type, 31088 statements: [] 31089 }; 31090} 31091/** 31092 * Gathers the declaration fields for an NgModule into a `DefinitionMap`. 31093 */ 31094 31095 31096function createNgModuleDefinitionMap(meta) { 31097 const definitionMap = new DefinitionMap(); 31098 definitionMap.set('minVersion', literal(MINIMUM_PARTIAL_LINKER_VERSION$1)); 31099 definitionMap.set('version', literal('14.2.12')); 31100 definitionMap.set('ngImport', importExpr(Identifiers.core)); 31101 definitionMap.set('type', meta.internalType); // We only generate the keys in the metadata if the arrays contain values. 31102 // We must wrap the arrays inside a function if any of the values are a forward reference to a 31103 // not-yet-declared class. This is to support JIT execution of the `ɵɵngDeclareNgModule(
31103)` call. 31104 // In the linker these wrappers are stripped and then reapplied for the `ɵɵdefineNgModule()` call. 31105 31106 if (meta.bootstrap.length > 0) { 31107 definitionMap.set('bootstrap', refsToArray(meta.bootstrap, meta.containsForwardDecls)); 31108 } 31109 31110 if (meta.declarations.length > 0) { 31111 definitionMap.set('declarations', refsToArray(meta.declarations, meta.containsForwardDecls)); 31112 } 31113 31114 if (meta.imports.length > 0) { 31115 definitionMap.set('imports', refsToArray(meta.imports, meta.containsForwardDecls)); 31116 } 31117 31118 if (meta.exports.length > 0) { 31119 definitionMap.set('exports', refsToArray(meta.exports, meta.containsForwardDecls)); 31120 } 31121 31122 if (meta.schemas !== null && meta.schemas.length > 0) { 31123 definitionMap.set('schemas', literalArr(meta.schemas.map(ref => ref.value))); 31124 } 31125 31126 if (meta.id !== null) { 31127 definitionMap.set('id', meta.id); 31128 } 31129 31130 return definitionMap; 31131} 31132/** 31133 * @license 31134 * Copyright Google LLC All Rights Reserved. 31135 * 31136 * Use of this source code is governed by an MIT-style license that can be 31137 * found in the LICENSE file at https://angular.io/license 31138 */ 31139 31140/** 31141 * Every time we make a breaking change to the declaration interface or partial-linker behavior, we 31142 * must update this constant to prevent old partial-linkers from incorrectly processing the 31143 * declaration. 31144 * 31145 * Do not include any prerelease in these versions as they are ignored. 31146 */ 31147 31148 31149const MINIMUM_PARTIAL_LINKER_VERSION = '14.0.0'; 31150/** 31151 * Compile a Pipe declaration defined by the `R3PipeMetadata`. 31152 */ 31153 31154function compileDeclarePipeFromMetadata(meta) { 31155 const definitionMap = createPipeDefinitionMap(meta); 31156 const expression = importExpr(Identifiers.declarePipe).callFn([definitionMap.toLiteralMap()]); 31157 const type = createPipeType(meta); 31158 return { 31159 expression, 31160 type, 31161 statements: [] 31162 }; 31163} 31164/** 31165 * Gathers the declaration fields for a Pipe into a `DefinitionMap`. 31166 */ 31167 31168 31169function createPipeDefinitionMap(meta) { 31170 const definitionMap = new DefinitionMap(); 31171 definitionMap.set('minVersion', literal(MINIMUM_PARTIAL_LINKER_VERSION)); 31172 definitionMap.set('version', literal('14.2.12')); 31173 definitionMap.set('ngImport', importExpr(Identifiers.core)); // e.g. `type: MyPipe` 31174 31175 definitionMap.set('type', meta.internalType); 31176 31177 if (meta.isStandalone) { 31178 definitionMap.set('isStandalone', literal(meta.isStandalone)); 31179 } // e.g. `name: "myPipe"` 31180 31181 31182 definitionMap.set('name', literal(meta.pipeName)); 31183 31184 if (meta.pure === false) { 31185 // e.g. `pure: false` 31186 definitionMap.set('pure', literal(meta.pure)); 31187 } 31188 31189 return definitionMap; 31190} 31191/** 31192 * @license 31193 * Copyright Google LLC All Rights Reserved. 31194 * 31195 * Use of this source code is governed by an MIT-style license that can be 31196 * found in the LICENSE file at https://angular.io/license 31197 */ 31198// This file only reexports content of the `src` folder. Keep it that way. 31199// This function call has a global side effects and publishes the compiler into global namespace for 31200// the late binding of the Compiler to the @angular/core for jit compilation. 31201 31202 31203publishFacade(_global); 31204/** 31205 * @license 31206 * Copyright Google LLC All Rights Reserved. 31207 * 31208 * Use of this source code is governed by an MIT-style license that can be 31209 * found in the LICENSE file at https://angular.io/license 31210 */ 31211// This file only reexports content of the `src` folder. Keep it that way. 31212 31213/** 31214 * @license 31215 * Copyright Google LLC All Rights Reserved. 31216 * 31217 * Use of this source code is governed by an MIT-style license that can be 31218 * found in the LICENSE file at https://angular.io/license 31219 */ 31220 31221/** 31222 * @license 31223 * Copyright Google LLC All Rights Reserved. 31224 * 31225 * Use of this source code is governed by an MIT-style license that can be 31226 * found in the LICENSE file at https://angular.io/license 31227 */ 31228 31229 31230 31231/***/ }), 31232 31233/***/ 6344: 31234/*!**********************************************************!*\ 31235 !*** ./node_modules/@angular/localize/fesm2020/init.mjs ***! 31236 \**********************************************************/ 31237/***/ ((__unused_webpack___webpack_module__, __webpack_exports__, __webpack_require__) => { 31238 31239__webpack_require__.r(__webpack_exports__); 31240/* harmony export */ __webpack_require__.d(__webpack_exports__, { 31241/* harmony export */ "$localize": () => (/* reexport safe */ _angular_localize__WEBPACK_IMPORTED_MODULE_0__["ɵ$localize"]) 31242/* harmony export */ }); 31243/* harmony import */ var _angular_localize__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! @angular/localize */ 9321); 31244/** 31245 * @license Angular v14.2.12 31246 * (c) 2010-2022 Google LLC. https://angular.io/ 31247 * License: MIT 31248 */ 31249 31250 31251/** 31252 * @license 31253 * Copyright Google LLC All Rights Reserved. 31254 * 31255 * Use of this source code is governed by an MIT-style license that can be 31256 * found in the LICENSE file at https://angular.io/license 31257 */ 31258// Attach $localize to the global context, as a side-effect of this module. 31259 31260_angular_localize__WEBPACK_IMPORTED_MODULE_0__["ɵ_global"].$localize = _angular_localize__WEBPACK_IMPORTED_MODULE_0__["ɵ$localize"]; 31261 31262/***/ }), 31263 31264/***/ 9321: 31265/*!**************************************************************!*\ 31266 !*** ./node_modules/@angular/localize/fesm2020/localize.mjs ***! 31267 \**************************************************************/ 31268/***/ ((__unused_webpack___webpack_module__, __webpack_exports__, __webpack_require__) => { 31269 31270__webpack_require__.r(__webpack_exports__); 31271/* harmony export */ __webpack_require__.d(__webpack_exports__, { 31272/* harmony export */ "clearTranslations": () => (/* binding */ clearTranslations), 31273/* harmony export */ "loadTranslations": () => (/* binding */ loadTranslations), 31274/* harmony export */ "ɵ$localize": () => (/* binding */ $localize$1), 31275/* harmony export */ "ɵMissingTranslationError": () => (/* binding */ MissingTranslationError), 31276/* harmony export */ "ɵ_global": () => (/* binding */ _global), 31277/* harmony export */ "ɵcomputeMsgId": () => (/* reexport safe */ _angular_compiler__WEBPACK_IMPORTED_MODULE_0__.computeMsgId), 31278/* harmony export */ "ɵfindEndOfBlock": () =>
31278 (/* binding */ findEndOfBlock), 31279/* harmony export */ "ɵisMissingTranslationError": () => (/* binding */ isMissingTranslationError), 31280/* harmony export */ "ɵmakeParsedTranslation": () => (/* binding */ makeParsedTranslation), 31281/* harmony export */ "ɵmakeTemplateObject": () => (/* binding */ makeTemplateObject), 31282/* harmony export */ "ɵparseMessage": () => (/* binding */ parseMessage), 31283/* harmony export */ "ɵparseMetadata": () => (/* binding */ parseMetadata), 31284/* harmony export */ "ɵparseTranslation": () => (/* binding */ parseTranslation), 31285/* harmony export */ "ɵsplitBlock": () => (/* binding */ splitBlock), 31286/* harmony export */ "ɵtranslate": () => (/* binding */ translate$1) 31287/* harmony export */ }); 31288/* harmony import */ var _angular_compiler__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! @angular/compiler */ 8781); 31289/** 31290 * @license Angular v14.2.12 31291 * (c) 2010-2022 Google LLC. https://angular.io/ 31292 * License: MIT 31293 */ 31294 31295 31296/** 31297 * @license 31298 * Copyright Google LLC All Rights Reserved. 31299 * 31300 * Use of this source code is governed by an MIT-style license that can be 31301 * found in the LICENSE file at https://angular.io/license 31302 */ 31303 31304/** 31305 * The character used to mark the start and end of a "block" in a `$localize` tagged string. 31306 * A block can indicate metadata about the message or specify a name of a placeholder for a 31307 * substitution expressions. 31308 * 31309 * For example: 31310 * 31311 * ```ts 31312 * $localize`Hello, ${title}:title:!`; 31313 * $localize`:meaning|description@@id:source message text`; 31314 * ``` 31315 */ 31316 31317const BLOCK_MARKER$1 = ':'; 31318/** 31319 * The marker used to separate a message's "meaning" from its "description" in a metadata block. 31320 * 31321 * For example: 31322 * 31323 * ```ts 31324 * $localize `:correct|Indicates that the user got the answer correct: Right!`; 31325 * $localize `:movement|Button label for moving to the right: Right!`; 31326 * ``` 31327 */ 31328 31329const MEANING_SEPARATOR = '|'; 31330/** 31331 * The marker used to separate a message's custom "id" from its "description" in a metadata block. 31332 * 31333 * For example: 31334 * 31335 * ```ts 31336 * $localize `:A welcome message on the home page@@myApp-homepage-welcome: Welcome!`; 31337 * ``` 31338 */ 31339 31340const ID_SEPARATOR = '@@'; 31341/** 31342 * The marker used to separate legacy message ids from the rest of a metadata block. 31343 * 31344 * For example: 31345 * 31346 * ```ts 31347 * $localize `:@@custom-idâ2df64767cd895a8fabe3e18b94b5b6b6f9e2e3f0: Welcome!`; 31348 * ``` 31349 * 31350 * Note that this character is the "symbol for the unit separator" (â) not the "unit separator 31351 * character" itself, since that has no visual representation. See https://graphemica.com/%E2%90%9F. 31352 * 31353 * Here is some background for the original "unit separator character": 31354 * https://stackoverflow.com/questions/8695118/whats-the-file-group-record-unit-separator-control-characters-and-its-usage 31355 */ 31356 31357const LEGACY_ID_INDICATOR = '\u241F'; 31358/** 31359 * @license 31360 * Copyright Google LLC All Rights Reserved. 31361 * 31362 * Use of this source code is governed by an MIT-style license that can be 31363 * found in the LICENSE file at https://angular.io/license 31364 */ 31365 31366/** 31367 * Parse a `$localize` tagged string into a structure that can be used for translation or 31368 * extraction. 31369 * 31370 * See `ParsedMessage` for an example. 31371 */ 31372 31373function parseMessage(messageParts, expressions, location, messagePartLocations, expressionLocations = []) { 31374 const substitutions = {}; 31375 const substitutionLocations = {}; 31376 const associatedMessageIds = {}; 31377 const metadata = parseMetadata(messageParts[0], messageParts.raw[0]); 31378 const cleanedMessageParts = [metadata.text]; 31379 const placeholderNames = []; 31380 let messageString = metadata.text; 31381 31382 for (let i = 1; i < messageParts.length; i++) { 31383 const { 31384 messagePart, 31385 placeholderName = computePlaceholderName(i), 31386 associatedMessageId 31387 } = parsePlaceholder(messageParts[i], messageParts.raw[i]); 31388 messageString += `{$${placeholderName}}${messagePart}`; 31389 31390 if (expressions !== undefined) { 31391 substitutions[placeholderName] = expressions[i - 1]; 31392 substitutionLocations[placeholderName] = expressionLocations[i - 1]; 31393 } 31394 31395 placeholderNames.push(placeholderName); 31396 31397 if (associatedMessageId !== undefined) { 31398 associatedMessageIds[placeholderName] = associatedMessageId; 31399 } 31400 31401 cleanedMessageParts.push(messagePart); 31402 } 31403 31404 const messageId = metadata.customId || (0,_angular_compiler__WEBPACK_IMPORTED_MODULE_0__.computeMsgId)(messageString, metadata.meaning || ''); 31405 const legacyIds = metadata.legacyIds ? metadata.legacyIds.filter(id => id !== messageId) : []; 31406 return { 31407 id: messageId, 31408 legacyIds, 31409 substitutions, 31410 substitutionLocations, 31411 text: messageString, 31412 customId: metadata.customId, 31413 meaning: metadata.meaning || '', 31414 description: metadata.description || '', 31415 messageParts: cleanedMessageParts, 31416 messagePartLocations, 31417 placeholderNames, 31418 associatedMessageIds, 31419 location 31420 }; 31421} 31422/**
31423 * Parse the given message part (`cooked` + `raw`) to extract the message metadata from the text. 31424 * 31425 * If the message part has a metadata block this function will extract the `meaning`, 31426 * `description`, `customId` and `legacyId` (if provided) from the block. These metadata properties 31427 * are serialized in the string delimited by `|`, `@@` and `â` respectively. 31428 * 31429 * (Note that `â` is the `LEGACY_ID_INDICATOR` - see `constants.ts`.) 31430 * 31431 * For example: 31432 * 31433 * ```ts 31434 * `:meaning|description@@custom-id:` 31435 * `:meaning|@@custom-id:` 31436 * `:meaning|description:` 31437 * `:description@@custom-id:` 31438 * `:meaning|:` 31439 * `:description:` 31440 * `:@@custom-id:` 31441 * `:meaning|description@@custom-idâlegacy-id-1âlegacy-id-2:` 31442 * ``` 31443 * 31444 * @param cooked The cooked version of the message part to parse. 31445 * @param raw The raw version of the message part to parse. 31446 * @returns A object containing any metadata that was parsed from the message part. 31447 */ 31448 31449 31450function parseMetadata(cooked, raw) { 31451 const { 31452 text: messageString, 31453 block 31454 } = splitBlock(cooked, raw); 31455 31456 if (block === undefined) { 31457 return { 31458 text: messageString 31459 }; 31460 } else { 31461 const [meaningDescAndId, ...legacyIds] = block.split(LEGACY_ID_INDICATOR); 31462 const [meaningAndDesc, customId] = meaningDescAndId.split(ID_SEPARATOR, 2); 31463 let [meaning, description] = meaningAndDesc.split(MEANING_SEPARATOR, 2); 31464 31465 if (description === undefined) { 31466 description = meaning; 31467 meaning = undefined; 31468 } 31469 31470 if (description === '') { 31471 description = undefined; 31472 } 31473 31474 return { 31475 text: messageString, 31476 meaning, 31477 description, 31478 customId, 31479 legacyIds 31480 }; 31481 } 31482} 31483/** 31484 * Parse the given message part (`cooked` + `raw`) to extract any placeholder metadata from the 31485 * text. 31486 * 31487 * If the message part has a metadata block this function will extract the `placeholderName` and 31488 * `associatedMessageId` (if provided) from the block. 31489 * 31490 * These metadata properties are serialized in the string delimited by `@@`. 31491 * 31492 * For example: 31493 * 31494 * ```ts 31495 * `:placeholder-name@@associated-id:` 31496 * ``` 31497 * 31498 * @param cooked The cooked version of the message part to parse. 31499 * @param raw The raw version of the message part to parse. 31500 * @returns A object containing the metadata (`placeholderName` and `associatedMessageId`) of the 31501 * preceding placeholder, along with the static text that follows. 31502 */ 31503 31504 31505function parsePlaceholder(cooked, raw) { 31506 const { 31507 text: messagePart, 31508 block 31509 } = splitBlock(cooked, raw); 31510 31511 if (block === undefined) { 31512 return { 31513 messagePart 31514 }; 31515 } else { 31516 const [placeholderName, associatedMessageId] = block.split(ID_SEPARATOR); 31517 return { 31518 messagePart, 31519 placeholderName, 31520 associatedMessageId 31521 }; 31522 } 31523} 31524/** 31525 * Split a message part (`cooked` + `raw`) into an optional delimited "block" off the front and the 31526 * rest of the text of the message part. 31527 * 31528 * Blocks appear at the start of message parts. They are delimited by a colon `:` character at the 31529 * start and end of the block. 31530 * 31531 * If the block is in the first message part then it will be metadata about the whole message: 31532 * meaning, description, id. Otherwise it will be metadata about the immediately preceding 31533 * substitution: placeholder name. 31534 * 31535 * Since blocks are optional, it is possible that the content of a message block actually starts 31536 * with a block marker. In this case the marker must be escaped `\:`. 31537 * 31538 * @param cooked The cooked version of the message part to parse. 31539 * @param raw The raw version of the message part to parse. 31540 * @returns An object containing the `text` of the message part and the text of the `block`, if it 31541 * exists. 31542 * @throws an error if the `block` is unterminated 31543 */ 31544 31545 31546function splitBlock(cooked, raw) { 31547 if (raw.charAt(0) !== BLOCK_MARKER$1) { 31548 return { 31549 text: cooked 31550 }; 31551 } else { 31552 const endOfBlock = findEndOfBlock(cooked, raw); 31553 return { 31554 block: cooked.substring(1, endOfBlock), 31555 text: cooked.substring(endOfBlock + 1) 31556 }; 31557 } 31558} 31559 31560function computePlaceholderName(index) { 31561 return index === 1 ? 'PH' : `PH_${index - 1}`; 31562} 31563/** 31564 * Find the end of a "marked block" indicated by the first non-e
31564scaped colon. 31565 * 31566 * @param cooked The cooked string (where escaped chars have been processed) 31567 * @param raw The raw string (where escape sequences are still in place) 31568 * 31569 * @returns the index of the end of block marker 31570 * @throws an error if the block is unterminated 31571 */ 31572 31573 31574function findEndOfBlock(cooked, raw) { 31575 for (let cookedIndex = 1, rawIndex = 1; cookedIndex < cooked.length; cookedIndex++, rawIndex++) { 31576 if (raw[rawIndex] === '\\') { 31577 rawIndex++; 31578 } else if (cooked[cookedIndex] === BLOCK_MARKER$1) { 31579 return cookedIndex; 31580 } 31581 } 31582 31583 throw new Error(`Unterminated $localize metadata block in "${raw}".`); 31584} 31585/** 31586 * @license 31587 * Copyright Google LLC All Rights Reserved. 31588 * 31589 * Use of this source code is governed by an MIT-style license that can be 31590 * found in the LICENSE file at https://angular.io/license 31591 */ 31592 31593 31594class MissingTranslationError extends Error { 31595 constructor(parsedMessage) { 31596 super(`No translation found for ${describeMessage(parsedMessage)}.`); 31597 this.parsedMessage = parsedMessage; 31598 this.type = 'MissingTranslationError'; 31599 } 31600 31601} 31602 31603function isMissingTranslationError(e) { 31604 return e.type === 'MissingTranslationError'; 31605} 31606/** 31607 * Translate the text of the `$localize` tagged-string (i.e. `messageParts` and 31608 * `substitutions`) using the given `translations`. 31609 * 31610 * The tagged-string is parsed to extract its `messageId` which is used to find an appropriate 31611 * `ParsedTranslation`. If this doesn't match and there are legacy ids then try matching a 31612 * translation using those. 31613 * 31614 * If one is found then it is used to translate the message into a new set of `messageParts` and 31615 * `substitutions`. 31616 * The translation may reorder (or remove) substitutions as appropriate. 31617 * 31618 * If there is no translation with a matching message id then an error is thrown. 31619 * If a translation contains a placeholder that is not found in the message being translated then an 31620 * error is thrown. 31621 */ 31622 31623 31624function translate$1(translations, messageParts, substitutions) { 31625 const message = parseMessage(messageParts, substitutions); // Look up the translation using the messageId, and then the legacyId if available. 31626 31627 let translation = translations[message.id]; // If the messageId did not match a translation, try matching the legacy ids instead 31628 31629 if (message.legacyIds !== undefined) { 31630 for (let i = 0; i < message.legacyIds.length && translation === undefined; i++) { 31631 translation = translations[message.legacyIds[i]]; 31632 } 31633 } 31634 31635 if (translation === undefined) { 31636 throw new MissingTranslationError(message); 31637 } 31638 31639 return [translation.messageParts, translation.placeholderNames.map(placeholder => { 31640 if (message.substitutions.hasOwnProperty(placeholder)) { 31641 return message.substitutions[placeholder]; 31642 } else { 31643 throw new Error(`There is a placeholder name mismatch with the translation provided for the message ${describeMessage(message)}.\n` + `The translation contains a placeholder with name ${placeholder}, which does not exist in the message.`); 31644 } 31645 })]; 31646} 31647/** 31648 * Parse the `messageParts` and `placeholderNames` out of a target `message`. 31649 * 31650 * Used by `loadTranslations()` to convert target message strings into a structure that is more 31651 * appropriate for doing translation. 31652 * 31653 * @param message the message to be parsed. 31654 */ 31655 31656 31657function parseTranslation(messageString) { 31658 const parts = messageString.split(/{\$([^}]*)}/); 31659 const messageParts = [parts[0]]; 31660 const placeholderNames = []; 31661 31662 for (let i = 1; i < parts.length - 1; i += 2) { 31663 placeholderNames.push(parts[i]); 31664 messageParts.push(`${parts[i + 1]}`); 31665 } 31666 31667 const rawMessageParts = messageParts.map(part => part.charAt(0) === BLOCK_MARKER$1 ? '\\' + part : part); 31668 return { 31669 text: messageString,
31670 messageParts: makeTemplateObject(messageParts, rawMessageParts), 31671 placeholderNames 31672 }; 31673} 31674/** 31675 * Create a `ParsedTranslation` from a set of `messageParts` and `placeholderNames`. 31676 * 31677 * @param messageParts The message parts to appear in the ParsedTranslation. 31678 * @param placeholderNames The names of the placeholders to intersperse between the `messageParts`. 31679 */ 31680 31681 31682function makeParsedTranslation(messageParts, placeholderNames = []) { 31683 let messageString = messageParts[0]; 31684 31685 for (let i = 0; i < placeholderNames.length; i++) { 31686 messageString += `{$${placeholderNames[i]}}${messageParts[i + 1]}`; 31687 } 31688 31689 return { 31690 text: messageString, 31691 messageParts: makeTemplateObject(messageParts, messageParts), 31692 placeholderNames 31693 }; 31694} 31695/** 31696 * Create the specialized array that is passed to tagged-string tag functions. 31697 * 31698 * @param cooked The message parts with their escape codes processed. 31699 * @param raw The message parts with their escaped codes as-is. 31700 */ 31701 31702 31703function makeTemplateObject(cooked, raw) { 31704 Object.defineProperty(cooked, 'raw', { 31705 value: raw 31706 }); 31707 return cooked; 31708} 31709 31710function describeMessage(message) { 31711 const meaningString = message.meaning && ` - "${message.meaning}"`; 31712 const legacy = message.legacyIds && message.legacyIds.length > 0 ? ` [${message.legacyIds.map(l => `"${l}"`).join(', ')}]` : ''; 31713 return `"${message.id}"${legacy} ("${message.text}"${meaningString})`; 31714} 31715/** 31716 * @license 31717 * Copyright Google LLC All Rights Reserved. 31718 * 31719 * Use of this source code is governed by an MIT-style license that can be 31720 * found in the LICENSE file at https://angular.io/license 31721 */ 31722 31723/** 31724 * Load translations for use by `$localize`, if doing runtime translation. 31725 * 31726 * If the `$localize` tagged strings are not going to be replaced at compiled time, it is possible 31727 * to load a set of translations that will be applied to the `$localize` tagged strings at runtime, 31728 * in the browser. 31729 * 31730 * Loading a new translation will overwrite a previous translation if it has the same `MessageId`. 31731 * 31732 * Note that `$localize` messages are only processed once, when the tagged string is first 31733 * encountered, and does not provide dynamic language changing without refreshing the browser. 31734 * Loading new translations later in the application life-cycle will not change the translated text 31735 * of messages that have already been translated. 31736 * 31737 * The message IDs and translations are in the same format as that rendered to "simple JSON" 31738 * translation files when extracting messages. In particular, placeholders in messages are rendered 31739 * using the `{$PLACEHOLDER_NAME}` syntax. For example the message from the following template: 31740 * 31741 * ```html 31742 * <div i18n>pre<span>inner-pre<b>bold</b>inner-post</span>post</div> 31743 * ``` 31744 * 31745 * would have the following form in the `translations` map: 31746 * 31747 * ```ts 31748 * { 31749 * "2932901491976224757": 31750 * "pre{$START_TAG_SPAN}inner-pre{$START_BOLD_TEXT}bold{$CLOSE_BOLD_TEXT}inner-post{$CLOSE_TAG_SPAN}post" 31751 * } 31752 * ``` 31753 * 31754 * @param translations A map from message ID to translated message. 31755 * 31756 * These messages are processed and added to a lookup based on their `MessageId`. 31757 * 31758 * @see `clearTranslations()` for removing translations loaded using this function. 31759 * @see `$localize` for tagging messages as needing to be translated. 31760 * @publicApi 31761 */ 31762 31763 31764function loadTranslations(translations) { 31765 // Ensure the translate function exists 31766 if (!$localize.translate) { 31767 $localize.translate = translate; 31768 } 31769 31770 if (!$localize.TRANSLATIONS) { 31771 $localize.TRANSLATIONS = {}; 31772 } 31773 31774 Object.keys(translations).forEach(key => { 31775 $localize.TRANSLATIONS[key] = parseTranslation(translations[key]); 31776 }); 31777} 31778/** 31779 * Remove all translations for `$localize`, if doing runtime translation. 31780 * 31781 * All translations that had been loading into memory using `loadTranslations()` will be removed. 31782 * 31783 * @see `loadTranslations()` for loading translations at runtime. 31784 * @see `$localize` for tagging messages as needing to be translated. 31785 * 31786 * @publicApi 31787 */ 31788 31789 31790function clearTranslations() { 31791 $localize.translate = undefined; 31792 $localize.TRANSLATIONS = {}; 31793} 31794/** 31795 * Translate the text of the given message, using the loaded translations. 31796 * 31797 * This function may reorder (or remove) substitutions as indicated in the matching translation. 31798 */ 31799 31800 31801function translate(messageParts, substitutions) { 31802 try { 31803 return translate$1($localize.TRANSLATIONS, messageParts, substitutions); 31804 } catch (e) { 31805 console.warn(e.message); 31806 return [messageParts, substitutions]; 31807 } 31808} 31809/** 31810 * @license 31811 * Copyright Google LLC All Rights Reserved. 31812 * 31813 * Use of this source code is governed by an MIT-style license that can be 31814 * found in the LICENSE file at https://angular.io/license 31815 */ 31816// Always use __globalThis if available, which is the spec-defined global variable across all 31817// environments, then fallback to __global first, because in Node tests both __global and 31818// __window may be defined and _global should be __global in that case. Note: Typeof/Instanceof 31819// checks are considered side-effects in Terser. We explicitly mark this as side-effect free: 31820// https://github.com/terser/terser/issues/250. 31821 31822 31823const _global = /* @__PURE__ */(() => typeof globalThis !== 'undefined' && globalThis || typeof global !== 'undefined' && global || typeof window !== 'undefined' && window || typeof self !== 'undefined' && typeof WorkerGlobalScope !== 'undefined' && self instanceof WorkerGlobalScope && self)(); 31824/** 31825 * @license 31826 * Copyright Google LLC All Rights Reserved. 31827 * 31828 * Use of this source code is governed by an MIT-style license that can be 31829 * found in the LICENSE file at https://angular.io/license 31830 */ 31831 31832/** 31833 * Tag a template literal string for localization. 31834 * 31835 * For example: 31836 * 31837 * ```ts 31838 * $localize `some string to localize` 31839 * ``` 31840 * 31841 * **Providing meaning, description and id** 31842 * 31843 * You can optionally specify one or more of `meaning`, `description` and `id` for a localized 31844 * string by pre-pending it with a colon delimited block of the form: 31845 * 31846 * ```ts 31847 * $localize`:meaning|description@@id:source message text`; 31848 * 31849 * $localize`:meaning|:source message text`; 31850 * $localize`:description:source message text`; 31851 * $localize`:@@id:source message text`; 31852 * ``` 31853 * 31854 * This format is the same as that used for `i18n` markers in Angular templates. See the 31855 * [Angular i18n guide](guide/i18n-common-prepare#mark-text-in-component-template). 31856 * 31857 * **Naming placeholders** 31858 * 31859 * If the template literal string contains expressions, then the expressions will be automatically 31860 * associated with placeholder names for you. 31861 * 31862 * For example: 31863 * 31864 * ```ts 31865 * $localize `Hi ${name}! There are ${items.length} items.`; 31866 * ``` 31867 * 31868 * will generate a message-source of `Hi {$PH}! There are {$PH_1} items`. 31869 * 31870 * The recommended practice is to name the placeholder associated with each expression though. 31871 * 31872 * Do this by providing the placeholder name wrapped in `:` characters directly after the 31873 * expression. These placeholder names are stripped out of the rendered localized string. 31874 * 31875 * For example, to name the `items.length` expression placeholder `itemCount` you write: 31876 * 31877 * ```ts 31878 * $localize `There are ${items.length}:itemCount: items`; 31879 * ``` 31880 * 31881 * **Escaping colon markers** 31882 * 31883 * If you need to use a `:` character directly at the start of a tagged string that has no 31884 * metadata block, or directly after a substitution expression that has no name you must escape 31885 * the `:` by preceding it with a backslash: 31886 * 31887 * For example: 31888 * 31889 * ```ts 31890 * // message has a metadata block so no need to escape colon 31891 * $localize `:some description::this message starts with a colon (:)`; 31892 * // no metadata block so the colon must be escaped 31893 * $localize `\:this message starts with a colon (:)`; 31894 * ``` 31895 * 31896 * ```ts 31897 * // named substitution so no need to escape colon 31898 * $localize `${label}:label:: ${}` 31899 * // anonymous substitution so colon must be escaped 31900 * $localize `${label}\: ${}` 31901 * ``` 31902 * 31903 * **Processing localized strings:** 31904 * 31905 * There are three scenarios: 31906 * 31907 * * **compile-time inlining**: the `$localize` tag is transformed at compile time by a 31908 * transpiler, removing the tag and replacing the template literal string with a translated 31909 * literal string from a collection of translations provided to the transpilation tool. 31910 * 31911 * * **run-time evaluation**: the `$localize` tag is a run-time function that replaces and 31912 * reorders the parts (static strings and expressions) of the template literal string with strings 31913 * from a collection of translations loaded at run-time. 31914 * 31915 * * **pass-through evaluation**: the `$localize` tag is a run-time function that simply evaluates 31916 * the original template literal string without applying any translations to the parts. This 31917 * version is used during development or where there is no need to translate the localized 31918 * template literals. 31919 * 31920 * @param messageParts a collection of the static parts of the template string. 31921 * @param expressions a collection of the values of each placeholder in the template string. 31922 * @returns the translated string, with the `messageParts` and `expressions` interleaved together. 31923 * 31924 * @globalApi 31925 * @publicApi 31926 */ 31927 31928 31929const $localize$1 = function (messageParts, ...expressions) { 31930 if ($localize$1.translate) { 31931 // Don't use array expansion here to avoid the compiler adding `__read()` helper unnecessarily. 31932 const translation = $localize$1.translate(messageParts, expressions); 31933 messageParts = translation[0]; 31934 expressions = translation[1]; 31935 } 31936 31937 let message = stripBlock(messageParts[0], messageParts.raw[0]); 31938 31939 for (let i = 1; i < messageParts.length; i++) { 31940 message += expressions[i - 1] + stripBlock(messageParts[i], messageParts.raw[i]); 31941 } 31942 31943 return message; 31944}; 31945 31946const BLOCK_MARKER = ':'; 31947/** 31948 * Strip a delimited "block" from the start of the `messagePart`, if it is found. 31949 * 31950 * If a marker character (:) actually appears in the content at the start of a tagged string or 31951 * after a substitution expression, where a block has not been provided the character must be 31952 * escaped with a backslash, `\:`. This function checks for this by looking at the `raw` 31953 * messagePart, which should still contain the backslash. 31954 * 31955 * @param messagePart The cooked message part to process. 31956 * @param rawMessagePart The raw message part to check. 31957 * @returns the message part with the placeholder name stripped, if found. 31958 * @throws an error if the block is unterminated 31959 */ 31960 31961function stripBlock(messagePart, rawMessagePart) { 31962 return rawMessagePart.charAt(0) === BLOCK_MARKER ? messagePart.substring(findEndOfBlock(messagePart, rawMessagePart) + 1) : messagePart; 31963} 31964/** 31965 * @license 31966 * Copyright Google LLC All Rights Reserved. 31967 * 31968 * Use of this source code is governed by an MIT-style license that can be 31969 * found in the LICENSE file at https://angular.io/license 31970 */ 31971 31972/** 31973 * @license 31974 * Copyright Google LLC All Rights Reserved. 31975 * 31976 * Use of this source code is governed by an MIT-style license that can be 31977 * found in the LICENSE file at https://angular.io/license 31978 */ 31979 31980/** 31981 * @license 31982 * Copyright Google LLC All Rights Reserved. 31983 * 31984 * Use of this source code is governed by an MIT-style license that can be 31985 * found in the LICENSE file at https://angular.io/license 31986 */ 31987 31988/** 31989 * @license 31990 * Copyright Google LLC All Rights Reserved. 31991 * 31992 * Use of this source code is governed by an MIT-style license that can be 31993 * found in the LICENSE file at https://angular.io/license 31994 */ 31995 31996 31997 31998 31999/***/ }) 32000 32001}, 32002/******/ __webpack_require__ => { // webpackRuntimeModules 32003/******/ var __webpack_exec__ = (moduleId) => (__webpack_require__(__webpack_require__.s = moduleId)) 32004/******/ var __webpack_exports__ = (__webpack_exec__(7435)); 32005/******/ } 32006]); 32007//# sourceMappingURL=polyfills.js.map
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.