Changelog: swc v1.2.46

Bugfixes#

Enums in namespaces (#1340)#

swc had support for namespaces since v1.2.46. But the support was not complete and enums were not handled properly. v1.2.46 adds support for enums, so the code below works as expected.

namespace Test {
export enum DummyValues {
A = "A",
B = "B",
}
}
console.log(Test.DummyValues.A);

Private class properties (#1353)#

Previously, swc didn't compile some of accesses to private properties of classes. This is fixed as of v1.2.46, by visiting all children in the ast visitor.

Block scoping (#1353)#

Preivously, swc miscompiled some of loops including

function combineOverlappingMatches(matches) {
let hasOverlaps = false;
for (let i = matches.length - 1; i >= 0; i--) {
let currentMatch = matches[i];
let overlap = matches.find((match) => {
return (
match !== currentMatch && match.itemsType === currentMatch.itemsType
);
});
if (overlap) {
hasOverlaps = true;
matches.splice(i, 1);
}
}
if (hasOverlaps) {
combineOverlappingMatches(matches);
}
}
combineOverlappingMatches([1]);

This is now fixed by making block statement transparent in point of view of the block scoping visitor. As this fix applies to all block statements, swc would not break such loops.

This in complex async arrow (#1353)#

Previously, swc errornously changed this in the asynchronous arrow function below.

class A {
val = "1";
async foo() {
try {
return await (async (x) => x + this.val)("a"); // this is undefined
// return await Promise.all(['a', 'b'].map(async (x) => x + this.val)); // this is undefined
} catch (e) {
throw e;
}
}
}
new A().foo();

This is fixed as of v1.2.46. Now swc uses quite general logic for handling such code, and I expect it not to break asynchronous arrows anymore.

bundler: Reserved word as an ident (#1346)#

As the bundler of swc is falttening bundler just like rollup, it had some code to handle difference of identifier context. For example, instanceof in the code below is valid,

import * as foo from "./util";
const x = foo.instanceof;

while instanceof in the code below is invalid.

const instanceof = function () {
// ...
};

The bundler renames instanceof in below to something different, but it had a bug related to object patterns in assignments. This is now fixed and the bundler will not break code using reserved works in object patterns.

New feautres#

Support for legacy decorators on methods with computed keys (#1347)#

swc now supports typescript code like

class Foo {
@dec
[bar]() {}
}

which uses decorator with computed keys.

Support for TypeScript 4.2 (#1330)#

swc now supports parsing and transcompiling typescript 4.2 files.

Changelog: swc v1.2.45

Bugfixes#

Escapes in string literals (#1227)#

This was a regression caused by some works related to span (and sourcemaps). I fixed it and swc can emit es5 code as before.

Panic on aliased reexports (#1307)#

This is a regresssion caused by promoting namespaced re-exports like (export * as foo from 'foo') to es2020 from esnext. This is now fixed.

Private class properties (#1306)#

swc previously miscompiled

class Animal {
readonly #name: string;
constructor(name: string) {
this.#name = name;
}
public noise() {
return this.#name.toUpperCase();
}
}

but now swc compiles it correctly. Actaully the fix was addition of one line.

Preserve imports (#1134)#

This is also a regression, but it's now fixed.

Features#

Support for typescript namespace (#1325)#

swc now supports typescript namespace.

Changelog: swc v1.2.44

Bugfixes#

Various dce bugs (#1301)#

The dead code elimination pass of swc was too aggressive and it broke some code. It's now overly conservative, and I'll improve it over time.

Small bundler rework (#1318)#

The swc project uses very creatitve (and strange) approach to handle scoping issue because rust does not allow two mutable reference to same data. Previously, the bundler of swc tried to do something smart. I patched it to depend on the approach I mentioned and as a result, almost all bugs are fixed.

Changelog: swc v1.2.42

Bugfixes#

bundler: Handle of export * correctly. (#1264)#

Previously the bundler of [swc][] did not exclude default while handling export *. This is wrong and it's fixed. As a result, you can now export default while using export * from './foo'

export { default } from "./foo";
export * from "./foo";

The code above now works.

bundler: Fix statement ordering. (#1264)#

Order of statements are now preserved. Previously, the bundler only considers about dependancy, but it resulted in some bugs so I patched it to preserve original order.

bundler: Group statements from same module. (#1264)#

While flattening all statements, the bundler now prefers statements from same module. It will help debugging the bundle, as related statements live at simillar place.

fixer: Handle assignmnet in new exprssion correctly. (#1264)#

Previously [swc][] errornously removed parenthesis from const a = new (a = b);. It resulted in const a = new a = b;, which has different meaning.

fixer: Handle comma expression in new exprssion correctly. (#1264)#

Previously [swc][] errornously removed parenthesis from const a = new (a, b);. It resulted in const a = new a, b; , which has different meaning. This is now fixed.

bundler: Prevent duplicate variable. (#1296)#

This bug occurrs when export * as foo is mixed with export * from '' more than three times, and with import. It's now fixed and bundler bundles it correctly.

bundler: Handle keywords. (#1296)#

EcmaScript allows using keywords as an identifier in some places. As the bundler flatten statements, it made a variable named instanceof when it met export { foo as instanceof }.

But this is a bug and it's now renamed to something other.

dce: Prevent tags in tagged template literals. (#1296)#

The dce was too aggresive and it removed tagged template literals. It now preserves as tagged template literals can have side effect.

Note:

If you are using some old target, you are not affected.

dce: Handle throw statement correctly. (#1296)#

Again, it errornously removed something used by throw statement. I patched it to mark argument as used correctly.

Changelog: swc v1.2.41

Bugfixes#

Codegen of string literals (#1287)#

The code generator of swc tries to preserve the original input, and it resulted in some bugs. It's now fixed by a huge breaking change - storing quote info in the string literal.

Note that this patch is also included in the new version of deno, which is also published today.

Normalization of \r\n in template literals (#1286)#

Thanks to @Liamolucko, swc now follows spec more closely.

\r\n in template literals are now normlized as \n.

Span of decalred items (#1282)#

Now span of various declared nodes like class declarations or function declarations include span of declare token. Due to how codegen determine codegen print comments, I expect this fix to make codegen print comments correctly.

No hang on invalid character (#1274)#

Previously, the lexer of swc hangs on invalid input. This was because it did not update the position of the character in case of error. The fix was trivial, but it's important for some environments like deno shell, which gets input from stdin.

Parse ?? correctly (#1270)#

Some tokens were not parsed correctly on ecmascript mode.

New package#

I wish this was a package about TypeScript type checkers, but I am still working hard on it still working hard. Instead, we introduce a package that allows swc to run on the web.

@swc/wasm-web is a new package which can be used for the web.

Changelog: swc v1.2.40

Bugfixes#

design;type for typescript enums (#1248)#

Decorator metadata can be used to create very convenient tools. swc now supports it more correctly.

For example, the code below works with swc@1.2.40+.

enum MyEnum {
x = "xxx",
y = "yyy",
}
class Xpto {
@Decorator()
value!: MyEnum;
}
function Decorator() {
return function (...args) {};
}

regenerator: ternary with await (#1228)#

Previously, swc miscompiled the code below because regenerator had a bug.

const source = Math.random() < 2 ? "matilda" : "fred";
const details = {
_id: "1",
};
async function request(path) {
return `success:${path}`;
}
(async () => {
const obj =
source === "matilda"
? details
: await request(`/${details._id}?source=${source}`);
console.log({ obj });
})();

I tried hard to mimic its logic as much as possible, but original codebase depends on dynamic nature of javascript and requires shared &mut, so logic differs even if it's a port.

Anyway, the code above works properly with swc@1.2.40.

bundler: Circular imports in wrapped module (#1234)#

import * as path from "https://deno.land/[email protected]/path/mod.ts";
const { a, ...rest } = { a: 3, b: "bar" };
console.log(a, rest, path);

Previously the swc-based bundlers (deno bundle and spack) had a bug which occurs

  • Module path is loaded as a wrapped module.
  • https://deno.land/[email protected]/path/mod.ts has circular imports internally.

This is now fixed and such code works well.

bundler: export * as alias (#1234)#

I got the bug report from deno issue tracker, and fixed it by preserving export info.

See: https://github.com/denoland/deno/issues/8481

bundler: fix deglobbing logic (#1234)#

Previously, deglobbing logic was to aggressive so that it replaces log.handlers.FileHandler into FileHandler.

It was because previous logic only checked the originating module. This is fixed by comparing symbols.

import * as log from "https://deno.land/std/log/mod.ts";
export async function myCLI(): Promise<void> {
await log.setup({
handlers: {
file: new log.handlers.FileHandler("DEBUG", {
filename: "my.log",
}),
console: new log.handlers.ConsoleHandler("INFO"),
},
loggers: {
default: {
level: "DEBUG",
handlers: ["console", "file"],
},
},
});
log.info("Ok!");
}
if (import.meta.main) {
myCLI();
}

codegen: unicode escape sequnces (#1242)#

There was a bug which ignores the value part in unicode escapes while printing result code.

bundler: importing a module multiple time (#1242)#

import Head from "https://deno.land/x/aleph/head.ts";
import * as Head2 from "https://deno.land/x/aleph/head.ts";
console.log(Head, Head2);

I was a bit curious about the usecase, but I fixed it to be spec-compilant and it works well.

bundler: export default in reexport (#1245)#

Previously the bundler broke code below,

import * as c from "https://deno.land/x/[email protected]/mod.ts";
const s = "one FINE day";
console.log("camel:", c.camelCase(s));

because https://deno.land/x/[email protected]/mod.ts is defined as

export { default as camelCase } from "./camelCase.ts";
export { default as constantCase } from "./constantCase.ts";
export { default as dotCase } from "./dotCase.ts";
export { default as headerCase } from "./headerCase.ts";
export { default as lowerCase } from "./lowerCase.ts";
export { default as lowerFirstCase } from "./lowerFirstCase.ts";
export { default as normalCase } from "./normalCase.ts";
export { default as paramCase } from "./paramCase.ts";
export { default as pascalCase } from "./pascalCase.ts";
export { default as pathCase } from "./pathCase.ts";
export { default as sentenceCase } from "./sentenceCase.ts";
export { default as snakeCase } from "./snakeCase.ts";
export { default as swapCase } from "./swapCase.ts";
export { default as titleCase } from "./titleCase.ts";
export { default as upperCase } from "./upperCase.ts";
export { default as upperFirstCase } from "./upperFirstCase.ts";

The bundler can now handle those kinds of reexports properly.

bundler: export specifiers without alias (#1246)#

Reported with https://github.com/denoland/deno/issues/8573

The bundler didn't handled it because while checking for reexports, the bundler modifies ast so that reexport specifier without alias does not exist. But in some circumstances, the bundler injects export specifiers without alias to maintain semantic of a module.

bundler: improve sorting (#1246)#

Reported with https://github.com/denoland/deno/issues/8574

The bug was that, the code below was not treated as an initializer of globalContext.

if (typeof window !== "undefined") {
globalContext = window;
} else if (typeof self !== "undefined") {
globalContext = self;
} else {
globalContext = {};
}

The fix was trivial as there were already utilities to detect initialization.

bundler: top-level-await flattening (#1246)#

// main.ts
import { log } from "./deps.ts";
await log.setup({});
// deps.ts
export * as log from "./log.ts";
// log.ts
export async function setup() {}
await setup();

This resulted in a bug because the bundler assumed wrapped module is not async.

At first glance, it seems hard to fix, but there's a simple trick.

const log_ts = await(async function () {
export async function setup() {}
await setup();
})();

This fixes the issue.

codegen: multiline jsx texts (#1241)#

Affected code looks like

function Component() {
return React.createElement("div", {
name: "A
BB"
});
}

async_to_generator: async method (#1241)#

class Service {
async is(a: string): Promise<boolean> {
return a.toUpperCase() === a;
}
}

should be

class Service {
is(a) {
return _asyncToGenerator(function* () {
yield Promise.resolve();
return a.toUpperCase() === a;
})();
}
}

but it was transpiled as

class Service {
is(a) {
return _asyncToGenerator(function* (a) {
yield Promise.resolve();
return a.toUpperCase() === a;
})();
}
}

which has wrong a in the parameter. This is fixed by simply removing all parameters.

regenerator: no useless statements (#1241)#

I made a mistake while proting regenerator pass. The mistake resulted in bit larger code, and very hard time debugging.

Now I find the cause of case number being not same as one of regenerator, so future bugs will be easily fixed.

regenerator: track finally properly (#1241)#

Again, regenerator pass depends on shared mutable state hardly, and I made mistake while porting it. Fixing it required some dirty code because we have to modify a value stored in a list after inserting it, but it's in managable range.


Changelog: swc v1.2.39

Bugfixes#

Preserved input (#1221)#

swc now respects the input, and preserves escapes.

Private name in interfaces (#1211)#

swc previously aborted on input like the below. This is changed to normal error.

interface Foo {
#bar();
}

Bundler rework (#1212)#

spack, the bundler of swc project, got a large refactoring and it can now handle almost all valid es codes. As the bundler is also used by deno, the pr contains lots of test for deno.

New features#

BigInt literals as property keys (#1192)#

Thanks to @braddunbar, swc now supports using bigint literal as a key of property.

Changelog: swc v1.2.38

Bugfixes#

Parenthesis with comments (#1203)#

Previously [swc][] miscompiled

function isModuleWrapper(node: Expression) {
return (
// It's an anonymous function expression that wraps module
(node.type === "FunctionExpression" && !node.id) ||
node.type === "ArrowFunctionExpression" ||
isModuleId(node) ||
(node.type === "ArrayExpression" &&
node.elements.length > 1 &&
isModuleId(node.elements[0]))
);
}

as

function isModuleWrapper(node) {
return; // It's an anonymous function expression that wraps module
(node.type === "FunctionExpression" && !node.id) ||
node.type === "ArrowFunctionExpression" ||
isModuleId(node) ||
(node.type === "ArrayExpression" &&
node.elements.length > 1 &&
isModuleId(node.elements[0]));
}

This is now fixed fundamentally. The parenthesis remover pass now checks if a comment exists for inner node.

bundler: Stack overflow / circular imports (#1196, #1205)#

Now dependencies of circular imports of exports are handled correctly and topo sort algorithm is now applied correctly. The pr fixes number of bugs of deno bundle.

bundler: Handle swc helpers (#1199)#

Now if you use bundler with [swc], the helpers of [swc][] will be efficiently emitted.

Caching of import.meta (#1201)#

Thanks to @nayeemrmn, multiple usage of import.meta does not create multiple import.meta object.

resolver: hoist class decls (#1200)#

Although class declarations are not hoisted, it's a top-level item and should be handled before function bodies.

I mean,

(() => {
function foo() {
return new Bar();
}
class Bar {}
})();

should be treated as

(() => {
function foo__1() {
return new Bar__1();
}
class Bar__1 {}
})();

Changelog: swc v1.2.37

Bugfixes#

ascii-only output (#1191)#

Previously [swc] emitted utf-8 output and had some bug related to escape, but[swc] now emits only ascii characters.

error instead of panic (#1170)#

Previously [swc] panicked if the parse is called with the code below.

const toString: (local)(this: Function) => string) = undefined;

This behavior is wrong and [swc] now emits error instead of panicking.

codegen bug of if (#1185)#

Previously [swc] emitted a wrong output for the code below.

if (...) {}
else foo++;

Thanks to @braddunbar, it's now fixed and the generated code works as expected.

typeof helper issue (#1183)#

typeof helper had a bug which occurs in a runtime without Symbol. It's fixed by @wessberg.

invalid escapes in template literals (#1175)#

According to es2018 specification, the code below is valid.

latex`\unicode`;

But previously, [swc] could not parse it. This is now fixed by @braddunbar.

error recoveries (#1189)#

The parser of [swc] can now recover from strict-mode violations.

It means, even if your file has some errors, you can still get ast although it's not valid. As one purpose of [swc] is being a basic building block, this is big win.

dce bug (#1157)#

The dead code elimination pass had a bug related to class properties, and it's now fixed.

Now code like below works well after optimizing.

export interface D {
resolve: any;
reject: any;
}
export function d(): D {
let methods;
const promise = new Promise((resolve, reject) => {
methods = { resolve, reject };
});
return Object.assign(promise, methods);
}

hygiene bug (#1144)#

[swc] had a bug which makes default value in object patterns miscompiled. This is now fixed.

Bundler#

Starting from [deno]@1.5, there's an option --no-check in options of deno bundle. It uses swc_bundler, which is a general implementation of a web asset bundler. While integrating, the [deno] team reported many bugs and those are all fixed.

import and export from a module (#1152)#

Previously the bundler failed to process code below.

import { a as defaultA, O } from "./m.ts";
export { O } from "./m.ts";
interface AOptions {
a?(): void;
c?: O;
}
class A {
#a: () => void;
#c?: O;
constructor(o: AOptions = {}) {
const { a = defaultA, c } = o;
this.#a = a;
this.#c = c;
}
a() {
this.#a();
}
c() {
console.log(this.#c);
}
}
let a = new A();
a.a();
a.c();

This is because there was no logic to handle exports and imports from a module. This is fixed by adding such logic.

computed access to namespace imports (#1159)#

This made https://deno.land/x/[email protected]/examples/server.ts work after bundling.

determinisctic output (#1166)#

For reliability, I made the output of swc_bundler deterministic.

pass ordering (#1171)#

The pass ordering was wrong, and resulted in a bug, which prevents https://deno.land/x/[email protected]/examples/sseServer.ts from working after bundling.

export * (#1154)#

The bundler of [swc] had a bug related to export * where a function or a class is exported. This is fixed by applying same rule as variable exports.

codegen of single arg arrow functions (#1186)#

Thanks to @braddunbar, [swc] now prints arrow function with single arguement properly.

TypeScript 4.1#

as in mapped type (#1151)#

Thanks to @g-plane, the code below now works.

let map: { [P in string as string]: number };

template literal type (#1190)#

Thanks to @g-plane, the code below now works.

type MultiLine = `
some value
`;
type WithTypes = `with-a-${string}`;
type WithTypes2 = `with-a-${MyAlias}-end`;

intrinsic type (#1193)#

Thanks to @g-plane, the code below now works.

let i: intrinsic;
```
[swc]: https://swc.rs
[deno]: https://deno.land