@angular-wave/angular.ts 0.4.1 → 0.4.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (90) hide show
  1. package/dist/angular-ts.esm.js +2 -2
  2. package/dist/angular-ts.umd.js +2 -2
  3. package/package.json +7 -7
  4. package/src/angular.spec.js +1 -264
  5. package/src/animations/animate-css-driver.js +2 -2
  6. package/src/animations/animate-css.js +7 -8
  7. package/src/animations/animate-js-driver.js +1 -3
  8. package/src/animations/animate-js.js +4 -4
  9. package/src/animations/animate-queue.js +6 -6
  10. package/src/animations/animation.js +3 -3
  11. package/src/animations/shared.js +16 -14
  12. package/src/core/compile/attributes.js +2 -3
  13. package/src/core/compile/compile.js +248 -232
  14. package/src/core/compile/compile.spec.js +46 -51
  15. package/src/core/compile/compile.test.js +1 -1
  16. package/src/core/interpolate/interpolate.js +2 -2
  17. package/src/core/interval/interval.test.js +1 -1
  18. package/src/core/{parser/lexer.html → parse/ast/ast.html} +1 -1
  19. package/src/core/{parser → parse/ast}/ast.js +43 -29
  20. package/src/core/parse/ast/ast.spec.js +1462 -0
  21. package/src/core/parse/ast/ast.test.js +10 -0
  22. package/src/core/{parser → parse}/interpreter.js +10 -10
  23. package/src/core/parse/lexer/lexer.html +18 -0
  24. package/src/core/{parser → parse/lexer}/lexer.js +1 -1
  25. package/src/core/{parser → parse/lexer}/lexer.spec.js +2 -2
  26. package/src/core/parse/lexer/lexer.test.js +10 -0
  27. package/src/core/{parser → parse}/parse.html +1 -1
  28. package/src/core/{parser → parse}/parse.js +6 -6
  29. package/src/core/{parser → parse}/parse.spec.js +6 -1725
  30. package/src/core/parse/parse.test.js +10 -0
  31. package/src/core/parse/parser/parser.html +18 -0
  32. package/src/core/{parser → parse/parser}/parser.js +6 -6
  33. package/src/core/parse/parser/parser.spec.js +8 -0
  34. package/src/core/parse/parser/parser.test.js +10 -0
  35. package/src/core/sce/sce.js +1 -2
  36. package/src/core/scope/scope.js +4 -5
  37. package/src/directive/attrs/attrs.test.js +11 -0
  38. package/src/directive/attrs/boolean.html +18 -0
  39. package/src/directive/attrs/boolean.test.js +11 -0
  40. package/src/directive/attrs/element-style.html +21 -0
  41. package/src/directive/attrs/element-style.test.js +11 -0
  42. package/src/directive/bind/bing-html.spec.js +1 -1
  43. package/src/directive/class/class.js +1 -1
  44. package/src/directive/form/form.js +12 -19
  45. package/src/directive/if/if.spec.js +2 -3
  46. package/src/directive/if/if.test.js +1 -2
  47. package/src/directive/include/include.js +2 -2
  48. package/src/directive/input/input.js +1 -2
  49. package/src/directive/input/input.spec.js +187 -191
  50. package/src/directive/list/list.js +2 -2
  51. package/src/directive/model/model.js +14 -19
  52. package/src/directive/model-options/model-options.js +22 -26
  53. package/src/directive/options/options.js +1 -3
  54. package/src/directive/options/options.spec.js +3 -4
  55. package/src/directive/repeat/repeat.js +2 -2
  56. package/src/directive/repeat/repeat.spec.js +48 -57
  57. package/src/directive/select/select.spec.js +9 -10
  58. package/src/directive/switch/switch.js +1 -2
  59. package/src/directive/validators/validators.js +3 -3
  60. package/src/public.js +1 -1
  61. package/src/router/directives/state-directives.js +18 -16
  62. package/src/router/directives/view-directive.js +2 -2
  63. package/src/router/state/views.js +2 -2
  64. package/src/router/url/url-service.js +2 -8
  65. package/src/router/url/url-service.spec.js +3 -4
  66. package/src/services/http/http.js +5 -6
  67. package/src/services/http-backend/http-backend.js +19 -17
  68. package/src/shared/common.js +5 -8
  69. package/src/shared/jqlite/jqlite.js +14 -12
  70. package/src/shared/jqlite/jqlite.spec.js +2 -2
  71. package/src/shared/utils.js +15 -92
  72. package/types/animations/shared.d.ts +1 -1
  73. package/types/core/compile/compile.d.ts +1 -1
  74. package/types/core/interpolate/interpolate.d.ts +1 -1
  75. package/types/core/{parser → parse/ast}/ast.d.ts +17 -17
  76. package/types/core/{parser → parse}/interpreter.d.ts +7 -7
  77. package/types/core/{parser → parse/parser}/parser.d.ts +8 -8
  78. package/types/core/scope/scope.d.ts +3 -3
  79. package/types/directive/class/class.d.ts +3 -3
  80. package/types/directive/form/form.d.ts +1 -0
  81. package/types/directive/model/model.d.ts +6 -6
  82. package/types/directive/validators/validators.d.ts +3 -3
  83. package/types/shared/common.d.ts +0 -1
  84. package/types/shared/utils.d.ts +0 -35
  85. package/src/core/parser/parser.test.js +0 -19
  86. /package/src/core/{parser → parse}/ast-type.js +0 -0
  87. /package/src/core/{parser → parse}/parse.md +0 -0
  88. /package/types/core/{parser → parse}/ast-type.d.ts +0 -0
  89. /package/types/core/{parser → parse/lexer}/lexer.d.ts +0 -0
  90. /package/types/core/{parser → parse}/parse.d.ts +0 -0
