Changelog: swc v1.2.35

Bugfixes#

This version includes lots of bugfixes.

optional chaining (#1130)#

Nested property access in optional chaining is now properly compiled.

The affected code looks like below. Notice that there's no ? before map.

let data;
const result = data
?.filter((item) => Math.random() > 0.5)
.map((item) => JSON.stringify(item));

computed typescript properties (#1122)#

This is a regression caused by v1.2.18. The issue is about computed class properties in typescript.

const identifier = "bar";
class Foo {
[identifier] = 5;
}
console.log(new Foo().bar);

The code above now works properly.

temp var in nullish coalescing (#1123)#

Previously,

interface SuperSubmission {
[key: string]: any;
}
const normalizedQuestionSet: any = {};
const submissions: SuperSubmission[] = (
normalizedQuestionSet.submissionIds ?? []
).map(
(id, index): SuperSubmission => {
const submission = normalizedQuestionSet.submissions?.[id];
const submissionAnswers = (submission.answers ?? []).map(
(answerId) => normalizedQuestionSet.answers?.[answerId]
);
console.log(id, index);
return {
type: "super-submission",
};
}
);
console.log(submissions);

was miscompiled as

"use strict";
const normalizedQuestionSet = {};
const submissions = ((_submissionIds = normalizedQuestionSet.submissionIds) !==
null && _submissionIds !== void 0
? _submissionIds
: []
).map((id, index) => {
var ref, ref1;
var _submissionIds;
const submission =
(ref = normalizedQuestionSet.submissions) === null || ref === void 0
? void 0
: ref[id];
var _answers;
const submissionAnswers = ((_answers = submission.answers) !== null &&
_answers !== void 0
? _answers
: []
).map((answerId) =>
(ref1 = normalizedQuestionSet.answers) === null || ref1 === void 0
? void 0
: ref1[answerId]
);
console.log(id, index);
return {
type: "super-submission",
};
});
console.log(submissions);

which is wrong because var _submissionIds; should be declared at tbe top level. This is fixed by visiting children nodes (like block statement) with a new empty variable buffer.

renaming of private class properties (#1117)#

At the time of implementing hygiene and resolver, which is the core of the swc, there was no support for private class properties. It resulted in this bug, where hygiene pass renaming private properties. This is fixed by not visiting private identifiers.

Affected code looks like below.

Two private identifiers with same name declared in different class, but in same file. This bug is found by @kitsonk while integrating swc_bundler into deno.

export class G {
#g!: number[];
constructor(shared: boolean) {
if (shared) {
this.#g = g;
} else {
this.#g = [];
}
}
}
export class H {
#g!: number[];
constructor(shared: boolean) {
if (shared) {
this.#g = g;
} else {
this.#g = [];
}
}
}

bundler: too many exports (#1119)#

export function a(...d: string[]): string {
return d.join(" ");
}

resulted in

const _i = (function () {
function a(...d) {
return d.join(" ");
}
return {
a,
d,
};
})();

which is clearly wrong. This is fixed by collecting exported identifiers carefully.

bundler: export * (#1116)#

Code like

export * from "./a.ts";

was handled inproperly by spack.

stack overflow of inliner (#1127)#

This is fixed by migrating by working with pointers instead of passing structs around.

bundler: import.meta support (#1115)#

As deno bundle, which works with tsc and in a progress of integrating the bundler of swc into it, supports import.meta, I added support for them.

Currently two meta properties are supported.

import.meta.main; // false for imported modules, and as-is for entries
import.meta.url; // The path of file. (Customizable for rust users)

bundler: namespaced imports (#1109)#

entry.ts:

import * as a from "./a.ts";
console.log(a);

a.ts:

export const a = "a";

is now bundled as

const a = (function () {
const a = "a";
return {
a,
};
})();
console.log(a);

bundler: namedspaced reexports (#1110)#

Namespaced export statements like

export * as c from "./c.ts";

is now properly handled.

bundler: shorthand properties (#1111)#

Bundler had a bug related to shorthand properties. But it's now fixed, and

entry.ts:

import { d } from "./d.ts";
console.log(d);

d.ts:

import { a } from "./a.ts";
export const d = { a }; // This was problematic

a.ts:

export const a = "a";

is compiled as

const a = "a";
const d = {
a: "a",
};
console.log(d);

bundler: top level await (#1112)#

As deno supports top level await, I added support for it to the bundler.