-
Notifications
You must be signed in to change notification settings - Fork 27.4k
refactor($compile): remove unnecessary try/catch #13263
Conversation
It could throw if See both in action here. Since I don't think we want to keep a non-string, user-specified directive.restrict = directive.restrict || 'EA'; ...to: directive.restrict = isString(directive.restrict) && directive.restrict || 'EA';
// or
directive.restrict = (directive.restrict && isString(directive.restrict)) ? directive.restrict : 'EA'; |
There are plenty of other directive properties without validation (priority, link, name, require, ...). But I'd be fine doing it if you'd like, better once in validation then a try/catch at runtime... |
I don't feel strongly either way (as they are both better than a try-catch). You said you didn't see anything that could throw - just pointing out there is 😛 |
True enough 😄 |
@gkalpak With your proposed change, you wouldn't notice that you have a wrong restrict setting, right? Because it would silently use 'EA' in that case. |
@Narretz, yes, but that is already the case if you have a falsy value or a wrong value (e.g. 'XYZ'). In both cases your directive won't work as expected, but there won't be an error. Do you think it's better to log a warning ? |
@gkalpak I see what you mean now. I guess we could log a debug / warning note. It would be pretty unusual for us, though. |
I think logging such a thing would be unusual and inconsistent with all the other DDO properties that could be invalid (and are not checked)... |
I'm still a little uneasy with merging this, as we remove the possibility to handle the exception. I don't think that anyone uses this, but you never know. And in that respect it would be a BC. |
I still don't see any issue with that, we don't do such validation on any other property. But if we did want validation I'd think it should be done on directive instantiation instead of each and every attempt at using the directive. |
ed6af3e
to
7aada46
Compare
7aada46
to
2ed4849
Compare
Any thoughts on this? Allow it to throw in |
I agree with @Narretz that this is a (tiny, highly unlikely to affect anyone) BC. So, an app that is working without this change (a simply logs an error for one broken directive), could stop working with this change. So, I would not merge it into 1.5. ("non-negligible" is subjective, so I leave room for interpretation 😛 ) |
If we want to do such validation how about moving it to directive registration instead of on each and every compilation of that directive? Then the user will get one error logged when the directive factory runs instead of 1 per compilation of the directive. |
Just to be clear, I don't feel strongly about keeping the So, to that end, since It's debatable if we want to just skip directives with an invalid |
2ed4849
to
bfacf9f
Compare
I've added an additional commit that validates the |
20f3c34
to
93a4d75
Compare
|
||
This error occurs when the restrict property of a directive is not valid. | ||
|
||
The directive restrict property must be a string with possible character values being: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would say "...string including one of more of the following characters:".
It might be also worth adding a couple of example: restrict: 'E'
, restrict: 'EAC'
$compileProvider.directive('invalidRestrictZero', valueFn({restrict: 0})); | ||
|
||
// We need to test with the exceptionHandler not rethrowing... | ||
$exceptionHandlerProvider.mode('log'); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You can keep the rethrow
mode and use the toThrowMinErr
helper instead.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
By default in tests $exceptionHandler
seems to throw. I had to change that to only log so that we can test that it only invokes $exceptionHandler
once (on first usage of the directive) and any further use of the directive does not re-log the same error message.
93a4d75
to
c985d11
Compare
@@ -969,6 +969,17 @@ function $CompileProvider($provide, $$sanitizeUriProvider) { | |||
return require; | |||
} | |||
|
|||
function getDirectiveRestrict(restrict, name) { | |||
if (restrict && !(isString(restrict) && /[EACM]/.test(restrict))) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I've updated this to convert all falsey values to the default like previously.
Cases which previously logged errors per-compilation (of an attribute/element with the same name), but otherwise did nothing:
- non-string truthy values
Cases which previously silently did nothing:
- arrays without single-character E/A/C/M
- strings with only invalid characters
Cases that previously worked unintentionally:
- arrays with single-character entries of E/A/C/M (such as
['E', 'A']
but not['EA']
)
Now all of these cases get logged as errors the first time an attribute/element of that name gets compiled.
I think I've addressed the comments. Let me know if there's anything else, or if you can prove I'm wrong again :) |
Looking better 😃 We have two possible BCs now:
I'm OK with the first category, since it's quite far-fetched and only worked accidentally. It's probably a programming error and throwing is a good thing. What bother's me a little with the second BC, is that (in far-fetched usecase) one could use the .directive('superAdminActions', function (User) {
return {
restrict: User.isSuperAdmin() ? 'E' : 'X',
...
};
}) It's a little contrieved, but not impossible imo 😃 So, while I don't think we need to support this, I would still land this change in 1.6.x only (with a proper BC notice). Other than that, LGTM 😃 |
For 1), do we care? Should we support the array case? I would vote no... For 2) note that this change only logs an error and prevents that directive from being added to the list of directives. The logged error will be new, but it shouldn't actually break anything. |
Me too
The logged error already is a BC imo. But here is a super contrived example of a usecase that would be totally broken: you broke me 😛 |
Is logging an error really a BC? It just adds information to inform the user of an error that they otherwise might not notice. Unless they purposely crash the app via However your example does show a potential BC, but honestly that seems like something that shouldn't even be supported: changing directive properties after a directive has already been registered. Your example was changing |
Now that would be a big BC. I'm not too bothered by any of the two BCs. If others think it is not a BC (i.e. it was never intended to work like this and if you are relying on that specific behavior it's your bad), I'm fine shipping it. |
Do you really think people abuse this today? I think preventing modifications to the DD would make things more consistent, and allow angular to do things like parsing or validation in the factory function (like this PR) instead of per-compile/link. |
I do :) I think there are people that try to access stuff off the DDO (e.g. using var ddo = {
...
compile: function () {
ddo.xyz...
}
};
return ddo; I'm not saying these are common usecases, but we shouldn't break uncommon usecases either between minor versions. I'm fine with the change if you think it has benefits, but for 1.6.x only (not 1.5.x). |
Is 1.6 stuff being merged yet? I do think isolating try/catch like this is worth it, similar to the recent acd4551 and many previous changes that did the same... |
Current master === 1.6 |
cbd3b69
to
fdac6ee
Compare
This allows the removal of try/catch from addDirective to avoid V8 deopt. Previously the directive.restrict property was not validated. This would potentially cause exceptions on each compilation of the directive requiring a try/catch and potentially causing repeated errors. New validation when directive.restrict is specified: * must be a string * must contain at least one valid character (E, A, C, M) Cases which previously silently failed (now throw an error): * values with an indexOf method (such as strings, arrays) which returned returned -1 for all valid restrict characters Cases which previously worked unintentionally (now throw an error): * arrays with single-character strings of valid restrict characters Closes angular#13263
This allows the removal of try/catch from addDirective to avoid V8 deopt. Previously the directive.restrict property was not validated. This would potentially cause exceptions on each compilation of the directive requiring a try/catch and potentially causing repeated errors. New validation when directive.restrict is specified: * must be a string * must contain at least one valid character (E, A, C, M) Cases which previously silently failed (now throw an error): * values with an indexOf method (such as strings, arrays) which returned returned -1 for all valid restrict characters Cases which previously worked unintentionally (now throw an error): * arrays with single-character strings of valid restrict characters Closes angular#13263
fdac6ee
to
50f9086
Compare
I've squashed and updated the commit message, and fixed a new eslint ' vs " error. As for breaking changes, only weird edge cases which were never intentionally supported will throw the error. Let me know if this is not clear from the commit message. |
This allows the removal of try/catch from addDirective to avoid V8 deopt. Previously the directive.restrict property was not validated. This would potentially cause exceptions on each compilation of the directive requiring a try/catch and potentially causing repeated errors. New validation when directive.restrict is specified: * must be a string * must contain at least one valid character (E, A, C, M) Cases which previously silently failed (now throw an error): * values with an indexOf method (such as strings, arrays) which returned returned -1 for all valid restrict characters Cases which previously worked unintentionally (now throw an error): * arrays with single-character strings of valid restrict characters PR (#13263)
This allows the removal of try/catch from addDirective to avoid V8 deopt. Previously the directive.restrict property was not validated. This would potentially cause exceptions on each compilation of the directive requiring a try/catch and potentially causing repeated errors. New validation when directive.restrict is specified: * must be a string * must contain at least one valid character (E, A, C, M) Cases which previously silently failed (now throw an error): * values with an indexOf method (such as strings, arrays) which returned returned -1 for all valid restrict characters Cases which previously worked unintentionally (now throw an error): * arrays with single-character strings of valid restrict characters PR (angular#13263)
This allows the removal of try/catch from addDirective to avoid V8 deopt. Previously the directive.restrict property was not validated. This would potentially cause exceptions on each compilation of the directive requiring a try/catch and potentially causing repeated errors. New validation when directive.restrict is specified: * must be a string * must contain at least one valid character (E, A, C, M) Cases which previously silently failed (now throw an error): * values with an indexOf method (such as strings, arrays) which returned returned -1 for all valid restrict characters Cases which previously worked unintentionally (now throw an error): * arrays with single-character strings of valid restrict characters PR (angular#13263)
This allows the removal of try/catch from addDirective to avoid V8 deopt. Previously the directive.restrict property was not validated. This would potentially cause exceptions on each compilation of the directive requiring a try/catch and potentially causing repeated errors. New validation when directive.restrict is specified: * must be a string * must contain at least one valid character (E, A, C, M) Cases which previously silently failed (now throw an error): * values with an indexOf method (such as strings, arrays) which returned returned -1 for all valid restrict characters Cases which previously worked unintentionally (now throw an error): * arrays with single-character strings of valid restrict characters PR (angular#13263)
This allows the removal of try/catch from addDirective to avoid V8 deopt. Previously the directive.restrict property was not validated. This would potentially cause exceptions on each compilation of the directive requiring a try/catch and potentially causing repeated errors. New validation when directive.restrict is specified: * must be a string * must contain at least one valid character (E, A, C, M) Cases which previously silently failed (now throw an error): * values with an indexOf method (such as strings, arrays) which returned returned -1 for all valid restrict characters Cases which previously worked unintentionally (now throw an error): * arrays with single-character strings of valid restrict characters PR (angular#13263)
This allows the removal of try/catch from addDirective to avoid V8 deopt. Previously the directive.restrict property was not validated. This would potentially cause exceptions on each compilation of the directive requiring a try/catch and potentially causing repeated errors. New validation when directive.restrict is specified: * must be a string * must contain at least one valid character (E, A, C, M) Cases which previously silently failed (now throw an error): * values with an indexOf method (such as strings, arrays) which returned returned -1 for all valid restrict characters Cases which previously worked unintentionally (now throw an error): * arrays with single-character strings of valid restrict characters PR (angular#13263)
This allows the removal of try/catch from addDirective to avoid V8 deopt. Previously the directive.restrict property was not validated. This would potentially cause exceptions on each compilation of the directive requiring a try/catch and potentially causing repeated errors. New validation when directive.restrict is specified: * must be a string * must contain at least one valid character (E, A, C, M) Cases which previously silently failed (now throw an error): * values with an indexOf method (such as strings, arrays) which returned returned -1 for all valid restrict characters Cases which previously worked unintentionally (now throw an error): * arrays with single-character strings of valid restrict characters PR (#13263)
This allows the removal of try/catch from addDirective to avoid V8 deopt. Previously the directive.restrict property was not validated. This would potentially cause exceptions on each compilation of the directive requiring a try/catch and potentially causing repeated errors. New validation when directive.restrict is specified: * must be a string * must contain at least one valid character (E, A, C, M) Cases which previously silently failed (now throw an error): * values with an indexOf method (such as strings, arrays) which returned returned -1 for all valid restrict characters Cases which previously worked unintentionally (now throw an error): * arrays with single-character strings of valid restrict characters PR (#13263)
I don't see anything in there that could throw...