@@ -1,7 +1,6 @@
1
1
  import { Angular } from "../../loader";
2
2
  import { dealoc, JQLite } from "../../shared/jqlite/jqlite";
3
3
  import { EMAIL_REGEXP, ISO_DATE_REGEXP, URL_REGEXP } from "./input";
4
- import { forEach } from "../../shared/utils";
5
4
 
6
5
  describe("input", () => {
7
6
  let $compile;
@@ -2157,197 +2156,194 @@ describe("input", () => {
2157
2156
  });
2158
2157
  });
2159
2158
 
2160
- forEach(
2161
- {
2162
- step: 'step="{{step}}"',
2163
- ngStep: 'ng-step="step"',
2164
- },
2165
- (attrHtml, attrName) => {
2166
- describe(attrName, () => {
2167
- it("should validate", () => {
2168
- scope.step = 10;
2169
- scope.value = 20;
2170
- const formElm = $compile(
2171
- `<form name="form"><input type="number" ng-model="value" name="alias" ${attrHtml} /></form>`,
2172
- )(scope);
2173
- inputElm = formElm.find("input");
2174
- scope.$digest();
2175
- expect(inputElm.val()).toBe("20");
2176
- expect(inputElm[0].classList.contains("ng-valid")).toBeTrue();
2177
- expect(scope.value).toBe(20);
2178
- expect(scope.form.alias.$error.step).toBeFalsy();
2179
-
2180
- inputElm[0].value = "18";
2181
- inputElm[0].dispatchEvent(new Event("change"));
2182
- expect(inputElm[0].classList.contains("ng-invalid")).toBeTrue();
2183
- expect(inputElm.val()).toBe("18");
2184
- expect(scope.value).toBeUndefined();
2185
- expect(scope.form.alias.$error.step).toBeTruthy();
2186
-
2187
- inputElm[0].value = "10";
2188
- inputElm[0].dispatchEvent(new Event("change"));
2189
- expect(inputElm[0].classList.contains("ng-valid")).toBeTrue();
2190
- expect(inputElm.val()).toBe("10");
2191
- expect(scope.value).toBe(10);
2192
- expect(scope.form.alias.$error.step).toBeFalsy();
2193
-
2194
- scope.$apply("value = 12");
2195
- expect(inputElm[0].classList.contains("ng-invalid")).toBeTrue();
2196
- expect(inputElm.val()).toBe("12");
2197
- expect(scope.value).toBe(12);
2198
- expect(scope.form.alias.$error.step).toBeTruthy();
2199
- });
2200
-
2201
- it("should validate even if the step value changes on-the-fly", () => {
2202
- scope.step = 10;
2203
- const formElm = $compile(
2204
- `<form name="form"><input type="number" ng-model="value" name="alias" ${attrHtml} /></form>`,
2205
- )(scope);
2206
- inputElm = formElm.find("input");
2207
- inputElm[0].value = "10";
2208
- inputElm[0].dispatchEvent(new Event("change"));
2209
- expect(inputElm[0].classList.contains("ng-valid")).toBeTrue();
2210
- expect(scope.value).toBe(10);
2211
-
2212
- // Step changes, but value matches
2213
- scope.$apply("step = 5");
2214
- expect(inputElm.val()).toBe("10");
2215
- expect(inputElm[0].classList.contains("ng-valid")).toBeTrue();
2216
- expect(scope.value).toBe(10);
2217
- expect(scope.form.alias.$error.step).toBeFalsy();
2218
-
2219
- // Step changes, value does not match
2220
- scope.$apply("step = 6");
2221
- expect(inputElm[0].classList.contains("ng-invalid")).toBeTrue();
2222
- expect(scope.value).toBeUndefined();
2223
- expect(inputElm.val()).toBe("10");
2224
- expect(scope.form.alias.$error.step).toBeTruthy();
2225
-
2226
- // null = valid
2227
- scope.$apply("step = null");
2228
- expect(inputElm[0].classList.contains("ng-valid")).toBeTrue();
2229
- expect(scope.value).toBe(10);
2230
- expect(inputElm.val()).toBe("10");
2231
- expect(scope.form.alias.$error.step).toBeFalsy();
2232
-
2233
- // Step val as string
2234
- scope.$apply('step = "7"');
2235
- expect(inputElm[0].classList.contains("ng-invalid")).toBeTrue();
2236
- expect(scope.value).toBeUndefined();
2237
- expect(inputElm.val()).toBe("10");
2238
- expect(scope.form.alias.$error.step).toBeTruthy();
2239
-
2240
- // unparsable string is ignored
2241
- scope.$apply('step = "abc"');
2242
- expect(inputElm[0].classList.contains("ng-valid")).toBeTrue();
2243
- expect(scope.value).toBe(10);
2244
- expect(inputElm.val()).toBe("10");
2245
- expect(scope.form.alias.$error.step).toBeFalsy();
2246
- });
2247
-
2248
- it('should use the correct "step base" when `[min]` is specified', () => {
2249
- scope.min = 5;
2250
- scope.step = 10;
2251
- scope.value = 10;
2252
- inputElm = $compile(
2253
- `<input type="number" ng-model="value" min="{{min}}" ${attrHtml} />`,
2254
- )(scope);
2255
- const ngModel = inputElm.controller("ngModel");
2256
- scope.$digest();
2257
- expect(inputElm.val()).toBe("10");
2258
- expect(inputElm[0].classList.contains("ng-invalid")).toBeTrue();
2259
- expect(ngModel.$error.step).toBe(true);
2260
- expect(scope.value).toBe(10); // an initially invalid value should not be changed
2261
-
2262
- inputElm[0].value = "15";
2263
- inputElm[0].dispatchEvent(new Event("change"));
2264
- expect(inputElm[0].classList.contains("ng-valid")).toBeTrue();
2265
- expect(scope.value).toBe(15);
2266
-
2267
- scope.$apply("step = 3");
2268
- expect(inputElm.val()).toBe("15");
2269
- expect(inputElm[0].classList.contains("ng-invalid")).toBeTrue();
2270
- expect(ngModel.$error.step).toBe(true);
2271
- expect(scope.value).toBeUndefined();
2272
-
2273
- inputElm[0].value = "8";
2274
- inputElm[0].dispatchEvent(new Event("change"));
2275
- expect(inputElm[0].classList.contains("ng-valid")).toBeTrue();
2276
- expect(scope.value).toBe(8);
2277
-
2278
- scope.$apply("min = 10; step = 20");
2279
- inputElm[0].value = "30";
2280
- inputElm[0].dispatchEvent(new Event("change"));
2281
- expect(inputElm.val()).toBe("30");
2282
- expect(inputElm[0].classList.contains("ng-valid")).toBeTrue();
2283
- expect(scope.value).toBe(30);
2284
-
2285
- scope.$apply("min = 5");
2286
- expect(inputElm.val()).toBe("30");
2287
- expect(inputElm[0].classList.contains("ng-invalid")).toBeTrue();
2288
- expect(ngModel.$error.step).toBe(true);
2289
- expect(scope.value).toBeUndefined();
2290
-
2291
- scope.$apply("step = 0.00000001");
2292
- expect(inputElm.val()).toBe("30");
2293
- expect(inputElm[0].classList.contains("ng-valid")).toBeTrue();
2294
- expect(scope.value).toBe(30);
2295
-
2296
- // 0.3 - 0.2 === 0.09999999999999998
2297
- scope.$apply("min = 0.2; step = (0.3 - 0.2)");
2298
- inputElm[0].value = "0.3";
2299
- inputElm[0].dispatchEvent(new Event("change"));
2300
- expect(inputElm.val()).toBe("0.3");
2301
- expect(inputElm[0].classList.contains("ng-invalid")).toBeTrue();
2302
- expect(ngModel.$error.step).toBe(true);
2303
- expect(scope.value).toBeUndefined();
2304
- });
2305
-
2306
- it("should correctly validate even in cases where the JS floating point arithmetic fails", () => {
2307
- scope.step = 0.1;
2308
- inputElm = $compile(
2309
- `<input type="number" ng-model="value" ${attrHtml} />`,
2310
- )(scope);
2311
- const ngModel = inputElm.controller("ngModel");
2312
-
2313
- expect(inputElm.val()).toBe("");
2314
- expect(inputElm[0].classList.contains("ng-valid")).toBeTrue();
2315
- expect(scope.value).toBeUndefined();
2316
-
2317
- inputElm[0].value = "0.3";
2318
- inputElm[0].dispatchEvent(new Event("change"));
2319
- expect(inputElm[0].classList.contains("ng-valid")).toBeTrue();
2320
- expect(scope.value).toBe(0.3);
2321
-
2322
- inputElm[0].value = "2.9999999999999996";
2323
- inputElm[0].dispatchEvent(new Event("change"));
2324
- expect(inputElm[0].classList.contains("ng-invalid")).toBeTrue();
2325
- expect(ngModel.$error.step).toBe(true);
2326
- expect(scope.value).toBeUndefined();
2327
-
2328
- // 0.5 % 0.1 === 0.09999999999999998
2329
- inputElm[0].value = "0.5";
2330
- inputElm[0].dispatchEvent(new Event("change"));
2331
- expect(inputElm[0].classList.contains("ng-valid")).toBeTrue();
2332
- expect(scope.value).toBe(0.5);
2333
-
2334
- // // 3.5 % 0.1 === 0.09999999999999981
2335
- inputElm[0].value = "3.5";
2336
- inputElm[0].dispatchEvent(new Event("change"));
2337
- expect(inputElm[0].classList.contains("ng-valid")).toBeTrue();
2338
- expect(scope.value).toBe(3.5);
2339
-
2340
- // 1.16 % 0.01 === 0.009999999999999896
2341
- // 1.16 * 100 === 115.99999999999999
2342
- scope.step = 0.01;
2343
- inputElm[0].value = "1.16";
2344
- inputElm[0].dispatchEvent(new Event("change"));
2345
- expect(inputElm[0].classList.contains("ng-valid")).toBeTrue();
2346
- expect(scope.value).toBe(1.16);
2347
- });
2159
+ Object.entries({
2160
+ step: 'step="{{step}}"',
2161
+ ngStep: 'ng-step="step"',
2162
+ }).forEach(([attrName, attrHtml]) => {
2163
+ describe(attrName, () => {
2164
+ it("should validate", () => {
2165
+ scope.step = 10;
2166
+ scope.value = 20;
2167
+ const formElm = $compile(
2168
+ `<form name="form"><input type="number" ng-model="value" name="alias" ${attrHtml} /></form>`,
2169
+ )(scope);
2170
+ inputElm = formElm.find("input");
2171
+ scope.$digest();
2172
+ expect(inputElm.val()).toBe("20");
2173
+ expect(inputElm[0].classList.contains("ng-valid")).toBeTrue();
2174
+ expect(scope.value).toBe(20);
2175
+ expect(scope.form.alias.$error.step).toBeFalsy();
2176
+
2177
+ inputElm[0].value = "18";
2178
+ inputElm[0].dispatchEvent(new Event("change"));
2179
+ expect(inputElm[0].classList.contains("ng-invalid")).toBeTrue();
2180
+ expect(inputElm.val()).toBe("18");
2181
+ expect(scope.value).toBeUndefined();
2182
+ expect(scope.form.alias.$error.step).toBeTruthy();
2183
+
2184
+ inputElm[0].value = "10";
2185
+ inputElm[0].dispatchEvent(new Event("change"));
2186
+ expect(inputElm[0].classList.contains("ng-valid")).toBeTrue();
2187
+ expect(inputElm.val()).toBe("10");
2188
+ expect(scope.value).toBe(10);
2189
+ expect(scope.form.alias.$error.step).toBeFalsy();
2190
+
2191
+ scope.$apply("value = 12");
2192
+ expect(inputElm[0].classList.contains("ng-invalid")).toBeTrue();
2193
+ expect(inputElm.val()).toBe("12");
2194
+ expect(scope.value).toBe(12);
2195
+ expect(scope.form.alias.$error.step).toBeTruthy();
2196
+ });
2197
+
2198
+ it("should validate even if the step value changes on-the-fly", () => {
2199
+ scope.step = 10;
2200
+ const formElm = $compile(
2201
+ `<form name="form"><input type="number" ng-model="value" name="alias" ${attrHtml} /></form>`,
2202
+ )(scope);
2203
+ inputElm = formElm.find("input");
2204
+ inputElm[0].value = "10";
2205
+ inputElm[0].dispatchEvent(new Event("change"));
2206
+ expect(inputElm[0].classList.contains("ng-valid")).toBeTrue();
2207
+ expect(scope.value).toBe(10);
2208
+
2209
+ // Step changes, but value matches
2210
+ scope.$apply("step = 5");
2211
+ expect(inputElm.val()).toBe("10");
2212
+ expect(inputElm[0].classList.contains("ng-valid")).toBeTrue();
2213
+ expect(scope.value).toBe(10);
2214
+ expect(scope.form.alias.$error.step).toBeFalsy();
2215
+
2216
+ // Step changes, value does not match
2217
+ scope.$apply("step = 6");
2218
+ expect(inputElm[0].classList.contains("ng-invalid")).toBeTrue();
2219
+ expect(scope.value).toBeUndefined();
2220
+ expect(inputElm.val()).toBe("10");
2221
+ expect(scope.form.alias.$error.step).toBeTruthy();
2222
+
2223
+ // null = valid
2224
+ scope.$apply("step = null");
2225
+ expect(inputElm[0].classList.contains("ng-valid")).toBeTrue();
2226
+ expect(scope.value).toBe(10);
2227
+ expect(inputElm.val()).toBe("10");
2228
+ expect(scope.form.alias.$error.step).toBeFalsy();
2229
+
2230
+ // Step val as string
2231
+ scope.$apply('step = "7"');
2232
+ expect(inputElm[0].classList.contains("ng-invalid")).toBeTrue();
2233
+ expect(scope.value).toBeUndefined();
2234
+ expect(inputElm.val()).toBe("10");
2235
+ expect(scope.form.alias.$error.step).toBeTruthy();
2236
+
2237
+ // unparsable string is ignored
2238
+ scope.$apply('step = "abc"');
2239
+ expect(inputElm[0].classList.contains("ng-valid")).toBeTrue();
2240
+ expect(scope.value).toBe(10);
2241
+ expect(inputElm.val()).toBe("10");
2242
+ expect(scope.form.alias.$error.step).toBeFalsy();
2243
+ });
2244
+
2245
+ it('should use the correct "step base" when `[min]` is specified', () => {
2246
+ scope.min = 5;
2247
+ scope.step = 10;
2248
+ scope.value = 10;
2249
+ inputElm = $compile(
2250
+ `<input type="number" ng-model="value" min="{{min}}" ${attrHtml} />`,
2251
+ )(scope);
2252
+ const ngModel = inputElm.controller("ngModel");
2253
+ scope.$digest();
2254
+ expect(inputElm.val()).toBe("10");
2255
+ expect(inputElm[0].classList.contains("ng-invalid")).toBeTrue();
2256
+ expect(ngModel.$error.step).toBe(true);
2257
+ expect(scope.value).toBe(10); // an initially invalid value should not be changed
2258
+
2259
+ inputElm[0].value = "15";
2260
+ inputElm[0].dispatchEvent(new Event("change"));
2261
+ expect(inputElm[0].classList.contains("ng-valid")).toBeTrue();
2262
+ expect(scope.value).toBe(15);
2263
+
2264
+ scope.$apply("step = 3");
2265
+ expect(inputElm.val()).toBe("15");
2266
+ expect(inputElm[0].classList.contains("ng-invalid")).toBeTrue();
2267
+ expect(ngModel.$error.step).toBe(true);
2268
+ expect(scope.value).toBeUndefined();
2269
+
2270
+ inputElm[0].value = "8";
2271
+ inputElm[0].dispatchEvent(new Event("change"));
2272
+ expect(inputElm[0].classList.contains("ng-valid")).toBeTrue();
2273
+ expect(scope.value).toBe(8);
2274
+
2275
+ scope.$apply("min = 10; step = 20");
2276
+ inputElm[0].value = "30";
2277
+ inputElm[0].dispatchEvent(new Event("change"));
2278
+ expect(inputElm.val()).toBe("30");
2279
+ expect(inputElm[0].classList.contains("ng-valid")).toBeTrue();
2280
+ expect(scope.value).toBe(30);
2281
+
2282
+ scope.$apply("min = 5");
2283
+ expect(inputElm.val()).toBe("30");
2284
+ expect(inputElm[0].classList.contains("ng-invalid")).toBeTrue();
2285
+ expect(ngModel.$error.step).toBe(true);
2286
+ expect(scope.value).toBeUndefined();
2287
+
2288
+ scope.$apply("step = 0.00000001");
2289
+ expect(inputElm.val()).toBe("30");
2290
+ expect(inputElm[0].classList.contains("ng-valid")).toBeTrue();
2291
+ expect(scope.value).toBe(30);
2292
+
2293
+ // 0.3 - 0.2 === 0.09999999999999998
2294
+ scope.$apply("min = 0.2; step = (0.3 - 0.2)");
2295
+ inputElm[0].value = "0.3";
2296
+ inputElm[0].dispatchEvent(new Event("change"));
2297
+ expect(inputElm.val()).toBe("0.3");
2298
+ expect(inputElm[0].classList.contains("ng-invalid")).toBeTrue();
2299
+ expect(ngModel.$error.step).toBe(true);
2300
+ expect(scope.value).toBeUndefined();
2348
2301
  });
2349
- },
2350
- );
2302
+
2303
+ it("should correctly validate even in cases where the JS floating point arithmetic fails", () => {
2304
+ scope.step = 0.1;
2305
+ inputElm = $compile(
2306
+ `<input type="number" ng-model="value" ${attrHtml} />`,
2307
+ )(scope);
2308
+ const ngModel = inputElm.controller("ngModel");
2309
+
2310
+ expect(inputElm.val()).toBe("");
2311
+ expect(inputElm[0].classList.contains("ng-valid")).toBeTrue();
2312
+ expect(scope.value).toBeUndefined();
2313
+
2314
+ inputElm[0].value = "0.3";
2315
+ inputElm[0].dispatchEvent(new Event("change"));
2316
+ expect(inputElm[0].classList.contains("ng-valid")).toBeTrue();
2317
+ expect(scope.value).toBe(0.3);
2318
+
2319
+ inputElm[0].value = "2.9999999999999996";
2320
+ inputElm[0].dispatchEvent(new Event("change"));
2321
+ expect(inputElm[0].classList.contains("ng-invalid")).toBeTrue();
2322
+ expect(ngModel.$error.step).toBe(true);
2323
+ expect(scope.value).toBeUndefined();
2324
+
2325
+ // 0.5 % 0.1 === 0.09999999999999998
2326
+ inputElm[0].value = "0.5";
2327
+ inputElm[0].dispatchEvent(new Event("change"));
2328
+ expect(inputElm[0].classList.contains("ng-valid")).toBeTrue();
2329
+ expect(scope.value).toBe(0.5);
2330
+
2331
+ // // 3.5 % 0.1 === 0.09999999999999981
2332
+ inputElm[0].value = "3.5";
2333
+ inputElm[0].dispatchEvent(new Event("change"));
2334
+ expect(inputElm[0].classList.contains("ng-valid")).toBeTrue();
2335
+ expect(scope.value).toBe(3.5);
2336
+
2337
+ // 1.16 % 0.01 === 0.009999999999999896
2338
+ // 1.16 * 100 === 115.99999999999999
2339
+ scope.step = 0.01;
2340
+ inputElm[0].value = "1.16";
2341
+ inputElm[0].dispatchEvent(new Event("change"));
2342
+ expect(inputElm[0].classList.contains("ng-valid")).toBeTrue();
2343
+ expect(scope.value).toBe(1.16);
2344
+ });
2345
+ });
2346
+ });
2351
2347
 
2352
2348
  describe("required", () => {
2353
2349
  it("should be valid even if value is 0", () => {
@@ -1,4 +1,4 @@
1
- import { forEach, isUndefined, trim } from "../../shared/utils";
1
+ import { isUndefined, trim } from "../../shared/utils";
2
2
 
3
3
  /**
4
4
  * @returns {import('../../types').Directive}
@@ -20,7 +20,7 @@ export function ngListDirective() {
20
20
  const list = [];
21
21
 
22
22
  if (viewValue) {
23
- forEach(viewValue.split(separator), (value) => {
23
+ viewValue.split(separator).forEach((value) => {
24
24
  if (value) list.push(trimValues ? trim(value) : value);
25
25
  });
26
26
  }
@@ -10,7 +10,6 @@ import {
10
10
  } from "../../shared/constants";
11
11
  import {
12
12
  minErr,
13
- forEach,
14
13
  isNumber,
15
14
  isNumberNaN,
16
15
  isPromiseLike,
@@ -87,7 +86,7 @@ export class NgModelController {
87
86
  * @param {import('../../core/exception-handler').ErrorHandler} $exceptionHandler
88
87
  * @param {import('../../core/compile/attributes').Attributes} $attr
89
88
  * @param {import('../../shared/jqlite/jqlite').JQLite} $element
90
- * @param {import("../../core/parser/parse").ParseService} $parse
89
+ * @param {import("../../core/parse/parse").ParseService} $parse
91
90
  * @param {*} $animate
92
91
  * @param {*} $timeout
93
92
  * @param {import("../../core/q/q").QPromise<any>} $q
@@ -147,7 +146,7 @@ export class NgModelController {
147
146
  this.$$parsedNgModel = $parse($attr["ngModel"]);
148
147
  this.$$parsedNgModelAssign = this.$$parsedNgModel.assign;
149
148
 
150
- /** @type {import("../../core/parser/parse").CompiledExpression|((Scope) => any)} */
149
+ /** @type {import("../../core/parse/parse").CompiledExpression|((Scope) => any)} */
151
150
  this.$$ngModelGet = this.$$parsedNgModel;
152
151
  this.$$ngModelSet = this.$$parsedNgModelAssign;
153
152
  this.$$pendingDebounce = null;
@@ -597,10 +596,10 @@ export class NgModelController {
597
596
  setValidity(errorKey, null);
598
597
  } else {
599
598
  if (!that.$$parserValid) {
600
- forEach(that.$validators, (v, name) => {
599
+ Object.keys(that.$validators).forEach((name) => {
601
600
  setValidity(name, null);
602
601
  });
603
- forEach(that.$asyncValidators, (v, name) => {
602
+ Object.keys(that.$asyncValidators).forEach((name) => {
604
603
  setValidity(name, null);
605
604
  });
606
605
  }
@@ -614,13 +613,13 @@ export class NgModelController {
614
613
 
615
614
  function processSyncValidators() {
616
615
  let syncValidatorsValid = true;
617
- forEach(that.$validators, (validator, name) => {
616
+ Object.entries(that.$validators).forEach(([name, validator]) => {
618
617
  const result = Boolean(validator(modelValue, viewValue));
619
618
  syncValidatorsValid = syncValidatorsValid && result;
620
619
  setValidity(name, result);
621
620
  });
622
621
  if (!syncValidatorsValid) {
623
- forEach(that.$asyncValidators, (v, name) => {
622
+ Object.keys(that.$asyncValidators).forEach((name) => {
624
623
  setValidity(name, null);
625
624
  });
626
625
  return false;
@@ -631,7 +630,7 @@ export class NgModelController {
631
630
  function processAsyncValidators() {
632
631
  const validatorPromises = [];
633
632
  let allValid = true;
634
- forEach(that.$asyncValidators, (validator, name) => {
633
+ Object.entries(that.$asyncValidators).forEach(([name, validator]) => {
635
634
  const promise = validator(modelValue, viewValue);
636
635
  if (!isPromiseLike(promise)) {
637
636
  throw ngModelMinErr(
@@ -776,17 +775,13 @@ export class NgModelController {
776
775
 
777
776
  $$writeModelToScope() {
778
777
  this.$$ngModelSet(this.$$scope, this.$modelValue);
779
- forEach(
780
- this.$viewChangeListeners,
781
- function (listener) {
782
- try {
783
- listener();
784
- } catch (e) {
785
- this.$$exceptionHandler(e);
786
- }
787
- },
788
- this,
789
- );
778
+ Object.values(this.$viewChangeListeners).forEach((listener) => {
779
+ try {
780
+ listener();
781
+ } catch (e) {
782
+ this.$$exceptionHandler(e);
783
+ }
784
+ }, this);
790
785
  }
791
786
 
792
787
  /**
@@ -1,4 +1,4 @@
1
- import { forEach, isDefined, trim } from "../../shared/utils";
1
+ import { isDefined, trim } from "../../shared/utils";
2
2
 
3
3
  const DEFAULT_REGEXP = /(\s+|^)default(\s+|$)/;
4
4
 
@@ -70,33 +70,29 @@ class ModelOptions {
70
70
  options = Object.assign({}, options);
71
71
 
72
72
  // Inherit options from the parent if specified by the value `"$inherit"`
73
- forEach(
74
- options,
75
- function (option, key) {
76
- if (option === "$inherit") {
77
- if (key === "*") {
78
- inheritAll = true;
79
- } else {
80
- options[key] = this.$$options[key];
81
- // `updateOn` is special so we must also inherit the `updateOnDefault` option
82
- if (key === "updateOn") {
83
- options.updateOnDefault = this.$$options.updateOnDefault;
84
- }
73
+ Object.entries(options).forEach(([key, option]) => {
74
+ if (option === "$inherit") {
75
+ if (key === "*") {
76
+ inheritAll = true;
77
+ } else {
78
+ options[key] = this.$$options[key];
79
+ // `updateOn` is special so we must also inherit the `updateOnDefault` option
80
+ if (key === "updateOn") {
81
+ options.updateOnDefault = this.$$options.updateOnDefault;
85
82
  }
86
- } else if (key === "updateOn") {
87
- // If the `updateOn` property contains the `default` event then we have to remove
88
- // it from the event list and set the `updateOnDefault` flag.
89
- options.updateOnDefault = false;
90
- options[key] = trim(
91
- option.replace(DEFAULT_REGEXP, () => {
92
- options.updateOnDefault = true;
93
- return " ";
94
- }),
95
- );
96
83
  }
97
- },
98
- this,
99
- );
84
+ } else if (key === "updateOn") {
85
+ // If the `updateOn` property contains the `default` event then we have to remove
86
+ // it from the event list and set the `updateOnDefault` flag.
87
+ options.updateOnDefault = false;
88
+ options[key] = trim(
89
+ /** @type {string} */ (option).replace(DEFAULT_REGEXP, () => {
90
+ options.updateOnDefault = true;
91
+ return " ";
92
+ }),
93
+ );
94
+ }
95
+ }, this);
100
96
 
101
97
  if (inheritAll) {
102
98
  // We have a property of the form: `"*": "$inherit"`
@@ -1,7 +1,6 @@
1
1
  import { JQLite, removeElement, startingTag } from "../../shared/jqlite/jqlite";
2
2
  import {
3
3
  equals,
4
- forEach,
5
4
  hashKey,
6
5
  includes,
7
6
  isArrayLike,
@@ -328,8 +327,7 @@ export const ngOptionsDirective = [
328
327
  selectCtrl.readValue = function readNgOptionsMultiple() {
329
328
  const selectedValues = selectElement.val() || [];
330
329
  const selections = [];
331
-
332
- forEach(selectedValues, (value) => {
330
+ selectedValues.forEach((value) => {
333
331
  const option = options.selectValueMap[value];
334
332
  if (option && !option.disabled)
335
333
  selections.push(options.getViewValueFromOption(option));
@@ -2,7 +2,6 @@ import { createInjector } from "../../core/di/injector";
2
2
  import { JQLite, dealoc } from "../../shared/jqlite/jqlite";
3
3
  import { Angular } from "../../loader";
4
4
  import {
5
- forEach,
6
5
  isBoolean,
7
6
  hashKey,
8
7
  equals,
@@ -232,7 +231,7 @@ describe("ngOptions", () => {
232
231
 
233
232
  function createSelect(attrs, blank, unknown) {
234
233
  let html = "<select";
235
- forEach(attrs, (value, key) => {
234
+ Object.entries(attrs).forEach(([key, value]) => {
236
235
  if (isBoolean(value)) {
237
236
  if (value) html += ` ${key}`;
238
237
  } else {
@@ -2993,7 +2992,7 @@ describe("ngOptions", () => {
2993
2992
  const addSpiesOnProto =
2994
2993
  originalSelectedDescriptor && originalSelectedDescriptor.configurable;
2995
2994
 
2996
- forEach(options, (option, i) => {
2995
+ Object.entries(options).forEach(([i, option]) => {
2997
2996
  const setSelected = function (value) {
2998
2997
  _selected[i] = value;
2999
2998
  };
@@ -3004,7 +3003,7 @@ describe("ngOptions", () => {
3004
3003
  });
3005
3004
 
3006
3005
  if (!addSpiesOnProto) {
3007
- forEach(options, (option, i) => {
3006
+ Object.entries(options).forEach(([i, option]) => {
3008
3007
  Object.defineProperty(option, "selected", {
3009
3008
  get() {
3010
3009
  return _selected[i];
@@ -1,4 +1,4 @@
1
- import { forEach, minErr, hashKey, isArrayLike } from "../../shared/utils";
1
+ import { minErr, hashKey, isArrayLike } from "../../shared/utils";
2
2
  import { getBlockNodes } from "../../shared/jqlite/jqlite";
3
3
 
4
4
  export const ngRepeatDirective = [
@@ -188,7 +188,7 @@ export const ngRepeatDirective = [
188
188
  nextBlockOrder[index] = block;
189
189
  } else if (nextBlockMap[trackById]) {
190
190
  // if collision detected. restore lastBlockMap and throw an error
191
- forEach(nextBlockOrder, function (block) {
191
+ Object.values(nextBlockOrder).forEach((block) => {
192
192
  if (block && block.scope) lastBlockMap[block.id] = block;
193
193
  });
194
194
  throw ngRepeatMinErr(