243 lines
7.1 KiB
TypeScript
243 lines
7.1 KiB
TypeScript
import assert from "assert";
|
|
import { parse } from "../lib/parser";
|
|
import { Printer } from "../lib/printer";
|
|
import * as types from "ast-types";
|
|
const n = types.namedTypes;
|
|
const b = types.builders;
|
|
import { EOL as eol } from "os";
|
|
|
|
describe("ES6 Compatability", function () {
|
|
function convertShorthandMethod() {
|
|
const printer = new Printer({ tabWidth: 2 });
|
|
|
|
const code = [
|
|
"var name='test-name';",
|
|
"var shorthandObj = {",
|
|
" name,",
|
|
" func() { return 'value'; }",
|
|
"};",
|
|
].join(eol);
|
|
|
|
const ast = parse(code);
|
|
n.VariableDeclaration.assert(ast.program.body[1]);
|
|
|
|
const shorthandObjDec = ast.program.body[1].declarations[0].init;
|
|
const methodDecProperty = shorthandObjDec.properties[1];
|
|
const newES5MethodProperty = b.property(
|
|
methodDecProperty.kind,
|
|
methodDecProperty.key,
|
|
methodDecProperty.value,
|
|
);
|
|
|
|
const correctMethodProperty = b.property(
|
|
methodDecProperty.kind,
|
|
methodDecProperty.key,
|
|
b.functionExpression(
|
|
methodDecProperty.value.id,
|
|
methodDecProperty.value.params,
|
|
methodDecProperty.value.body,
|
|
methodDecProperty.value.generator,
|
|
methodDecProperty.value.expression,
|
|
),
|
|
);
|
|
|
|
assert.strictEqual(
|
|
printer.print(newES5MethodProperty).code,
|
|
printer.print(correctMethodProperty).code,
|
|
);
|
|
}
|
|
|
|
it(
|
|
"correctly converts from a shorthand method to ES5 function",
|
|
convertShorthandMethod,
|
|
);
|
|
|
|
function respectDestructuringAssignment() {
|
|
const printer = new Printer({ tabWidth: 2 });
|
|
const code = "var {a} = {};";
|
|
const ast = parse(code);
|
|
n.VariableDeclaration.assert(ast.program.body[0]);
|
|
assert.strictEqual(printer.print(ast).code, code);
|
|
}
|
|
|
|
it("respects destructuring assignments", respectDestructuringAssignment);
|
|
});
|
|
|
|
describe("import/export syntax", function () {
|
|
const printer = new Printer({ tabWidth: 2 });
|
|
|
|
function check(source: string) {
|
|
const ast1 = parse(source);
|
|
const ast2 = parse(printer.printGenerically(ast1).code);
|
|
types.astNodesAreEquivalent.assert(ast1, ast2);
|
|
}
|
|
|
|
it("should parse and print import statements correctly", function () {
|
|
check("import foo from 'foo'");
|
|
|
|
// default imports
|
|
check("import foo from 'foo';");
|
|
check("import {default as foo} from 'foo';");
|
|
|
|
// named imports
|
|
check("import {bar} from 'foo';");
|
|
check("import {bar, baz} from 'foo';");
|
|
check("import {bar as baz} from 'foo';");
|
|
check("import {bar as baz, xyz} from 'foo';");
|
|
|
|
// glob imports
|
|
check("import * as foo from 'foo';");
|
|
|
|
// mixing imports
|
|
check("import foo, {baz as xyz} from 'foo';");
|
|
check("import foo, * as bar from 'foo';");
|
|
|
|
// just import
|
|
check("import 'foo';");
|
|
});
|
|
|
|
it("should parse and print export statements correctly", function () {
|
|
// default exports
|
|
check("export default 42;");
|
|
check("export default {};");
|
|
check("export default [];");
|
|
check("export default foo;");
|
|
check("export default function () {}");
|
|
check("export default class {}");
|
|
check("export default function foo () {}");
|
|
check("export default class foo {}");
|
|
check("export default `hello world`");
|
|
|
|
// variables exports
|
|
check("export var foo = 1;");
|
|
check("export var foo = function () {};");
|
|
check("export var bar;"); // lazy initialization
|
|
check("export let foo = 2;");
|
|
check("export let bar;"); // lazy initialization
|
|
check("export const foo = 3;");
|
|
check("export function foo () {}");
|
|
check("export class foo {}");
|
|
|
|
// named exports
|
|
check("export {foo};");
|
|
check("export {foo, bar};");
|
|
check("export {foo as bar};");
|
|
check("export {foo as default};");
|
|
check("export {foo as default, bar};");
|
|
|
|
// exports from
|
|
check("export * from 'foo';");
|
|
check("export {foo} from 'foo';");
|
|
check("export {foo, bar} from 'foo';");
|
|
check("export {foo as bar} from 'foo';");
|
|
check("export {foo as default} from 'foo';");
|
|
check("export {foo as default, bar} from 'foo';");
|
|
check("export {default} from 'foo';");
|
|
check("export {default as foo} from 'foo';");
|
|
});
|
|
|
|
it("should forbid invalid import/export syntax", function () {
|
|
function checkInvalid(source: string, expectedMessage: string) {
|
|
try {
|
|
parse(source);
|
|
throw new Error(
|
|
"Parsing should have failed: " + JSON.stringify(source),
|
|
);
|
|
} catch (err: any) {
|
|
assert.strictEqual(err.message, "Line 1: " + expectedMessage);
|
|
}
|
|
}
|
|
|
|
// const variables must have an initializer
|
|
checkInvalid(
|
|
"export const bar;",
|
|
"Missing initializer in const declaration",
|
|
);
|
|
|
|
// Unexpected token identifier, invalid named export syntax
|
|
checkInvalid("export foo;", "Unexpected identifier");
|
|
|
|
// Unexpected token (, use a function declaration instead
|
|
checkInvalid("export function () {}", "Unexpected token (");
|
|
|
|
// Unexpected token default
|
|
checkInvalid("export function default () {}", "Unexpected token default");
|
|
|
|
// Missing from after import
|
|
checkInvalid("import foo;", "Unexpected token ;");
|
|
|
|
// Missing from after import
|
|
checkInvalid("import { foo, bar };", "Unexpected token ;");
|
|
|
|
// Invalid module specifier
|
|
checkInvalid("import foo from bar;", "Unexpected token");
|
|
|
|
// Unexpected token default
|
|
checkInvalid("import default from 'foo';", "Unexpected token default");
|
|
|
|
// Unexpected token from
|
|
checkInvalid("export default from 'foo';", "Unexpected token from");
|
|
|
|
// Missing from after export
|
|
checkInvalid("export {default};", "Unexpected token ;");
|
|
|
|
// Missing from after export
|
|
checkInvalid("export *;", "Unexpected token ;");
|
|
|
|
// Missing from after import
|
|
checkInvalid("import {default as foo};", "Unexpected token ;");
|
|
|
|
// Missing as after import *
|
|
checkInvalid("import * from 'foo';", "Unexpected token");
|
|
|
|
// Unexpected token =
|
|
checkInvalid("export default = 42;", "Unexpected token =");
|
|
|
|
// Unexpected token default
|
|
checkInvalid(
|
|
"import {bar as default} from 'foo';",
|
|
"Unexpected token default",
|
|
);
|
|
|
|
// Unexpected token ,
|
|
checkInvalid(
|
|
"import foo, * as bar, {baz as xyz} from 'foo';",
|
|
"Unexpected token ,",
|
|
);
|
|
|
|
// Unexpected token ,
|
|
checkInvalid("import {bar}, foo from 'foo';", "Unexpected token ,");
|
|
|
|
// Unexpected token ,
|
|
checkInvalid("import {bar}, * as foo from 'foo';", "Unexpected token ,");
|
|
|
|
// Unexpected token ,
|
|
checkInvalid("import foo, {bar}, foo from 'foo';", "Unexpected token ,");
|
|
|
|
// Unexpected token ,
|
|
checkInvalid("import {bar}, {foo} from 'foo';", "Unexpected token ,");
|
|
|
|
// Unexpected token ,
|
|
checkInvalid(
|
|
"import * as bar, {baz as xyz} from 'foo';",
|
|
"Unexpected token ,",
|
|
);
|
|
});
|
|
|
|
it("should pretty-print template strings with backticks", function () {
|
|
const code = [
|
|
'var noun = "fool";',
|
|
"var s = `I am a ${noun}`;",
|
|
"var t = tag`You said: ${s}!`;",
|
|
].join(eol);
|
|
|
|
const ast = parse(code);
|
|
|
|
assert.strictEqual(
|
|
new Printer({
|
|
tabWidth: 2,
|
|
}).printGenerically(ast).code,
|
|
code,
|
|
);
|
|
});
|
|
});
|