Issue 1:
Bug Report

Current Behavior

Sharing an identifier instance between visitors breaks import aliasing.

Input Code

babel-plugin.js

module.exports = function babelPlugin({ types: t }) {
return {
name: 'test',
visitor: {
Program: {
enter(path) {
const program = path.scope.getProgramParent();

// Alias the import so that it doesn't clash with anything else
// then reuse it when inseting the calls
this.localName = program.generateUidIdentifier('_foo');

// Add `import { foo as _foo } from "bar"`
[this.last] = program.path.unshiftContainer(
"body",
t.importDeclaration(
[t.importSpecifier(this.localName, t.identifier("foo"))],
t.stringLiteral("bar")
)
);
}
},
JSXElement(path) {
// Add `_foo.doSomething()`
[this.last] = this.last.insertAfter(
t.expressionStatement(
t.callExpression(
t.memberExpression(this.localName, t.identifier("doSomething")),
[]
)
)
);
},
},
};
};

example.js

import React, { Component } from 'react'
import { Node } from 'some-library'

class App extends Component {
render() {
return (
<>
<Node uri="test1.txt">hello</Node>
<Node uri="test2.txt">hello</Node>
<Node uri="test3.txt">hello</Node>
</>
)
}
}

Expected behavior/code

Transpiled in following way:

BABEL_DISABLE_CACHE=1 babel --verbose example.js --out-dir dist/

Produces:

// (...)
var _bar = require("bar");
// (...)
_bar.foo.doSomething();
_foo.doSomething();
_foo.doSomething();
// (...)

Expected result:

// (...)
var _bar = require("bar");
// (...)
_bar.foo.doSomething();
_bar.foo.doSomething();
_bar.foo.doSomething();
// (...)

Babel Configuration (.babelrc, package.json, cli command)

babel.config.js

module.exports = {
env: {
development: {
presets: [["next/babel"]],
plugins: ["./babel-plugin"],
},
},
};

Environment

Babel version(s): v7.5.5

Node/npm version: v12.4.0

OS: macOS v10.14.6

How you are using Babel: cli

Possible Solution

I'm a complete rookie when it comes to the babel internals, so I'm probably not fit for producing an actual bugfix, but I can share a workaround that I've made for this issue.

I can namely achieve the expected result by recreating the identifier in each visitor instead:

module.exports = function djediBabelPlugin({ types: t }) {
return {
name: 'test',
visitor: {
Program: {
enter(path) {
const program = path.scope.getProgramParent();

// Rename the import so that it doesn't clash with anything else
// then reuse it when inseting the calls
this.localName = program.generateUidIdentifier('_foo').name;

// Add `import { foo as _foo } from "bar"`
[this.last] = program.path.unshiftContainer(
"body",
t.importDeclaration(
[t.importSpecifier(t.identifier(this.localName), t.identifier("foo"))],
t.stringLiteral("bar")
)
);
}
},
JSXElement(path) {
// Add `_foo.doSomething()`
[this.last] = this.last.insertAfter(
t.expressionStatement(
t.callExpression(
t.memberExpression(t.identifier(this.localName), t.identifier("doSomething")),
[]
)
)
);
},
},
};
};

Issue 2:
This is a bug report

With the @babel/plugin-proposal-class-properties plugin, it appears that property initializers get duplicated in the nested class' constructor when both classes are extended classes that call super.

Input Code

Minimum repro:

class A extends C {
B;
constructor() {
super();
this.B = class B extends C {
constructor() {
super();
}
};
}
}

Babel/Babylon Configuration (.babelrc, package.json, cli command)

module.exports = {
plugins: [
['@babel/plugin-proposal-class-properties', { loose: true }],
],
presets: [
['@babel/preset-env', { targets: { node: 'current' } }],
],
};

Expected Behavior

class A extends C {
constructor() {
super();
this.B = void 0;
this.B = class B extends C {
constructor() {
super();
}
};
}
}

Current Behavior

class A extends C {
constructor() {
super();
this.B = void 0;
this.B = class B extends C {
constructor() {
super();
this.B = void 0; // THIS LINE SHOULDN'T BE HERE!
}
};
}
}

example (same deal, but with B = 1;): https://babeljs.io/repl/#?babili=false&browsers=&build=&builtIns=false&code_lz=MYGwhgzhAECC0FMAeAXBA7AJjAwtA3gFDTQBC0AvNAIwDcx0wA9uhCgE4CuwKT7AFAEoCDEhE4AHBAMH0SJFAAsAlhAB05KqEgxyyNFlwj585qw7deM4yfnipMubYC-o6M6evnQA&debug=false&forceAllTransforms=false&shippedProposals=false&circleciRepo=&evaluate=false&fileSize=false&lineWrap=false&presets=stage-2&prettier=false&targets=&version=6.26.0&envVersion=

There is an extra this.B = void 0; which is problematic because it will make this.B = undefined if the inner class is instantiated at any point, overwriting this.B = class ....

Possible Solution

There's probably some logic that just naively inserts the initializer based on the constructor pattern without accounting for context?

Context

I am implementing some React components, where a nested component is defined during the parent's constructor call because it will need to read props from the parent. The reason why there's a property initializer that's set to undefined in the first place is for flow types.

Your Environment

software
version(s)

Babel
7.0.0-beta.39

Babylon

node
8.9.0

npm
5.5.1

Operating System
macos