Skip to content

Commit f5010e6

Browse files
committed
Additional module validation
1 parent 125e37b commit f5010e6

File tree

9 files changed

+90
-96
lines changed

9 files changed

+90
-96
lines changed

@types/core/di/ng-module/ng-module.d.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -165,14 +165,14 @@ export class NgModule {
165165
): NgModule;
166166
/**
167167
* @param {string} name
168-
* @param {Function} ctor
168+
* @param {Function|Object} ctor - A regular function, an arrow function or an object
169169
* @param {ng.StorageType} type
170170
* @param {ng.StorageBackend} [backendOrConfig]
171171
* @returns {NgModule}
172172
*/
173173
store(
174174
name: string,
175-
ctor: Function,
175+
ctor: Function | any,
176176
type: ng.StorageType,
177177
backendOrConfig?: ng.StorageBackend,
178178
): NgModule;

@types/shared/utils.d.ts

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -93,10 +93,7 @@ export function notNullOrUndefined(obj: any): boolean;
9393
*/
9494
export function isNumber(value: any): boolean;
9595
/**
96-
* @module angular
97-
* @function isDate
9896
*
99-
* @description
10097
* Determines if a value is a date.
10198
*
10299
* @param {*} value Reference to check.
@@ -634,6 +631,11 @@ export function instantiateWasm(
634631
exports: WebAssembly.Exports;
635632
module: WebAssembly.Module;
636633
}>;
634+
/**
635+
* @param {*} fn
636+
* @returns {boolean}
637+
*/
638+
export function isArrowFunction(fn: any): boolean;
637639
export const isProxySymbol: unique symbol;
638640
export const BADARG: "badarg";
639641
export const BADARGKEY: "badarg: key";

docs/content/docs/service/eventBus.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,9 @@ but uses
1414
[`queueMicrotask`](https://developer.mozilla.org/en-US/docs/Web/API/Window/queueMicrotask)
1515
instead of
1616
[`Window.setTimeout()`](https://developer.mozilla.org/en-US/docs/Web/API/Window/setTimeout)
17-
for its async implementation. `$eventBus` allows communication between an
17+
for its async implementation.
18+
19+
`$eventBus` allows communication between an
1820
Angular application instance and the outside context, which can be a different
1921
module, a non-Angular application, a third-party party library, or even a WASM
2022
application. Additionally, `$eventBus` can be used to communicate directly with

src/core/compile/compile.spec.js

Lines changed: 17 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -263,25 +263,6 @@ describe("$compile", () => {
263263
}).toThrowError();
264264
});
265265

