Skip to content

Commit 8fe87e2

Browse files
author
Anatoly Ostrovsky
committed
Type improvements
1 parent 81d8865 commit 8fe87e2

File tree

25 files changed

+210
-223
lines changed

25 files changed

+210
-223
lines changed

@types/core/parse/interface.d.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ export interface CompiledExpressionProps {
4141
* Evaluates the compiled expression.
4242
*/
4343
export type CompiledExpressionFunction = (
44-
context?: Scope,
44+
context?: Scope | typeof Proxy<Scope>,
4545
locals?: object,
4646
assign?: any,
4747
) => any;

@types/core/scope/scope.d.ts

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ export class Scope {
4949
$$listeners: Map<string, Function[]>;
5050
/** @type {Map<string, Array<import('./interface.ts').Listener>>} Watch listeners from other proxies */
5151
foreignListeners: Map<string, Array<import("./interface.ts").Listener>>;
52-
/** @type {Set<ProxyConstructor>} */
52+
/** @type {Set<Proxy<ng.Scope>>} */
5353
foreignProxies: Set<ProxyConstructor>;
5454
/** @type {WeakMap<Object, Array<string>>} */
5555
objectListeners: WeakMap<any, Array<string>>;
@@ -61,8 +61,8 @@ export class Scope {
6161
fn: Function;
6262
}
6363
>;
64-
/** Current proxy being operated on */
65-
$proxy: ProxyConstructor | ng.Scope;
64+
/** @type {Proxy<Scope>} Current proxy being operated on */
65+
$proxy: ProxyConstructor;
6666
/** @type {Scope} The actual proxy */
6767
$handler: Scope;
6868
/** @type {*} Current target being called on */
@@ -96,7 +96,7 @@ export class Scope {
9696
* @param {Object} target - The target object.
9797
* @param {string} property - The name of the property being set.
9898
* @param {*} value - The new value being assigned to the property.
99-
* @param {Proxy} proxy - The proxy intercepting property access
99+
* @param {Proxy<Scope>} proxy - The proxy intercepting property access
100100
* @returns {boolean} - Returns true to indicate success of the operation.
101101
*/
102102
set(
@@ -112,7 +112,7 @@ export class Scope {
112112
*
113113
* @param {Object} target - The target object.
114114
* @param {string|number|symbol} property - The name of the property being accessed.
115-
* @param {Proxy} proxy - The proxy object being invoked
115+
* @param {Proxy<Scope>} proxy - The proxy object being invoked
116116
* @returns {*} - The value of the property or a method if accessing `watch` or `sync`.
117117
*/
118118
get(

@types/namespace.d.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -95,7 +95,10 @@ import { AnimateProvider as TAnimateProvider } from "./animations/animate.js";
9595
import { UrlService as TUrlService } from "./router/url/url-service.js";
9696
import { LocationProvider as TLocationProvider } from "./services/location/location.js";
9797
import { ViewService as TViewService } from "./router/view/view.js";
98-
import { StateDeclaration as TStateDeclaration } from "./router/state/interface.ts";
98+
import {
99+
BuiltStateDeclaration as TBuiltStateDeclaration,
100+
StateDeclaration as TStateDeclaration,
101+
} from "./router/state/interface.ts";
99102
import { StateObject as TStateObject } from "./router/state/state-object.js";
100103
import { StateRegistryProvider as TStateRegistryProvider } from "./router/state/state-registry.js";
101104
declare global {
@@ -188,6 +191,7 @@ declare global {
188191
type NgModelController = TNgModelController;
189192
type Validator = TValidator;
190193
type StateDeclaration = TStateDeclaration;
194+
type BuiltStateDeclaration = TBuiltStateDeclaration;
191195
type StateObject = TStateObject;
192196
}
193197
}

@types/router/state/interface.d.ts

Lines changed: 24 additions & 125 deletions
Original file line numberDiff line numberDiff line change
@@ -385,131 +385,6 @@ export interface StateDeclaration {
385385
* ```
386386
*/
387387
parent?: string | StateDeclaration;
388-
/**
389-
* Resolve - a mechanism to asynchronously fetch data, participating in the Transition lifecycle
390-
*
391-
* The `resolve:` property defines data (or other dependencies) to be fetched asynchronously when the state is being entered.
392-
* After the data is fetched, it may be used in views, transition hooks or other resolves that belong to this state.
393-
* The data may also be used in any views or resolves that belong to nested states.
394-
*
395-
* ### As an array
396-
*
397-
* Each array element should be a [[ResolvableLiteral]] object.
398-
*
399-
* #### Example:
400-
* The `user` resolve injects the current `Transition` and the `UserService` (using its token, which is a string).
401-
* The [[ResolvableLiteral.resolvePolicy]] sets how the resolve is processed.
402-
* The `user` data, fetched asynchronously, can then be used in a view.
403-
* ```js
404-
* var state = {
405-
* name: 'user',
406-
* url: '/user/:userId
407-
* resolve: [
408-
* {
409-
* token: 'user',
410-
* policy: { when: 'EAGER' },
411-
* deps: ['UserService', Transition],
412-
* resolveFn: (userSvc, trans) => userSvc.fetchUser(trans.params().userId) },
413-
* }
414-
* ]
415-
* }
416-
* ```
417-
*
418-
* Note: an Angular 2 style [`useFactory` provider literal](https://angular.io/docs/ts/latest/cookbook/dependency-injection.html#!#provide)
419-
* may also be used. See [[ProviderLike]].
420-
* #### Example:
421-
* ```
422-
* resolve: [
423-
* { provide: 'token', useFactory: (http) => http.get('/'), deps: [ Http ] },
424-
* ]
425-
* ```
426-
*
427-
* ### As an object
428-
*
429-
* The `resolve` property may be an object where:
430-
* - Each key (string) is the name of the dependency.
431-
* - Each value (function) is an injectable function which returns the dependency, or a promise for the dependency.
432-
*
433-
* This style is based on AngularTS injectable functions, but can be used with any UI-Router implementation.
434-
* If your code will be minified, the function should be ["annotated" in the AngularTS manner](https://docs.angularjs.org/guide/di#dependency-annotation).
435-
*
436-
* #### AngularTS Example:
437-
* ```js
438-
* resolve: {
439-
* // If you inject `myStateDependency` into a controller, you'll get "abc"
440-
* myStateDependency: function() {
441-
* return "abc";
442-
* },
443-
* // Dependencies are annotated in "Inline Array Annotation"
444-
* myAsyncData: ['$http', '$transition$' function($http, $transition$) {
445-
* // Return a promise (async) for the data
446-
* return $http.get("/foos/" + $transition$.params().foo);
447-
* }]
448-
* }
449-
* ```
450-
*
451-
* Note: You cannot specify a policy for each Resolvable, nor can you use non-string
452-
* tokens when using the object style `resolve:` block.
453-
*
454-
* ### Lifecycle
455-
*
456-
* Since a resolve function can return a promise, the router will delay entering the state until the promises are ready.
457-
* If any of the promises are rejected, the Transition is aborted with an Error.
458-
*
459-
* By default, resolves for a state are fetched just before that state is entered.
460-
* Note that only states which are being *entered* during the `Transition` have their resolves fetched.
461-
* States that are "retained" do not have their resolves re-fetched.
462-
*
463-
* If you are currently in a parent state `parent` and are transitioning to a child state `parent.child`, the
464-
* previously resolved data for state `parent` can be injected into `parent.child` without delay.
465-
*
466-
* Any resolved data for `parent.child` is retained until `parent.child` is exited, e.g., by transitioning back to the `parent` state.
467-
*
468-
* Because of this scoping and lifecycle, resolves are a great place to fetch your application's primary data.
469-
*
470-
* ### Injecting resolves into other things
471-
*
472-
* During a transition, Resolve data can be injected into:
473-
*
474-
* - Views (the components which fill a `ui-view` tag)
475-
* - Transition Hooks
476-
* - Other resolves (a resolve may depend on asynchronous data from a different resolve)
477-
*
478-
* ### Injecting other things into resolves
479-
*
480-
* Resolve functions usually have dependencies on some other API(s).
481-
* The dependencies are usually declared and injected into the resolve function.
482-
* A common pattern is to inject a custom service such as `UserService`.
483-
* The resolve then delegates to a service method, such as `UserService.list()`;
484-
*
485-
* #### Special injectable tokens
486-
*
487-
* - `UIRouter`: The [[UIRouter]] instance which has references to all the UI-Router services.
488-
* - `Transition`: The current [[Transition]] object; information and API about the current transition, such as
489-
* "to" and "from" State Parameters and transition options.
490-
* - `'$transition$'`: A string alias for the `Transition` injectable
491-
* - `'$state$'`: For `onEnter`/`onExit`/`onRetain`, the state being entered/exited/retained.
492-
* - Other resolve tokens: A resolve can depend on another resolve, either from the same state, or from any parent state.
493-
*
494-
* #### Example:
495-
* ```js
496-
* // Injecting a resolve into another resolve
497-
* resolve: [
498-
* // Define a resolve 'allusers' which delegates to the UserService.list()
499-
* // which returns a promise (async) for all the users
500-
* { provide: 'allusers', useFactory: (UserService) => UserService.list(), deps: [UserService] },
501-
*
502-
* // Define a resolve 'user' which depends on the allusers resolve.
503-
* // This resolve function is not called until 'allusers' is ready.
504-
* { provide: 'user', (allusers, trans) => _.find(allusers, trans.params().userId, deps: ['allusers', Transition] }
505-
* }
506-
* ```
507-
*/
508-
resolve?:
509-
| ResolveTypes[]
510-
| {
511-
[key: string]: Injectable<any>;
512-
};
513388
/**
514389
* Sets the resolve policy defaults for all resolves on this state
515390
*
@@ -928,6 +803,30 @@ export interface StateDeclaration {
928803
*/
929804
reloadOnSearch?: boolean;
930805
}
806+
/**
807+
* Represents a fully built StateObject, after registration in the StateRegistry
808+
* and application of all StateBuilder decorators.
809+
*/
810+
export interface BuiltStateDeclaration extends StateDeclaration {
811+
/** Reference to the original StateDeclaration */
812+
self: StateDeclaration;
813+
/** Array of Resolvables built from the resolve / resolvePolicy */
814+
resolvables: Resolvable[];
815+
/** Full path from root down to this state */
816+
path: BuiltStateDeclaration[];
817+
/** Fast lookup of included states for $state.includes() */
818+
includes: Record<string, boolean>;
819+
/** Closest ancestor state that has a URL (navigable) */
820+
navigable?: BuiltStateDeclaration | null;
821+
/** URL object built from url / parent / root */
822+
url?: any;
823+
/** Computed parameters of this state */
824+
params?: Record<string, any>;
825+
/** Optional parent state */
826+
parent?: BuiltStateDeclaration | null;
827+
/** Optional inherited data */
828+
data?: any;
829+
}
931830
/**
932831
* The return type of a [[StateDeclaration.lazyLoad]] function
933832
*

@types/router/state/state-object.d.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,9 +24,9 @@ export class StateObject implements StateDeclaration {
2424
includes: any;
2525
$$state: () => this;
2626
/**
27-
* @type {ng.StateDeclaration}
27+
* @type {ng.StateDeclaration|ng.BuiltStateDeclaration}
2828
*/
29-
self: ng.StateDeclaration;
29+
self: ng.StateDeclaration | ng.BuiltStateDeclaration;
3030
__stateObjectCache: {
3131
nameGlob: Glob;
3232
};

@types/router/state/state-registry.d.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -112,9 +112,9 @@ export class StateRegistryProvider {
112112
*/
113113
deregister(stateOrName: any): any[];
114114
/**
115-
* @return {ng.StateDeclaration[]}
115+
* @return {ng.BuiltStateDeclaration[]}
116116
*/
117-
getAll(): ng.StateDeclaration[];
117+
getAll(): ng.BuiltStateDeclaration[];
118118
get(stateOrName: any, base: any, ...args: any[]): any;
119119
/**
120120
* Registers a [[BuilderFunction]] for a specific [[StateObject]] property (e.g., `parent`, `url`, or `path`).

@types/router/transition/transition.d.ts

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -77,15 +77,19 @@ export class Transition implements IHookRegistry {
7777
*
7878
* @returns The state declaration object for the Transition's ("from state").
7979
*/
80-
from(): import("../state/interface.ts").StateDeclaration;
80+
from():
81+
| import("../state/interface.ts").StateDeclaration
82+
| import("../state/interface.ts").BuiltStateDeclaration;
8183
/**
8284
* Returns the "to state"
8385
*
8486
* Returns the state that the transition is going *to*.
8587
*
8688
* @returns The state declaration object for the Transition's target state ("to state").
8789
*/
88-
to(): import("../state/interface.ts").StateDeclaration;
90+
to():
91+
| import("../state/interface.ts").StateDeclaration
92+
| import("../state/interface.ts").BuiltStateDeclaration;
8993
/**
9094
* Gets the Target State
9195
*

@types/shared/utils.d.ts

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,22 @@
11
/**
2-
*
32
* @param {any} value
4-
* @returns {value is ng.Scope}
3+
* @returns {value is Proxy<ng.Scope> | ng.Scope}
54
*/
6-
export function isProxy(value: any): value is ng.Scope;
5+
export function isProxy(value: any): value is ProxyConstructor | ng.Scope;
6+
/**
7+
* Unwraps a proxy if the value is a proxy, otherwise returns the value as-is.
8+
*
9+
* @template T
10+
* @param {T | (T & { $target: T })} val - A value that might be a proxy.
11+
* @returns {T} The unproxied value.
12+
*/
13+
export function deProxy<T>(
14+
val:
15+
| T
16+
| (T & {
17+
$target: T;
18+
}),
19+
): T;
720
/**
821
* @returns {number} an unique alpha-numeric string
922
*/

src/core/compile/attributes.js

Lines changed: 21 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import {
44
directiveNormalize,
55
hasAnimate,
66
hasOwn,
7+
isNullOrUndefined,
78
isString,
89
isUndefined,
910
minErr,
@@ -180,15 +181,22 @@ export class Attributes {
180181

181182
const nodeName = this.$nodeRef.node.nodeName.toLowerCase();
182183

184+
let maybeSanitizedValue;
185+
183186
// Sanitize img[srcset] values.
184187
if (nodeName === "img" && key === "srcset") {
185-
this[key] = value = this.sanitizeSrcset(value, "$set('srcset', value)");
188+
this[key] = maybeSanitizedValue = this.sanitizeSrcset(
189+
value,
190+
"$set('srcset', value)",
191+
);
192+
} else {
193+
maybeSanitizedValue = value;
186194
}
187195

188196
if (writeAttr !== false) {
189197
const elem = /** @type {Element} */ (this.$$element);
190198

191-
if (value === null || isUndefined(value)) {
199+
if (isNullOrUndefined(maybeSanitizedValue)) {
192200
elem.removeAttribute(attrName);
193201
//
194202
} else if (SIMPLE_ATTR_NAME.test(attrName)) {
@@ -197,17 +205,23 @@ export class Attributes {
197205
// `.getAttribute(attrName, false) with such attributes. To avoid issues
198206
// in XHTML, call `removeAttr` in such cases instead.
199207
// See https://github.com/jquery/jquery/issues/4249
200-
if (booleanKey && value === false) {
208+
if (booleanKey && maybeSanitizedValue === false) {
201209
elem.removeAttribute(attrName);
202210
} else {
203211
if (booleanKey) {
204-
elem.toggleAttribute(attrName, /** @type {boolean} */ (value));
212+
elem.toggleAttribute(
213+
attrName,
214+
/** @type {boolean} */ (maybeSanitizedValue),
215+
);
205216
} else {
206-
elem.setAttribute(attrName, /** @type {string} */ (value));
217+
elem.setAttribute(
218+
attrName,
219+
/** @type {string} */ (maybeSanitizedValue),
220+
);
207221
}
208222
}
209223
} else {
210-
this.setSpecialAttr(this.$$element, attrName, value);
224+
this.setSpecialAttr(this.$$element, attrName, maybeSanitizedValue);
211225
}
212226
}
213227

@@ -217,7 +231,7 @@ export class Attributes {
217231
if ($$observers && $$observers[observer]) {
218232
$$observers[observer].forEach((fn) => {
219233
try {
220-
fn(value);
234+
fn(maybeSanitizedValue);
221235
} catch (err) {
222236
this._$exceptionHandler(err);
223237
}

0 commit comments

Comments
 (0)