UNPKG

46.2 kBJavaScriptView Raw
1/**
2 * @license Angular v15.0.1
3 * (c) 2010-2022 Google LLC. https://angular.io/
4 * License: MIT
5 */
6
7import { ɵsetRootDomAdapter, DOCUMENT, XhrFactory, PlatformLocation, ɵgetDOM, ɵPLATFORM_SERVER_ID, ViewportScroller, ɵNullViewportScroller } from '@angular/common';
8import * as i0 from '@angular/core';
9import { Injectable, Inject, InjectionToken, inject, EnvironmentInjector, Optional, ViewEncapsulation, RendererStyleFlags2, APP_ID, NgModule, Injector, PLATFORM_ID, PLATFORM_INITIALIZER, ɵALLOW_MULTIPLE_PLATFORMS, RendererFactory2, NgZone, Testability, ɵTESTABILITY, ɵsetDocument, createPlatformFactory, platformCore, Renderer2, ApplicationRef, ɵisPromise, importProvidersFrom, ɵinternalCreateApplication, Version } from '@angular/core';
10import * as i1 from '@angular/platform-browser';
11import { ɵBrowserDomAdapter, ɵflattenStyles, ɵNAMESPACE_URIS, ɵshimContentAttribute, ɵshimHostAttribute, ɵSharedStylesHost, ɵTRANSITION_ID, TransferState, ɵescapeHtml, EVENT_MANAGER_PLUGINS, BrowserModule } from '@angular/platform-browser';
12import * as domino from 'domino';
13import { ɵAnimationEngine } from '@angular/animations/browser';
14import { ɵHttpInterceptorHandler, HttpBackend, HttpHandler, HttpClientModule } from '@angular/common/http';
15import { ɵplatformCoreDynamic } from '@angular/platform-browser-dynamic';
16import { ɵAnimationRendererFactory, NoopAnimationsModule } from '@angular/platform-browser/animations';
17import { Observable, Subject } from 'rxjs';
18import * as xhr2 from 'xhr2';
19import * as url from 'url';
20import { DomElementSchemaRegistry } from '@angular/compiler';
21import { first } from 'rxjs/operators';
22
23/**
24 * @license
25 * Copyright Google LLC All Rights Reserved.
26 *
27 * Use of this source code is governed by an MIT-style license that can be
28 * found in the LICENSE file at https://angular.io/license
29 */
30function setDomTypes() {
31 // Make all Domino types available in the global env.
32 Object.assign(global, domino.impl);
33 global['KeyboardEvent'] = domino.impl.Event;
34}
35/**
36 * Parses a document string to a Document object.
37 */
38function parseDocument(html, url = '/') {
39 let window = domino.createWindow(html, url);
40 let doc = window.document;
41 return doc;
42}
43/**
44 * Serializes a document to string.
45 */
46function serializeDocument(doc) {
47 return doc.serialize();
48}
49/**
50 * DOM Adapter for the server platform based on https://github.com/fgnass/domino.
51 */
52class DominoAdapter extends ɵBrowserDomAdapter {
53 constructor() {
54 super(...arguments);
55 this.supportsDOMEvents = false;
56 }
57 static makeCurrent() {
58 setDomTypes();
59 ɵsetRootDomAdapter(new DominoAdapter());
60 }
61 createHtmlDocument() {
62 return parseDocument('<html><head><title>fakeTitle</title></head><body></body></html>');
63 }
64 getDefaultDocument() {
65 if (!DominoAdapter.defaultDoc) {
66 DominoAdapter.defaultDoc = domino.createDocument();
67 }
68 return DominoAdapter.defaultDoc;
69 }
70 isElementNode(node) {
71 return node ? node.nodeType === DominoAdapter.defaultDoc.ELEMENT_NODE : false;
72 }
73 isShadowRoot(node) {
74 return node.shadowRoot == node;
75 }
76 /** @deprecated No longer being used in Ivy code. To be removed in version 14. */
77 getGlobalEventTarget(doc, target) {
78 if (target === 'window') {
79 return doc.defaultView;
80 }
81 if (target === 'document') {
82 return doc;
83 }
84 if (target === 'body') {
85 return doc.body;
86 }
87 return null;
88 }
89 getBaseHref(doc) {
90 // TODO(alxhub): Need relative path logic from BrowserDomAdapter here?
91 return doc.documentElement.querySelector('base')?.getAttribute('href') || '';
92 }
93 dispatchEvent(el, evt) {
94 el.dispatchEvent(evt);
95 // Dispatch the event to the window also.
96 const doc = el.ownerDocument || el;
97 const win = doc.defaultView;
98 if (win) {
99 win.dispatchEvent(evt);
100 }
101 }
102 getUserAgent() {
103 return 'Fake user agent';
104 }
105 getCookie(name) {
106 throw new Error('getCookie has not been implemented');
107 }
108}
109
110/**
111 * @license
112 * Copyright Google LLC All Rights Reserved.
113 *
114 * Use of this source code is governed by an MIT-style license that can be
115 * found in the LICENSE file at https://angular.io/license
116 */
117/**
118 * Representation of the current platform state.
119 *
120 * @publicApi
121 */
122class PlatformState {
123 constructor(_doc) {
124 this._doc = _doc;
125 }
126 /**
127 * Renders the current state of the platform to string.
128 */
129 renderToString() {
130 return serializeDocument(this._doc);
131 }
132 /**
133 * Returns the current DOM state.
134 */
135 getDocument() {
136 return this._doc;
137 }
138}
139PlatformState.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.0.1", ngImport: i0, type: PlatformState, deps: [{ token: DOCUMENT }], target: i0.ɵɵFactoryTarget.Injectable });
140PlatformState.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "15.0.1", ngImport: i0, type: PlatformState });
141i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.0.1", ngImport: i0, type: PlatformState, decorators: [{
142 type: Injectable
143 }], ctorParameters: function () { return [{ type: undefined, decorators: [{
144 type: Inject,
145 args: [DOCUMENT]
146 }] }]; } });
147
148/**
149 * @license
150 * Copyright Google LLC All Rights Reserved.
151 *
152 * Use of this source code is governed by an MIT-style license that can be
153 * found in the LICENSE file at https://angular.io/license
154 */
155/**
156 * The DI token for setting the initial config for the platform.
157 *
158 * @publicApi
159 */
160const INITIAL_CONFIG = new InjectionToken('Server.INITIAL_CONFIG');
161/**
162 * A function that will be executed when calling `renderApplication`, `renderModuleFactory` or
163 * `renderModule` just before current platform state is rendered to string.
164 *
165 * @publicApi
166 */
167const BEFORE_APP_SERIALIZED = new InjectionToken('Server.RENDER_MODULE_HOOK');
168
169/**
170 * @license
171 * Copyright Google LLC All Rights Reserved.
172 *
173 * Use of this source code is governed by an MIT-style license that can be
174 * found in the LICENSE file at https://angular.io/license
175 */
176// @see https://www.w3.org/Protocols/HTTP/1.1/draft-ietf-http-v11-spec-01#URI-syntax
177const isAbsoluteUrl = /^[a-zA-Z\-\+.]+:\/\//;
178class ServerXhr {
179 build() {
180 return new xhr2.XMLHttpRequest();
181 }
182}
183ServerXhr.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.0.1", ngImport: i0, type: ServerXhr, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
184ServerXhr.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "15.0.1", ngImport: i0, type: ServerXhr });
185i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.0.1", ngImport: i0, type: ServerXhr, decorators: [{
186 type: Injectable
187 }] });
188class ZoneMacroTaskWrapper {
189 wrap(request) {
190 return new Observable((observer) => {
191 let task = null;
192 let scheduled = false;
193 let sub = null;
194 let savedResult = null;
195 let savedError = null;
196 const scheduleTask = (_task) => {
197 task = _task;
198 scheduled = true;
199 const delegate = this.delegate(request);
200 sub = delegate.subscribe(res => savedResult = res, err => {
201 if (!scheduled) {
202 throw new Error('An http observable was completed twice. This shouldn\'t happen, please file a bug.');
203 }
204 savedError = err;
205 scheduled = false;
206 task.invoke();
207 }, () => {
208 if (!scheduled) {
209 throw new Error('An http observable was completed twice. This shouldn\'t happen, please file a bug.');
210 }
211 scheduled = false;
212 task.invoke();
213 });
214 };
215 const cancelTask = (_task) => {
216 if (!scheduled) {
217 return;
218 }
219 scheduled = false;
220 if (sub) {
221 sub.unsubscribe();
222 sub = null;
223 }
224 };
225 const onComplete = () => {
226 if (savedError !== null) {
227 observer.error(savedError);
228 }
229 else {
230 observer.next(savedResult);
231 observer.complete();
232 }
233 };
234 // MockBackend for Http is synchronous, which means that if scheduleTask is by
235 // scheduleMacroTask, the request will hit MockBackend and the response will be
236 // sent, causing task.invoke() to be called.
237 const _task = Zone.current.scheduleMacroTask('ZoneMacroTaskWrapper.subscribe', onComplete, {}, () => null, cancelTask);
238 scheduleTask(_task);
239 return () => {
240 if (scheduled && task) {
241 task.zone.cancelTask(task);
242 scheduled = false;
243 }
244 if (sub) {
245 sub.unsubscribe();
246 sub = null;
247 }
248 };
249 });
250 }
251}
252class ZoneClientBackend extends ZoneMacroTaskWrapper {
253 constructor(backend, platformLocation, config) {
254 super();
255 this.backend = backend;
256 this.platformLocation = platformLocation;
257 this.config = config;
258 }
259 handle(request) {
260 const { href, protocol, hostname, port } = this.platformLocation;
261 if (this.config.useAbsoluteUrl && !isAbsoluteUrl.test(request.url) &&
262 isAbsoluteUrl.test(href)) {
263 const baseHref = this.platformLocation.getBaseHrefFromDOM() || href;
264 const urlPrefix = `${protocol}//${hostname}` + (port ? `:${port}` : '');
265 const baseUrl = new URL(baseHref, urlPrefix);
266 const url = new URL(request.url, baseUrl);
267 return this.wrap(request.clone({ url: url.toString() }));
268 }
269 return this.wrap(request);
270 }
271 delegate(request) {
272 return this.backend.handle(request);
273 }
274}
275function zoneWrappedInterceptorHandler(platformLocation, config) {
276 return new ZoneClientBackend(new ɵHttpInterceptorHandler(inject(HttpBackend), inject(EnvironmentInjector)), platformLocation, config);
277}
278const SERVER_HTTP_PROVIDERS = [
279 { provide: XhrFactory, useClass: ServerXhr }, {
280 provide: HttpHandler,
281 useFactory: zoneWrappedInterceptorHandler,
282 deps: [PlatformLocation, INITIAL_CONFIG]
283 }
284];
285
286/**
287 * @license
288 * Copyright Google LLC All Rights Reserved.
289 *
290 * Use of this source code is governed by an MIT-style license that can be
291 * found in the LICENSE file at https://angular.io/license
292 */
293function parseUrl(urlStr) {
294 const parsedUrl = url.parse(urlStr);
295 return {
296 hostname: parsedUrl.hostname || '',
297 protocol: parsedUrl.protocol || '',
298 port: parsedUrl.port || '',
299 pathname: parsedUrl.pathname || '',
300 search: parsedUrl.search || '',
301 hash: parsedUrl.hash || '',
302 };
303}
304/**
305 * Server-side implementation of URL state. Implements `pathname`, `search`, and `hash`
306 * but not the state stack.
307 */
308class ServerPlatformLocation {
309 constructor(_doc, _config) {
310 this._doc = _doc;
311 this.href = '/';
312 this.hostname = '/';
313 this.protocol = '/';
314 this.port = '/';
315 this.pathname = '/';
316 this.search = '';
317 this.hash = '';
318 this._hashUpdate = new Subject();
319 const config = _config;
320 if (!config) {
321 return;
322 }
323 if (config.url) {
324 const url = parseUrl(config.url);
325 this.protocol = url.protocol;
326 this.hostname = url.hostname;
327 this.port = url.port;
328 this.pathname = url.pathname;
329 this.search = url.search;
330 this.hash = url.hash;
331 this.href = _doc.location.href;
332 }
333 if (config.useAbsoluteUrl) {
334 if (!config.baseUrl) {
335 throw new Error(`"PlatformConfig.baseUrl" must be set if "useAbsoluteUrl" is true`);
336 }
337 const url = parseUrl(config.baseUrl);
338 this.protocol = url.protocol;
339 this.hostname = url.hostname;
340 this.port = url.port;
341 }
342 }
343 getBaseHrefFromDOM() {
344 return ɵgetDOM().getBaseHref(this._doc);
345 }
346 onPopState(fn) {
347 // No-op: a state stack is not implemented, so
348 // no events will ever come.
349 return () => { };
350 }
351 onHashChange(fn) {
352 const subscription = this._hashUpdate.subscribe(fn);
353 return () => subscription.unsubscribe();
354 }
355 get url() {
356 return `${this.pathname}${this.search}${this.hash}`;
357 }
358 setHash(value, oldUrl) {
359 if (this.hash === value) {
360 // Don't fire events if the hash has not changed.
361 return;
362 }
363 this.hash = value;
364 const newUrl = this.url;
365 scheduleMicroTask(() => this._hashUpdate.next({ type: 'hashchange', state: null, oldUrl, newUrl }));
366 }
367 replaceState(state, title, newUrl) {
368 const oldUrl = this.url;
369 const parsedUrl = parseUrl(newUrl);
370 this.pathname = parsedUrl.pathname;
371 this.search = parsedUrl.search;
372 this.setHash(parsedUrl.hash, oldUrl);
373 }
374 pushState(state, title, newUrl) {
375 this.replaceState(state, title, newUrl);
376 }
377 forward() {
378 throw new Error('Not implemented');
379 }
380 back() {
381 throw new Error('Not implemented');
382 }
383 // History API isn't available on server, therefore return undefined
384 getState() {
385 return undefined;
386 }
387}
388ServerPlatformLocation.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.0.1", ngImport: i0, type: ServerPlatformLocation, deps: [{ token: DOCUMENT }, { token: INITIAL_CONFIG, optional: true }], target: i0.ɵɵFactoryTarget.Injectable });
389ServerPlatformLocation.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "15.0.1", ngImport: i0, type: ServerPlatformLocation });
390i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.0.1", ngImport: i0, type: ServerPlatformLocation, decorators: [{
391 type: Injectable
392 }], ctorParameters: function () { return [{ type: undefined, decorators: [{
393 type: Inject,
394 args: [DOCUMENT]
395 }] }, { type: undefined, decorators: [{
396 type: Optional
397 }, {
398 type: Inject,
399 args: [INITIAL_CONFIG]
400 }] }]; } });
401function scheduleMicroTask(fn) {
402 Zone.current.scheduleMicroTask('scheduleMicrotask', fn);
403}
404
405/**
406 * @license
407 * Copyright Google LLC All Rights Reserved.
408 *
409 * Use of this source code is governed by an MIT-style license that can be
410 * found in the LICENSE file at https://angular.io/license
411 */
412class ServerEventManagerPlugin /* extends EventManagerPlugin which is private */ {
413 constructor(doc) {
414 this.doc = doc;
415 }
416 // Handle all events on the server.
417 supports(eventName) {
418 return true;
419 }
420 addEventListener(element, eventName, handler) {
421 return ɵgetDOM().onAndCancel(element, eventName, handler);
422 }
423 /** @deprecated No longer being used in Ivy code. To be removed in version 14. */
424 addGlobalEventListener(element, eventName, handler) {
425 const target = ɵgetDOM().getGlobalEventTarget(this.doc, element);
426 if (!target) {
427 throw new Error(`Unsupported event target ${target} for event ${eventName}`);
428 }
429 return this.addEventListener(target, eventName, handler);
430 }
431}
432ServerEventManagerPlugin.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.0.1", ngImport: i0, type: ServerEventManagerPlugin /* extends EventManagerPlugin which is private */, deps: [{ token: DOCUMENT }], target: i0.ɵɵFactoryTarget.Injectable });
433ServerEventManagerPlugin.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "15.0.1", ngImport: i0, type: ServerEventManagerPlugin /* extends EventManagerPlugin which is private */ });
434i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.0.1", ngImport: i0, type: ServerEventManagerPlugin /* extends EventManagerPlugin which is private */, decorators: [{
435 type: Injectable
436 }], ctorParameters: function () { return [{ type: undefined, decorators: [{
437 type: Inject,
438 args: [DOCUMENT]
439 }] }]; } });
440
441/**
442 * @license
443 * Copyright Google LLC All Rights Reserved.
444 *
445 * Use of this source code is governed by an MIT-style license that can be
446 * found in the LICENSE file at https://angular.io/license
447 */
448const EMPTY_ARRAY = [];
449const DEFAULT_SCHEMA = new DomElementSchemaRegistry();
450class ServerRendererFactory2 {
451 constructor(eventManager, ngZone, document, sharedStylesHost) {
452 this.eventManager = eventManager;
453 this.ngZone = ngZone;
454 this.document = document;
455 this.sharedStylesHost = sharedStylesHost;
456 this.rendererByCompId = new Map();
457 this.schema = DEFAULT_SCHEMA;
458 this.defaultRenderer = new DefaultServerRenderer2(eventManager, document, ngZone, this.schema);
459 }
460 createRenderer(element, type) {
461 if (!element || !type) {
462 return this.defaultRenderer;
463 }
464 switch (type.encapsulation) {
465 case ViewEncapsulation.Emulated: {
466 let renderer = this.rendererByCompId.get(type.id);
467 if (!renderer) {
468 renderer = new EmulatedEncapsulationServerRenderer2(this.eventManager, this.document, this.ngZone, this.sharedStylesHost, this.schema, type);
469 this.rendererByCompId.set(type.id, renderer);
470 }
471 renderer.applyToHost(element);
472 return renderer;
473 }
474 default: {
475 if (!this.rendererByCompId.has(type.id)) {
476 const styles = ɵflattenStyles(type.id, type.styles, []);
477 this.sharedStylesHost.addStyles(styles);
478 this.rendererByCompId.set(type.id, this.defaultRenderer);
479 }
480 return this.defaultRenderer;
481 }
482 }
483 }
484 begin() { }
485 end() { }
486}
487ServerRendererFactory2.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.0.1", ngImport: i0, type: ServerRendererFactory2, deps: [{ token: i1.EventManager }, { token: i0.NgZone }, { token: DOCUMENT }, { token: i1.ɵSharedStylesHost }], target: i0.ɵɵFactoryTarget.Injectable });
488ServerRendererFactory2.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "15.0.1", ngImport: i0, type: ServerRendererFactory2 });
489i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.0.1", ngImport: i0, type: ServerRendererFactory2, decorators: [{
490 type: Injectable
491 }], ctorParameters: function () { return [{ type: i1.EventManager }, { type: i0.NgZone }, { type: undefined, decorators: [{
492 type: Inject,
493 args: [DOCUMENT]
494 }] }, { type: i1.ɵSharedStylesHost }]; } });
495class DefaultServerRenderer2 {
496 constructor(eventManager, document, ngZone, schema) {
497 this.eventManager = eventManager;
498 this.document = document;
499 this.ngZone = ngZone;
500 this.schema = schema;
501 this.data = Object.create(null);
502 this.destroyNode = null;
503 }
504 destroy() { }
505 createElement(name, namespace) {
506 if (namespace) {
507 const doc = this.document || ɵgetDOM().getDefaultDocument();
508 return doc.createElementNS(ɵNAMESPACE_URIS[namespace], name);
509 }
510 return ɵgetDOM().createElement(name, this.document);
511 }
512 createComment(value) {
513 return ɵgetDOM().getDefaultDocument().createComment(value);
514 }
515 createText(value) {
516 const doc = ɵgetDOM().getDefaultDocument();
517 return doc.createTextNode(value);
518 }
519 appendChild(parent, newChild) {
520 const targetParent = isTemplateNode(parent) ? parent.content : parent;
521 targetParent.appendChild(newChild);
522 }
523 insertBefore(parent, newChild, refChild) {
524 if (parent) {
525 const targetParent = isTemplateNode(parent) ? parent.content : parent;
526 targetParent.insertBefore(newChild, refChild);
527 }
528 }
529 removeChild(parent, oldChild) {
530 if (parent) {
531 parent.removeChild(oldChild);
532 }
533 }
534 selectRootElement(selectorOrNode, preserveContent) {
535 const el = typeof selectorOrNode === 'string' ? this.document.querySelector(selectorOrNode) :
536 selectorOrNode;
537 if (!el) {
538 throw new Error(`The selector "${selectorOrNode}" did not match any elements`);
539 }
540 if (!preserveContent) {
541 while (el.firstChild) {
542 el.removeChild(el.firstChild);
543 }
544 }
545 return el;
546 }
547 parentNode(node) {
548 return node.parentNode;
549 }
550 nextSibling(node) {
551 return node.nextSibling;
552 }
553 setAttribute(el, name, value, namespace) {
554 if (namespace) {
555 el.setAttributeNS(ɵNAMESPACE_URIS[namespace], namespace + ':' + name, value);
556 }
557 else {
558 el.setAttribute(name, value);
559 }
560 }
561 removeAttribute(el, name, namespace) {
562 if (namespace) {
563 el.removeAttributeNS(ɵNAMESPACE_URIS[namespace], name);
564 }
565 else {
566 el.removeAttribute(name);
567 }
568 }
569 addClass(el, name) {
570 el.classList.add(name);
571 }
572 removeClass(el, name) {
573 el.classList.remove(name);
574 }
575 setStyle(el, style, value, flags) {
576 style = style.replace(/([a-z])([A-Z])/g, '$1-$2').toLowerCase();
577 value = value == null ? '' : `${value}`.trim();
578 const styleMap = _readStyleAttribute(el);
579 if (flags & RendererStyleFlags2.Important) {
580 value += ' !important';
581 }
582 styleMap[style] = value;
583 _writeStyleAttribute(el, styleMap);
584 }
585 removeStyle(el, style, flags) {
586 // IE requires '' instead of null
587 // see https://github.com/angular/angular/issues/7916
588 this.setStyle(el, style, '', flags);
589 }
590 // The value was validated already as a property binding, against the property name.
591 // To know this value is safe to use as an attribute, the security context of the
592 // attribute with the given name is checked against that security context of the
593 // property.
594 _isSafeToReflectProperty(tagName, propertyName) {
595 return this.schema.securityContext(tagName, propertyName, true) ===
596 this.schema.securityContext(tagName, propertyName, false);
597 }
598 setProperty(el, name, value) {
599 checkNoSyntheticProp(name, 'property');
600 if (name === 'innerText') {
601 // Domino does not support innerText. Just map it to textContent.
602 el.textContent = value;
603 }
604 el[name] = value;
605 // Mirror property values for known HTML element properties in the attributes.
606 // Skip `innerhtml` which is conservatively marked as an attribute for security
607 // purposes but is not actually an attribute.
608 const tagName = el.tagName.toLowerCase();
609 if (value != null && (typeof value === 'number' || typeof value == 'string') &&
610 name.toLowerCase() !== 'innerhtml' && this.schema.hasElement(tagName, EMPTY_ARRAY) &&
611 this.schema.hasProperty(tagName, name, EMPTY_ARRAY) &&
612 this._isSafeToReflectProperty(tagName, name)) {
613 this.setAttribute(el, name, value.toString());
614 }
615 }
616 setValue(node, value) {
617 node.textContent = value;
618 }
619 listen(target, eventName, callback) {
620 checkNoSyntheticProp(eventName, 'listener');
621 if (typeof target === 'string') {
622 return this.eventManager.addGlobalEventListener(target, eventName, this.decoratePreventDefault(callback));
623 }
624 return this.eventManager.addEventListener(target, eventName, this.decoratePreventDefault(callback));
625 }
626 decoratePreventDefault(eventHandler) {
627 return (event) => {
628 // Ivy uses `Function` as a special token that allows us to unwrap the function
629 // so that it can be invoked programmatically by `DebugNode.triggerEventHandler`.
630 if (event === Function) {
631 return eventHandler;
632 }
633 // Run the event handler inside the ngZone because event handlers are not patched
634 // by Zone on the server. This is required only for tests.
635 const allowDefaultBehavior = this.ngZone.runGuarded(() => eventHandler(event));
636 if (allowDefaultBehavior === false) {
637 event.preventDefault();
638 event.returnValue = false;
639 }
640 return undefined;
641 };
642 }
643}
644const AT_CHARCODE = '@'.charCodeAt(0);
645function checkNoSyntheticProp(name, nameKind) {
646 if (name.charCodeAt(0) === AT_CHARCODE) {
647 throw new Error(`Unexpected synthetic ${nameKind} ${name} found. Please make sure that:
648 - Either \`BrowserAnimationsModule\` or \`NoopAnimationsModule\` are imported in your application.
649 - There is corresponding configuration for the animation named \`${name}\` defined in the \`animations\` field of the \`@Component\` decorator (see https://angular.io/api/core/Component#animations).`);
650 }
651}
652function isTemplateNode(node) {
653 return node.tagName === 'TEMPLATE' && node.content !== undefined;
654}
655class EmulatedEncapsulationServerRenderer2 extends DefaultServerRenderer2 {
656 constructor(eventManager, document, ngZone, sharedStylesHost, schema, component) {
657 super(eventManager, document, ngZone, schema);
658 this.component = component;
659 // Add a 's' prefix to style attributes to indicate server.
660 const componentId = 's' + component.id;
661 const styles = ɵflattenStyles(componentId, component.styles, []);
662 sharedStylesHost.addStyles(styles);
663 this.contentAttr = ɵshimContentAttribute(componentId);
664 this.hostAttr = ɵshimHostAttribute(componentId);
665 }
666 applyToHost(element) {
667 super.setAttribute(element, this.hostAttr, '');
668 }
669 createElement(parent, name) {
670 const el = super.createElement(parent, name);
671 super.setAttribute(el, this.contentAttr, '');
672 return el;
673 }
674}
675function _readStyleAttribute(element) {
676 const styleMap = {};
677 const styleAttribute = element.getAttribute('style');
678 if (styleAttribute) {
679 const styleList = styleAttribute.split(/;+/g);
680 for (let i = 0; i < styleList.length; i++) {
681 const style = styleList[i].trim();
682 if (style.length > 0) {
683 const colonIndex = style.indexOf(':');
684 if (colonIndex === -1) {
685 throw new Error(`Invalid CSS style: ${style}`);
686 }
687 const name = style.slice(0, colonIndex).trim();
688 styleMap[name] = style.slice(colonIndex + 1).trim();
689 }
690 }
691 }
692 return styleMap;
693}
694function _writeStyleAttribute(element, styleMap) {
695 // We have to construct the `style` attribute ourselves, instead of going through
696 // `element.style.setProperty` like the other renderers, because `setProperty` won't
697 // write newer CSS properties that Domino doesn't know about like `clip-path`.
698 let styleAttrValue = '';
699 for (const key in styleMap) {
700 const newValue = styleMap[key];
701 if (newValue != null && newValue !== '') {
702 styleAttrValue += key + ':' + newValue + ';';
703 }
704 }
705 if (styleAttrValue) {
706 element.setAttribute('style', styleAttrValue);
707 }
708 else {
709 element.removeAttribute('style');
710 }
711}
712
713/**
714 * @license
715 * Copyright Google LLC All Rights Reserved.
716 *
717 * Use of this source code is governed by an MIT-style license that can be
718 * found in the LICENSE file at https://angular.io/license
719 */
720class ServerStylesHost extends ɵSharedStylesHost {
721 constructor(doc, transitionId) {
722 super();
723 this.doc = doc;
724 this.transitionId = transitionId;
725 this.head = null;
726 this._styleNodes = new Set();
727 this.head = doc.getElementsByTagName('head')[0];
728 }
729 _addStyle(style) {
730 let adapter = ɵgetDOM();
731 const el = adapter.createElement('style');
732 el.textContent = style;
733 if (!!this.transitionId) {
734 el.setAttribute('ng-transition', this.transitionId);
735 }
736 this.head.appendChild(el);
737 this._styleNodes.add(el);
738 }
739 onStylesAdded(additions) {
740 additions.forEach(style => this._addStyle(style));
741 }
742 ngOnDestroy() {
743 this._styleNodes.forEach(styleNode => styleNode.remove());
744 }
745}
746ServerStylesHost.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.0.1", ngImport: i0, type: ServerStylesHost, deps: [{ token: DOCUMENT }, { token: ɵTRANSITION_ID, optional: true }], target: i0.ɵɵFactoryTarget.Injectable });
747ServerStylesHost.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "15.0.1", ngImport: i0, type: ServerStylesHost });
748i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.0.1", ngImport: i0, type: ServerStylesHost, decorators: [{
749 type: Injectable
750 }], ctorParameters: function () { return [{ type: undefined, decorators: [{
751 type: Inject,
752 args: [DOCUMENT]
753 }] }, { type: undefined, decorators: [{
754 type: Optional
755 }, {
756 type: Inject,
757 args: [ɵTRANSITION_ID]
758 }] }]; } });
759
760/**
761 * @license
762 * Copyright Google LLC All Rights Reserved.
763 *
764 * Use of this source code is governed by an MIT-style license that can be
765 * found in the LICENSE file at https://angular.io/license
766 */
767const TRANSFER_STATE_SERIALIZATION_PROVIDERS = [{
768 provide: BEFORE_APP_SERIALIZED,
769 useFactory: serializeTransferStateFactory,
770 deps: [DOCUMENT, APP_ID, TransferState],
771 multi: true,
772 }];
773function serializeTransferStateFactory(doc, appId, transferStore) {
774 return () => {
775 // The `.toJSON` here causes the `onSerialize` callbacks to be called.
776 // These callbacks can be used to provide the value for a given key.
777 const content = transferStore.toJson();
778 if (transferStore.isEmpty) {
779 // The state is empty, nothing to transfer,
780 // avoid creating an extra `<script>` tag in this case.
781 return;
782 }
783 const script = doc.createElement('script');
784 script.id = appId + '-state';
785 script.setAttribute('type', 'application/json');
786 script.textContent = ɵescapeHtml(content);
787 doc.body.appendChild(script);
788 };
789}
790/**
791 * NgModule to install on the server side while using the `TransferState` to transfer state from
792 * server to client.
793 *
794 * Note: this module is not needed if the `renderApplication` function is used.
795 * The `renderApplication` makes all providers from this module available in the application.
796 *
797 * @publicApi
798 * @deprecated no longer needed, you can inject the `TransferState` in an app without providing
799 * this module.
800 */
801class ServerTransferStateModule {
802}
803ServerTransferStateModule.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.0.1", ngImport: i0, type: ServerTransferStateModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule });
804ServerTransferStateModule.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "15.0.1", ngImport: i0, type: ServerTransferStateModule });
805ServerTransferStateModule.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "15.0.1", ngImport: i0, type: ServerTransferStateModule });
806i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.0.1", ngImport: i0, type: ServerTransferStateModule, decorators: [{
807 type: NgModule,
808 args: [{}]
809 }] });
810
811/**
812 * @license
813 * Copyright Google LLC All Rights Reserved.
814 *
815 * Use of this source code is governed by an MIT-style license that can be
816 * found in the LICENSE file at https://angular.io/license
817 */
818const INTERNAL_SERVER_PLATFORM_PROVIDERS = [
819 { provide: DOCUMENT, useFactory: _document, deps: [Injector] },
820 { provide: PLATFORM_ID, useValue: ɵPLATFORM_SERVER_ID },
821 { provide: PLATFORM_INITIALIZER, useFactory: initDominoAdapter, multi: true, deps: [Injector] }, {
822 provide: PlatformLocation,
823 useClass: ServerPlatformLocation,
824 deps: [DOCUMENT, [Optional, INITIAL_CONFIG]]
825 },
826 { provide: PlatformState, deps: [DOCUMENT] },
827 // Add special provider that allows multiple instances of platformServer* to be created.
828 { provide: ɵALLOW_MULTIPLE_PLATFORMS, useValue: true }
829];
830function initDominoAdapter(injector) {
831 return () => {
832 DominoAdapter.makeCurrent();
833 };
834}
835function instantiateServerRendererFactory(renderer, engine, zone) {
836 return new ɵAnimationRendererFactory(renderer, engine, zone);
837}
838const SERVER_RENDER_PROVIDERS = [
839 ServerRendererFactory2,
840 {
841 provide: RendererFactory2,
842 useFactory: instantiateServerRendererFactory,
843 deps: [ServerRendererFactory2, ɵAnimationEngine, NgZone]
844 },
845 ServerStylesHost,
846 { provide: ɵSharedStylesHost, useExisting: ServerStylesHost },
847 { provide: EVENT_MANAGER_PLUGINS, multi: true, useClass: ServerEventManagerPlugin },
848];
849/**
850 * The ng module for the server.
851 *
852 * @publicApi
853 */
854class ServerModule {
855}
856ServerModule.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.0.1", ngImport: i0, type: ServerModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule });
857ServerModule.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "15.0.1", ngImport: i0, type: ServerModule, imports: [HttpClientModule, NoopAnimationsModule], exports: [BrowserModule] });
858ServerModule.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "15.0.1", ngImport: i0, type: ServerModule, providers: [
859 TRANSFER_STATE_SERIALIZATION_PROVIDERS,
860 SERVER_RENDER_PROVIDERS,
861 SERVER_HTTP_PROVIDERS,
862 { provide: Testability, useValue: null },
863 { provide: ɵTESTABILITY, useValue: null },
864 { provide: ViewportScroller, useClass: ɵNullViewportScroller },
865 ], imports: [HttpClientModule, NoopAnimationsModule, BrowserModule] });
866i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.0.1", ngImport: i0, type: ServerModule, decorators: [{
867 type: NgModule,
868 args: [{
869 exports: [BrowserModule],
870 imports: [HttpClientModule, NoopAnimationsModule],
871 providers: [
872 TRANSFER_STATE_SERIALIZATION_PROVIDERS,
873 SERVER_RENDER_PROVIDERS,
874 SERVER_HTTP_PROVIDERS,
875 { provide: Testability, useValue: null },
876 { provide: ɵTESTABILITY, useValue: null },
877 { provide: ViewportScroller, useClass: ɵNullViewportScroller },
878 ],
879 }]
880 }] });
881function _document(injector) {
882 const config = injector.get(INITIAL_CONFIG, null);
883 let document;
884 if (config && config.document) {
885 document = typeof config.document === 'string' ? parseDocument(config.document, config.url) :
886 config.document;
887 }
888 else {
889 document = ɵgetDOM().createHtmlDocument();
890 }
891 // Tell ivy about the global document
892 ɵsetDocument(document);
893 return document;
894}
895/**
896 * @publicApi
897 */
898const platformServer = createPlatformFactory(platformCore, 'server', INTERNAL_SERVER_PLATFORM_PROVIDERS);
899/**
900 * The server platform that supports the runtime compiler.
901 *
902 * @publicApi
903 */
904const platformDynamicServer = createPlatformFactory(ɵplatformCoreDynamic, 'serverDynamic', INTERNAL_SERVER_PLATFORM_PROVIDERS);
905
906/**
907 * @license
908 * Copyright Google LLC All Rights Reserved.
909 *
910 * Use of this source code is governed by an MIT-style license that can be
911 * found in the LICENSE file at https://angular.io/license
912 */
913function _getPlatform(platformFactory, options) {
914 const extraProviders = options.platformProviders ?? [];
915 return platformFactory([
916 { provide: INITIAL_CONFIG, useValue: { document: options.document, url: options.url } },
917 extraProviders
918 ]);
919}
920/**
921 * Adds the `ng-server-context` attribute to host elements of all bootstrapped components
922 * within a given application.
923 */
924function appendServerContextInfo(serverContext, applicationRef) {
925 applicationRef.components.forEach(componentRef => {
926 const renderer = componentRef.injector.get(Renderer2);
927 const element = componentRef.location.nativeElement;
928 if (element) {
929 renderer.setAttribute(element, 'ng-server-context', serverContext);
930 }
931 });
932}
933function _render(platform, bootstrapPromise) {
934 return bootstrapPromise.then((moduleOrApplicationRef) => {
935 const environmentInjector = moduleOrApplicationRef.injector;
936 const transitionId = environmentInjector.get(ɵTRANSITION_ID, null);
937 if (!transitionId) {
938 throw new Error(`renderModule[Factory]() requires the use of BrowserModule.withServerTransition() to ensure
939the server-rendered app can be properly bootstrapped into a client app.`);
940 }
941 const applicationRef = moduleOrApplicationRef instanceof ApplicationRef ?
942 moduleOrApplicationRef :
943 environmentInjector.get(ApplicationRef);
944 const serverContext = sanitizeServerContext(environmentInjector.get(SERVER_CONTEXT, DEFAULT_SERVER_CONTEXT));
945 return applicationRef.isStable.pipe((first((isStable) => isStable)))
946 .toPromise()
947 .then(() => {
948 appendServerContextInfo(serverContext, applicationRef);
949 const platformState = platform.injector.get(PlatformState);
950 const asyncPromises = [];
951 // Run any BEFORE_APP_SERIALIZED callbacks just before rendering to string.
952 const callbacks = environmentInjector.get(BEFORE_APP_SERIALIZED, null);
953 if (callbacks) {
954 for (const callback of callbacks) {
955 try {
956 const callbackResult = callback();
957 if (ɵisPromise(callbackResult)) {
958 // TODO: in TS3.7, callbackResult is void.
959 asyncPromises.push(callbackResult);
960 }
961 }
962 catch (e) {
963 // Ignore exceptions.
964 console.warn('Ignoring BEFORE_APP_SERIALIZED Exception: ', e);
965 }
966 }
967 }
968 const complete = () => {
969 const output = platformState.renderToString();
970 platform.destroy();
971 return output;
972 };
973 if (asyncPromises.length === 0) {
974 return complete();
975 }
976 return Promise
977 .all(asyncPromises.map(asyncPromise => {
978 return asyncPromise.catch(e => {
979 console.warn('Ignoring BEFORE_APP_SERIALIZED Exception: ', e);
980 });
981 }))
982 .then(complete);
983 });
984 });
985}
986/**
987 * Specifies the value that should be used if no server context value has been provided.
988 */
989const DEFAULT_SERVER_CONTEXT = 'other';
990/**
991 * An internal token that allows providing extra information about the server context
992 * (e.g. whether SSR or SSG was used). The value is a string and characters other
993 * than [a-zA-Z0-9\-] are removed. See the default value in `DEFAULT_SERVER_CONTEXT` const.
994 */
995const SERVER_CONTEXT = new InjectionToken('SERVER_CONTEXT');
996/**
997 * Sanitizes provided server context:
998 * - removes all characters other than a-z, A-Z, 0-9 and `-`
999 * - returns `other` if nothing is provided or the string is empty after sanitization
1000 */
1001function sanitizeServerContext(serverContext) {
1002 const context = serverContext.replace(/[^a-zA-Z0-9\-]/g, '');
1003 return context.length > 0 ? context : DEFAULT_SERVER_CONTEXT;
1004}
1005/**
1006 * Bootstraps an application using provided NgModule and serializes the page content to string.
1007 *
1008 * @param moduleType A reference to an NgModule that should be used for bootstrap.
1009 * @param options Additional configuration for the render operation:
1010 * - `document` - the document of the page to render, either as an HTML string or
1011 * as a reference to the `document` instance.
1012 * - `url` - the URL for the current render request.
1013 * - `extraProviders` - set of platform level providers for the current render request.
1014 *
1015 * @publicApi
1016 */
1017function renderModule(moduleType, options) {
1018 const { document, url, extraProviders: platformProviders } = options;
1019 const platform = _getPlatform(platformDynamicServer, { document, url, platformProviders });
1020 return _render(platform, platform.bootstrapModule(moduleType));
1021}
1022/**
1023 * Bootstraps an instance of an Angular application and renders it to a string.
1024 *
1025 * Note: the root component passed into this function *must* be a standalone one (should have the
1026 * `standalone: true` flag in the `@Component` decorator config).
1027 *
1028 * ```typescript
1029 * @Component({
1030 * standalone: true,
1031 * template: 'Hello world!'
1032 * })
1033 * class RootComponent {}
1034 *
1035 * const output: string = await renderApplication(RootComponent, {appId: 'server-app'});
1036 * ```
1037 *
1038 * @param rootComponent A reference to a Standalone Component that should be rendered.
1039 * @param options Additional configuration for the render operation:
1040 * - `appId` - a string identifier of this application. The appId is used to prefix all
1041 * server-generated stylings and state keys of the application in TransferState
1042 * use-cases.
1043 * - `document` - the document of the page to render, either as an HTML string or
1044 * as a reference to the `document` instance.
1045 * - `url` - the URL for the current render request.
1046 * - `providers` - set of application level providers for the current render request.
1047 * - `platformProviders` - the platform level providers for the current render request.
1048 *
1049 * @returns A Promise, that returns serialized (to a string) rendered page, once resolved.
1050 *
1051 * @publicApi
1052 * @developerPreview
1053 */
1054function renderApplication(rootComponent, options) {
1055 const { document, url, platformProviders, appId } = options;
1056 const platform = _getPlatform(platformDynamicServer, { document, url, platformProviders });
1057 const appProviders = [
1058 importProvidersFrom(BrowserModule.withServerTransition({ appId })),
1059 importProvidersFrom(ServerModule),
1060 ...TRANSFER_STATE_SERIALIZATION_PROVIDERS,
1061 ...(options.providers ?? []),
1062 ];
1063 return _render(platform, ɵinternalCreateApplication({ rootComponent, appProviders }));
1064}
1065/**
1066 * Bootstraps an application using provided {@link NgModuleFactory} and serializes the page content
1067 * to string.
1068 *
1069 * @param moduleFactory An instance of the {@link NgModuleFactory} that should be used for
1070 * bootstrap.
1071 * @param options Additional configuration for the render operation:
1072 * - `document` - the document of the page to render, either as an HTML string or
1073 * as a reference to the `document` instance.
1074 * - `url` - the URL for the current render request.
1075 * - `extraProviders` - set of platform level providers for the current render request.
1076 *
1077 * @publicApi
1078 *
1079 * @deprecated
1080 * This symbol is no longer necessary as of Angular v13.
1081 * Use {@link renderModule} API instead.
1082 */
1083function renderModuleFactory(moduleFactory, options) {
1084 const { document, url, extraProviders: platformProviders } = options;
1085 const platform = _getPlatform(platformServer, { document, url, platformProviders });
1086 return _render(platform, platform.bootstrapModuleFactory(moduleFactory));
1087}
1088
1089/**
1090 * @license
1091 * Copyright Google LLC All Rights Reserved.
1092 *
1093 * Use of this source code is governed by an MIT-style license that can be
1094 * found in the LICENSE file at https://angular.io/license
1095 */
1096
1097/**
1098 * @license
1099 * Copyright Google LLC All Rights Reserved.
1100 *
1101 * Use of this source code is governed by an MIT-style license that can be
1102 * found in the LICENSE file at https://angular.io/license
1103 */
1104/**
1105 * @publicApi
1106 */
1107const VERSION = new Version('15.0.1');
1108
1109/**
1110 * @license
1111 * Copyright Google LLC All Rights Reserved.
1112 *
1113 * Use of this source code is governed by an MIT-style license that can be
1114 * found in the LICENSE file at https://angular.io/license
1115 */
1116
1117/**
1118 * @license
1119 * Copyright Google LLC All Rights Reserved.
1120 *
1121 * Use of this source code is governed by an MIT-style license that can be
1122 * found in the LICENSE file at https://angular.io/license
1123 */
1124// This file only reexports content of the `src` folder. Keep it that way.
1125
1126/**
1127 * @license
1128 * Copyright Google LLC All Rights Reserved.
1129 *
1130 * Use of this source code is governed by an MIT-style license that can be
1131 * found in the LICENSE file at https://angular.io/license
1132 */
1133
1134/**
1135 * Generated bundle index. Do not edit.
1136 */
1137
1138export { BEFORE_APP_SERIALIZED, INITIAL_CONFIG, PlatformState, ServerModule, ServerTransferStateModule, VERSION, platformDynamicServer, platformServer, renderApplication, renderModule, renderModuleFactory, INTERNAL_SERVER_PLATFORM_PROVIDERS as ɵINTERNAL_SERVER_PLATFORM_PROVIDERS, SERVER_CONTEXT as ɵSERVER_CONTEXT, SERVER_RENDER_PROVIDERS as ɵSERVER_RENDER_PROVIDERS, ServerRendererFactory2 as ɵServerRendererFactory2, setDomTypes as ɵsetDomTypes };
1139//# sourceMappingURL=platform-server.mjs.map