266-
it("allows creating directives with object notation", () => {
267-
myModule.directive({
268-
a: () => {
269-
/* empty */
270-
},
271-
b: () => {
272-
/* empty */
273-
},
274-
c: () => {
275-
/* empty */
276-
},
277-
});
278-
reloadModules();
279-
280-
expect(injector.has("aDirective")).toBe(true);
281-
expect(injector.has("bDirective")).toBe(true);
282-
expect(injector.has("cDirective")).toBe(true);
283-
});
284-
285266
it("passes an element to directive compile", () => {
286267
let el;
287268
myModule.directive("myDirective", () => {
@@ -4758,7 +4739,7 @@ describe("$compile", () => {
47584739
expect(() => {
47594740
myModule.directive();
47604741
createInjector(["myModule"]).invoke(($compile) => {});
4761-
}).toThrowError(/areq/);
4742+
}).toThrowError(/badarg/);
47624743
});
47634744

47644745
it("should ignore special chars before processing attribute directive name", () => {
@@ -4781,7 +4762,7 @@ describe("$compile", () => {
47814762
expect(() => {
47824763
myModule.directive("myDir");
47834764
createInjector(["myModule"]).invoke(($compile) => {});
4784-
}).toThrowError(/areq/);
4765+
}).toThrowError(/badarg/);
47854766
});
47864767

47874768
it("should preserve context within declaration", async () => {
@@ -7491,13 +7472,11 @@ describe("$compile", () => {
74917472

74927473
describe("attrs", () => {
74937474
it("should allow setting of attributes", async () => {
7494-
module.directive({
7495-
setter: () => (scope, element, attr) => {
7496-
attr.$set("name", "abc");
7497-
attr.$set("disabled", true);
7498-
expect(attr.name).toBe("abc");
7499-
expect(attr.disabled).toBe(true);
7500-
},
7475+
module.directive("setter", () => (scope, element, attr) => {
7476+
attr.$set("name", "abc");
7477+
attr.$set("disabled", true);
7478+
expect(attr.name).toBe("abc");
7479+
expect(attr.disabled).toBe(true);
75017480
});
75027481

75037482
createInjector(["test1"]).invoke((_$compile_, _$rootScope_) => {
@@ -7513,13 +7492,11 @@ describe("$compile", () => {
75137492

75147493
it("should read boolean attributes as boolean only on control elements", async () => {
75157494
let value;
7516-
module.directive({
7517-
input: () => ({
7518-
link(scope, element, attr) {
7519-
value = attr.required;
7520-
},
7521-
}),
7522-
});
7495+
module.directive("input", () => ({
7496+
link(scope, element, attr) {
7497+
value = attr.required;
7498+
},
7499+
}));
75237500

75247501
createInjector(["test1"]).invoke((_$compile_, _$rootScope_) => {
75257502
$compile = _$compile_;
@@ -7533,13 +7510,11 @@ describe("$compile", () => {
75337510

75347511
it("should read boolean attributes as text on non-control elements", async () => {
75357512
let value;
7536-
module.directive({
7537-
div: () => ({
7538-
link(scope, element, attr) {
7539-
value = attr.required;
7540-
},
7541-
}),
7542-
});
7513+
module.directive("div", () => ({
7514+
link(scope, element, attr) {
7515+
value = attr.required;
7516+
},
7517+
}));
75437518

75447519
createInjector(["test1"]).invoke((_$compile_, _$rootScope_) => {
75457520
$compile = _$compile_;

src/core/di/injector.spec.js

Lines changed: 15 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -2290,14 +2290,12 @@ describe("strict-di injector", () => {
22902290
});
22912291

22922292
it("should throw if magic annotation is used by service", () => {
2293-
module.provider(($provide) => {
2294-
$provide.service({
2295-
$test: () => {
2296-
return this;
2297-
},
2298-
$test2: function ($test) {
2299-
return this;
2300-
},
2293+
module.provider("test", ($provide) => {
2294+
$provide.service("$test", () => {
2295+
return this;
2296+
});
2297+
$provide.service("$test2", function ($test) {
2298+
return this;
23012299
});
23022300
});
23032301
expect(() => {
@@ -2306,13 +2304,11 @@ describe("strict-di injector", () => {
23062304
});
23072305

23082306
it("should throw if magic annotation is used by provider", () => {
2309-
module.provider(($provide) => {
2310-
$provide.provider({
2311-
$test: () => {
2312-
this.$get = function ($rootScope) {
2313-
return $rootScope;
2314-
};
2315-
},
2307+
module.provider("test", ($provide) => {
2308+
$provide.provider("test", () => {
2309+
this.$get = function ($rootScope) {
2310+
return $rootScope;
2311+
};
23162312
});
23172313
});
23182314
expect(() => {
@@ -2321,11 +2317,9 @@ describe("strict-di injector", () => {
23212317
});
23222318

23232319
it("should throw if magic annotation is used by factory", () => {
2324-
module.provider(($provide) => {
2325-
$provide.factory({
2326-
$test: function ($rootScope) {
2327-
return function () {};
2328-
},
2320+
module.provider("test", ($provide) => {
2321+
$provide.factory("$test", function ($rootScope) {
2322+
return function () {};
23292323
});
23302324
});
23312325
expect(() => {
@@ -2334,7 +2328,7 @@ describe("strict-di injector", () => {
23342328
});
23352329

23362330
it("should throw if factory does not return a value", () => {
2337-
module.provider(($provide) => {
2331+
module.provider("test", ($provide) => {
23382332
$provide.factory("$test", () => {
23392333
/* empty */
23402334
});

src/core/di/internal-injector.js

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { hasOwn, minErr } from "../../shared/utils.js";
1+
import { hasOwn, isArrowFunction, minErr } from "../../shared/utils.js";
22
import { annotate, isClass } from "./di.js";
33
import { $injectTokens } from "../../injection-tokens.js";
44

@@ -137,7 +137,16 @@ class AbstractInjector {
137137
// Empty object at position 0 is ignored for invocation with `new`, but required.
138138
args.unshift(null);
139139

140-
return new (Function.prototype.bind.apply(ctor, args))();
140+
try {
141+
return new (Function.prototype.bind.apply(ctor, args))();
142+
} catch (err) {
143+
// try arrow function
144+
if (isArrowFunction(ctor)) {
145+
return ctor(args);
146+
} else {
147+
throw err;
148+
}
149+
}
141150
}
142151

143152
/**

src/core/di/ng-module/ng-module.js

Lines changed: 27 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@ import {
66
isString,
77
validate,
88
isDefined,
9+
validateRequired,
10+
isObject,
911
} from "../../../shared/utils.js";
1012
import { isInjectable } from "../../../shared/predicates.js";
1113

@@ -129,6 +131,8 @@ export class NgModule {
129131
* @returns {NgModule}
130132
*/
131133
factory(name, providerFunction) {
134+
validate(isString, name, "name");
135+
validateRequired(providerFunction, "providerFunction");
132136
this.invokeQueue.push([$t.$provide, "factory", [name, providerFunction]]);
133137

134138
return this;
@@ -140,6 +144,8 @@ export class NgModule {
140144
* @returns {NgModule}
141145
*/
142146
service(name, serviceFunction) {
147+
validate(isString, name, "name");
148+
validateRequired(serviceFunction, "serviceFunction");
143149
this.services.push(name);
144150
this.invokeQueue.push([$t.$provide, "service", [name, serviceFunction]]);
145151

@@ -152,9 +158,8 @@ export class NgModule {
152158
* @returns {NgModule}
153159
*/
154160
provider(name, providerType) {
155-
if (providerType && isFunction(providerType)) {
156-
providerType.$$moduleName = name;
157-
}
161+
validate(isString, name, "name");
162+
validateRequired(providerType, "providerType");
158163
this.invokeQueue.push([$t.$provide, "provider", [name, providerType]]);
159164

160165
return this;
@@ -166,9 +171,8 @@ export class NgModule {
166171
* @returns {NgModule}
167172
*/
168173
decorator(name, decorFn) {
169-
if (decorFn && isFunction(decorFn)) {
170-
decorFn.$$moduleName = name;
171-
}
174+
validate(isString, name, "name");
175+
validateRequired(decorFn, "decorFn");
172176
this.configBlocks.push([$t.$provide, "decorator", [name, decorFn]]);
173177

174178
return this;
@@ -180,6 +184,8 @@ export class NgModule {
180184
* @returns {NgModule}
181185
*/
182186
directive(name, directiveFactory) {
187+
validate(isString, name, "name");
188+
validateRequired(directiveFactory, "directiveFactory");
183189
this.invokeQueue.push([
184190
$t.$compileProvider,
185191
"directive",
@@ -195,6 +201,8 @@ export class NgModule {
195201
* @returns {NgModule}
196202
*/
197203
animation(name, animationFactory) {
204+
validate(isString, name, "name");
205+
validateRequired(animationFactory, "animationFactory");
198206
this.invokeQueue.push([
199207
$t.$animateProvider,
200208
"register",
@@ -226,6 +234,8 @@ export class NgModule {
226234
* @returns {NgModule}
227235
*/
228236
controller(name, ctlFn) {
237+
validate(isString, name, "name");
238+
validateRequired(ctlFn, `fictlFnlterFn`);
229239
this.invokeQueue.push([$t.$controllerProvider, "register", [name, ctlFn]]);
230240

231241
return this;
@@ -253,6 +263,8 @@ export class NgModule {
253263
* @returns {NgModule}
254264
*/
255265
wasm(name, src, imports = {}, opts = {}) {
266+
validate(isString, name, "name");
267+
validate(isString, src, "src");
256268
const raw = !!opts.raw;
257269

258270
this.invokeQueue.push([
@@ -282,6 +294,8 @@ export class NgModule {
282294
* @returns {NgModule}
283295
*/
284296
worker(name, scriptPath, config) {
297+
validate(isString, name, "name");
298+
validate(isString, scriptPath, "scriptPath");
285299
this.invokeQueue.push([
286300
$t.$provide,
287301
"provider",
@@ -298,16 +312,18 @@ export class NgModule {
298312

299313
/**
300314
* @param {string} name
301-
* @param {Function} ctor
315+
* @param {Function|Object} ctor - A regular function, an arrow function or an object
302316
* @param {ng.StorageType} type
303317
* @param {ng.StorageBackend} [backendOrConfig]
304318
* @returns {NgModule}
305319
*/
306320
store(name, ctor, type, backendOrConfig) {
321+
validate(isString, name, "name");
322+
validateRequired(ctor, "ctor");
307323
this.invokeQueue.push([
308324
$t.$provide,
309325
"store",
310-
[name, ctor, type, backendOrConfig],
326+
[name, isObject(ctor) ? () => ctor : ctor, type, backendOrConfig],
311327
]);
312328

313329
return this;
@@ -323,6 +339,9 @@ export class NgModule {
323339
* @returns {NgModule}
324340
*/
325341
rest(name, url, entityClass, options = {}) {
342+
validate(isString, name, "name");
343+
validate(isString, url, "url");
344+
validate(isFunction, entityClass, "entityClass");
326345
const def = { name, url, entityClass, options };
327346

328347
this.restDefinitions.push(def);

src/services/storage/storage-example.html

Lines changed: 2 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -61,20 +61,8 @@
6161
},
6262
"session",
6363
)
64-
.store(
65-
"localStore",
66-
class {
67-
counter = 0;
68-
},
69-
"local",
70-
)
71-
.store(
72-
"cookieStore",
73-
class {
74-
counter = 0;
75-
},
76-
"cookie",
77-
);
64+
.store("localStore", () => ({ counter: 0 }), "local")
65+
.store("cookieStore", { counter: 0 }, "cookie");
7866
});
7967
</script>
8068
</head>

0 commit comments

Comments
 (0)