UNPKG

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