Skip to content

Commit 440cce9

Browse files
committed
fix: answer DOM probes on NativeScriptDocument instead of throwing
* Angular discovers some optional configuration by reading the DOM. The CSP_NONCE default factory, for example, evaluates `DOCUMENT.body.querySelector('[ngCspNonce]')`. `NativeScriptDocument.body` was a hollow object, so the optional chaining in those probes did not help and they failed with `body?.querySelector is not a function`. Signal forms reach this on the first `[formField]` binding, which crashed every signal-form dialog at construction. * `querySelector`, `querySelectorAll`, `getElementById`, `getElementsByTagName` and `getElementsByClassName` now answer "nothing found" on the document and on `body`/`head`. `createElement` still throws, since constructing real nodes is a caller bug rather than a probe. * CSP_NONCE is also provided as `null`, as there is no CSP in a NativeScript runtime. It has to be a root provider: the root injector resolves `providedIn: 'root'` tokens itself before consulting the platform injector, so providing it in COMMON_PROVIDERS would have had no effect.
1 parent 780e666 commit 440cce9

2 files changed

Lines changed: 34 additions & 1 deletion

File tree

packages/angular/src/lib/nativescript.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { ViewportScroller, XhrFactory, ɵNullViewportScroller as NullViewportScroller } from '@angular/common';
2-
import { ApplicationModule, ErrorHandler, Inject, NgModule, NO_ERRORS_SCHEMA, Optional, Provider, RendererFactory2, SkipSelf, StaticProvider, ɵINJECTOR_SCOPE as INJECTOR_SCOPE } from '@angular/core';
2+
import { ApplicationModule, CSP_NONCE, ErrorHandler, Inject, NgModule, NO_ERRORS_SCHEMA, Optional, Provider, RendererFactory2, SkipSelf, StaticProvider, ɵINJECTOR_SCOPE as INJECTOR_SCOPE } from '@angular/core';
33
import { Color, Device, View } from '@nativescript/core';
44
import { AppHostView } from './app-host-view';
55
import { NativescriptXhrFactory } from './nativescript-xhr-factory';
@@ -39,6 +39,10 @@ export const NATIVESCRIPT_MODULE_STATIC_PROVIDERS: StaticProvider[] = [
3939
{ provide: NAMESPACE_FILTERS, useClass: PlatformNamespaceFilter, deps: [DEVICE], multi: true },
4040
{ provide: DEVICE, useValue: Device },
4141
{ provide: XhrFactory, useClass: NativescriptXhrFactory, deps: [] },
42+
// No CSP in a NativeScript runtime. Providing it also stops the token's default
43+
// factory reading `DOCUMENT.body.querySelector()`. Must stay root-scoped: the root
44+
// injector resolves `providedIn: 'root'` tokens before consulting the platform.
45+
{ provide: CSP_NONCE, useValue: null },
4246
];
4347
export const NATIVESCRIPT_MODULE_PROVIDERS: Provider[] = [{ provide: ViewportScroller, useClass: NullViewportScroller }];
4448

packages/angular/src/lib/platform-nativescript.ts

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,12 +37,41 @@ export class NativeScriptSanitizer extends Sanitizer {
3737
// };
3838
// }
3939

40+
/**
41+
* Angular probes the DOM to discover optional configuration it may have been handed
42+
* out of band - a `ngCspNonce` attribute on `<body>`, a transfer state `<script>` in
43+
* the document. None of that can exist here, so the lookups answer "nothing found".
44+
* Leaving the methods undefined instead surfaces as a `TypeError` thrown from deep
45+
* inside framework code, since `document.body` is present and merely hollow.
46+
*/
47+
const NO_DOM_QUERIES = {
48+
querySelector: () => null,
49+
querySelectorAll: () => [],
50+
getElementById: () => null,
51+
getElementsByTagName: () => [],
52+
getElementsByClassName: () => [],
53+
getAttribute: () => null,
54+
hasAttribute: () => false,
55+
};
56+
4057
export class NativeScriptDocument {
4158
// Required by the AnimationDriver
4259
public body: any = {
4360
isOverride: true,
61+
...NO_DOM_QUERIES,
4462
};
4563

64+
public head: any = {
65+
...NO_DOM_QUERIES,
66+
};
67+
68+
public querySelector = NO_DOM_QUERIES.querySelector;
69+
public querySelectorAll = NO_DOM_QUERIES.querySelectorAll;
70+
public getElementById = NO_DOM_QUERIES.getElementById;
71+
public getElementsByTagName = NO_DOM_QUERIES.getElementsByTagName;
72+
public getElementsByClassName = NO_DOM_QUERIES.getElementsByClassName;
73+
74+
// Deliberately still throws: constructing real nodes is a caller bug, not a probe.
4675
createElement(tag: string) {
4776
throw new Error('NativeScriptDocument is not DOM Document. There is no createElement() method.');
4877
}

0 commit comments

Comments
 (0)