Conversation
|
Thanks for your pr! Could you please add a test case where the parent already has the "use strict";
class Foo {
method(){
}
}should be "use strict";
var Foo = function () {
function Foo() {
_classCallCheck(this, Foo);
}
_createClass(Foo, [{
key: "method",
value: function method() {}
}]);
return Foo;
}(); |
|
@xtuc I guess I would have to check if the program already has a |
|
I think we could do it with |
| closureParams, | ||
| t.blockStatement(body, [t.directive(t.directiveLiteral("use strict"))]), | ||
| ); | ||
| } |
There was a problem hiding this comment.
These two blocks looks really similar, maybe we could add on a condition for the injection of the directive.
Something like:
const directives = [];
if (parentHasUseStrict) {
directives push t.directive(t.directiveLiteral("use strict"))
}
t.blockStatement(body, directives)| method() { | ||
|
|
||
| } | ||
| } No newline at end of file |
There was a problem hiding this comment.
Test showing the case where the directive is already preset.+1:
Could you also please add a test where the directive isn't in the program but in a parent node? like that:
function t() {
"use strict";
class Foo {
method() {}
}
}|
Build successful! You can test your changes in the REPL here: https://babeljs.io/repl/build/7543/ |
|
Build successful! You can test your changes in the REPL here: https://babeljs.io/repl/build/7029/ |
|
|
||
| if (!parentHasUseStrict) { | ||
| directives.push(t.directive(t.directiveLiteral("use strict"))); | ||
| } |
There was a problem hiding this comment.
Nit: we are matching two times the use strict string, we could construct the node t.directiveLiteral("use strict") before. Just an idea.
| closureParams, | ||
| t.blockStatement(body, [t.directive(t.directiveLiteral("use strict"))]), | ||
| ); | ||
| const parent = this.path.findParent((path) => path.isProgram() || path.isBlockStatement()); |
There was a problem hiding this comment.
wont it check only the nearest parent? we can have really deep tree and I guess we should check for something like:
const strictParent = this.path.findParent((path) => {
if (!path.isProgram() && !path.isBlockStatement()) {
return false
}
return path.node.directives.some(directive => directive.value.value === 'use strict')
});| // | ||
| body.push(t.returnStatement(t.cloneNode(this.classRef))); | ||
|
|
||
| const parent = this.path.findParent( |
There was a problem hiding this comment.
ive left comment regarding this here, it got hidden by github though (i think i might have commented on some older commit)
| // | ||
| body.push(t.returnStatement(t.cloneNode(this.classRef))); | ||
|
|
||
| const strictParent = this.path.findParent(path => { |
There was a problem hiding this comment.
looks better now 👍 would be great to add tests to cover this
also would be great to skip adding those directives in modules, but im not entirely sure how to check that, maybe you can check some property on the program or file? there are things like sourceType which could hint you this info, im not sure though where this info resides
There was a problem hiding this comment.
I'm not sure this is actually testable. Having the directive in the program or in a parent function produces the same result.
There was a problem hiding this comment.
You can test by writing a random non-simple arguments list (destructuring, defaults) in the IIFE the transform generates and seeing if it compiles.
'use strict' inside a function is too late to disable sloppy mode in the arguments list.
There was a problem hiding this comment.
Not sure if we have understood each other - I was asking if there is a possibility to skip adding this for such input
import a from './a'
class B {
constructor() { this.c = a() }
}Modules are already strict be definition and they do not have to add use strict directive explicitly.
There was a problem hiding this comment.
Agreed. We'll want to make sure to avoid adding it to module. It should be safe to do
if (path.isProgram() && path.node.sourceType === "module") {
return true;
}
to this to cover the module case.
nicolo-ribaudo
left a comment
There was a problem hiding this comment.
You also need to consider classes with only the onstructor (for which the iife isn't created):
// Input
class A {
constructor() {
}
}
// Current output
var A = function A() {
_classCallCheck(this, A);
};
// Expected output
var A = function A() {
"use strict";
_classCallCheck(this, A);
};|
We definitely need to always create an IIFE then. Otherwise, it won't be possible to have argument defaults or destructuring in the constructor's arguments. |
|
@Kovensky could u give example of problematic input? I've looked into constructor with default argument case and I'm not sure why it wouldn't be possible to skip the IIFE in such case. |
|
@Andarist For instance if we converted to that in fact throws an error because non-simple parameters need to already be strict by the time the parser reaches them, if you're going to try to make them strict. We could likely skip the IIFE and keeping the simple function, as long as we special-case the non-simple function params to still create the IIFE. |
|
Ok, that's an interesting case. As you said - we could try to continue optimizing this and de-opt on non-simple params when strict directive has to be added to the class (which in reality should be in minority of cases). I would be for optimizing it as it shouldn't be too complicated code-wise and I'm a little weirdo who likes optimized outputs 😅 dunno how you & other feel about such cases though. Also I'm wondering why this: let Foo = function(arg = {}) {};doesn't throw? 🤔 Why it starts to throw once we add a strict directive in the function's body? |
There's nothing wrong with having non-simple parameters when non-strict. The problem is that The issue essentially is that if your code is non-strict and you're parsing a whole function and then suddenly hit a when the parser encounters |
|
@loganfsmyth thanks for clarifying, makes sense 😄 |
9d3143d to
07b8409
Compare
|
@loganfsmyth I am not sure how to handle the constructor only cases - could you please give me some guidance on where to start and what to check for? So I guess at first we have to add the "use strict" directive to constructor-only function bodies, and then we should check for non-simple arguments and not add the "use strict" directive? |
|
I think there are such cases:
|
|
How can I help us get this across the finish line? You've done some great work and I feel bad that it keep getting conflicts. |
- Add "use strict" directive to transformed class bodies
But constructor only that use non-simple parameters must use a strict function wrapper.
1462b23 to
0ef10c8
Compare
|
Pushed a rebase, and included the constructor-only and non-simple parameter edge case. |
|
@jridgewell Can you move the |
Was already planning on it. Would you file an issue?
Done. |
|
Thanks for the core of the work @MarkusToe! |
|
@jridgewell Thanks for finishing and I'm sorry that I didn't put more time in lately. |
|
@MarkusToe No problem at all. Thanks for getting the work on this moving in the first place! |
I added the "use strict" directive in the function body BlockStatement.