Add babel-plugin-syntax-typescript, babel-plugin-transform-typescript, and babel-preset-typescript (#5899)
* Add babel-plugin-syntax-typescript and babel-plugin-transform-typescript * Add babel-preset-typescript * Remove unnecessary handler for JSXOpeningElement * Use `t.isFoo(node)` instead of `node.type === "Foo"` * Clean up parameter property assignment generation * Don't use function for `isSuperCall` * slice -> shift * Calculate sourceFileHasJsx only if necessary * Remove `export =` support * remove some syntax readme newlines [skip ci]
This commit is contained in:
parent
66ec5263a4
commit
e37a5eb5eb
2
packages/babel-plugin-syntax-typescript/.npmignore
Normal file
2
packages/babel-plugin-syntax-typescript/.npmignore
Normal file
@ -0,0 +1,2 @@
|
||||
node_modules
|
||||
src
|
||||
33
packages/babel-plugin-syntax-typescript/README.md
Normal file
33
packages/babel-plugin-syntax-typescript/README.md
Normal file
@ -0,0 +1,33 @@
|
||||
# babel-plugin-syntax-typescript
|
||||
|
||||
## Installation
|
||||
|
||||
```sh
|
||||
npm install --save-dev babel-plugin-syntax-typescript
|
||||
```
|
||||
|
||||
## Usage
|
||||
|
||||
### Via `.babelrc` (Recommended)
|
||||
|
||||
**.babelrc**
|
||||
|
||||
```json
|
||||
{
|
||||
"plugins": ["syntax-typescript"]
|
||||
}
|
||||
```
|
||||
|
||||
### Via CLI
|
||||
|
||||
```sh
|
||||
babel --plugins syntax-typescript script.js
|
||||
```
|
||||
|
||||
### Via Node API
|
||||
|
||||
```javascript
|
||||
require("babel-core").transform("code", {
|
||||
plugins: ["syntax-typescript"]
|
||||
});
|
||||
```
|
||||
14
packages/babel-plugin-syntax-typescript/package.json
Normal file
14
packages/babel-plugin-syntax-typescript/package.json
Normal file
@ -0,0 +1,14 @@
|
||||
{
|
||||
"name": "babel-plugin-syntax-typescript",
|
||||
"version": "7.0.0-alpha.17",
|
||||
"description": "Allow parsing of TypeScript syntax",
|
||||
"repository": "https://github.com/babel/babel/tree/master/packages/babel-plugin-syntax-typescript",
|
||||
"license": "MIT",
|
||||
"main": "lib/index.js",
|
||||
"keywords": [
|
||||
"babel-plugin",
|
||||
"typescript"
|
||||
],
|
||||
"dependencies": {},
|
||||
"devDependencies": {}
|
||||
}
|
||||
7
packages/babel-plugin-syntax-typescript/src/index.js
Normal file
7
packages/babel-plugin-syntax-typescript/src/index.js
Normal file
@ -0,0 +1,7 @@
|
||||
export default function() {
|
||||
return {
|
||||
manipulateOptions(opts, parserOpts) {
|
||||
parserOpts.plugins.push("typescript");
|
||||
},
|
||||
};
|
||||
}
|
||||
3
packages/babel-plugin-transform-typescript/.npmignore
Normal file
3
packages/babel-plugin-transform-typescript/.npmignore
Normal file
@ -0,0 +1,3 @@
|
||||
.gitignore
|
||||
src
|
||||
test
|
||||
54
packages/babel-plugin-transform-typescript/README.md
Normal file
54
packages/babel-plugin-transform-typescript/README.md
Normal file
@ -0,0 +1,54 @@
|
||||
# babel-plugin-transform-typescript
|
||||
|
||||
> Transform [TypeScript](https://github.com/Microsoft/TypeScript) into ES.next.
|
||||
|
||||
Does not type-check its input. For that, you will need to install and set up TypeScript.
|
||||
|
||||
Does not support `namespace`s or `const enum`s because those require type information to transpile.
|
||||
Also does not support `export =` and `import =`, because those cannot be transpiled to ES.next.
|
||||
|
||||
## Example
|
||||
|
||||
**In**
|
||||
|
||||
```javascript
|
||||
const x: number = 0;
|
||||
```
|
||||
|
||||
**Out**
|
||||
|
||||
```javascript
|
||||
const x = 0;
|
||||
```
|
||||
|
||||
## Installation
|
||||
|
||||
```sh
|
||||
npm install --save-dev babel-plugin-transform-typescript
|
||||
```
|
||||
|
||||
## Usage
|
||||
|
||||
### Via `.babelrc` (Recommended)
|
||||
|
||||
**.babelrc**
|
||||
|
||||
```json
|
||||
{
|
||||
"plugins": ["transform-typescript"]
|
||||
}
|
||||
```
|
||||
|
||||
### Via CLI
|
||||
|
||||
```sh
|
||||
babel --plugins transform-typescript script.js
|
||||
```
|
||||
|
||||
### Via Node API
|
||||
|
||||
```javascript
|
||||
require("babel-core").transform("code", {
|
||||
plugins: ["transform-typescript"]
|
||||
});
|
||||
```
|
||||
18
packages/babel-plugin-transform-typescript/package.json
Normal file
18
packages/babel-plugin-transform-typescript/package.json
Normal file
@ -0,0 +1,18 @@
|
||||
{
|
||||
"name": "babel-plugin-transform-typescript",
|
||||
"version": "7.0.0-alpha.17",
|
||||
"description": "Transform TypeScript into ES.next",
|
||||
"repository": "https://github.com/babel/babel/tree/master/packages/babel-plugin-transform-typescript",
|
||||
"license": "MIT",
|
||||
"main": "lib/index.js",
|
||||
"keywords": [
|
||||
"babel-plugin",
|
||||
"typescript"
|
||||
],
|
||||
"dependencies": {
|
||||
"babel-plugin-syntax-typescript": "7.0.0-alpha.17"
|
||||
},
|
||||
"devDependencies": {
|
||||
"babel-helper-plugin-test-runner": "7.0.0-alpha.17"
|
||||
}
|
||||
}
|
||||
206
packages/babel-plugin-transform-typescript/src/enum.js
Normal file
206
packages/babel-plugin-transform-typescript/src/enum.js
Normal file
@ -0,0 +1,206 @@
|
||||
export default function transpileEnum(path, t) {
|
||||
const { node } = path;
|
||||
if (node.declare) {
|
||||
path.remove();
|
||||
return;
|
||||
}
|
||||
|
||||
if (node.const) {
|
||||
throw path.buildCodeFrameError("'const' enums are not supported.");
|
||||
}
|
||||
|
||||
const name = node.id.name;
|
||||
const fill = enumFill(path, t, node.id);
|
||||
|
||||
switch (path.parent.type) {
|
||||
case "BlockStatement":
|
||||
case "Program": {
|
||||
const isGlobal = t.isProgram(path.parent); // && !path.parent.body.some(t.isModuleDeclaration);
|
||||
if (seen(path.parentPath)) {
|
||||
path.replaceWith(fill);
|
||||
} else {
|
||||
path.replaceWithMultiple([
|
||||
makeVar(node.id, t, isGlobal ? "var" : "let"),
|
||||
fill,
|
||||
]);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case "ExportNamedDeclaration": {
|
||||
path.parentPath.insertAfter(fill);
|
||||
if (seen(path.parentPath.parentPath)) {
|
||||
path.remove();
|
||||
} else {
|
||||
path.replaceWith(makeVar(node.id, t, "let"));
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
throw new Error(`Unexpected enum parent '${path.parent.type}`);
|
||||
}
|
||||
|
||||
function seen(parentPath: Path<Node>) {
|
||||
if (parentPath.getData(name)) {
|
||||
return true;
|
||||
} else {
|
||||
parentPath.setData(name, true);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function makeVar(id, t, kind): VariableDeclaration {
|
||||
return t.variableDeclaration(kind, [t.variableDeclarator(id)]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates the statement that fills in the variable declared by the enum.
|
||||
* `(function (E) { ... assignments ... })(E || (E = {}));`
|
||||
*/
|
||||
function enumFill(path, t, id) {
|
||||
const x = translateEnumValues(path, t);
|
||||
const assignments = x.map(([memberName, memberValue]) => {
|
||||
const inner = t.assignmentExpression(
|
||||
"=",
|
||||
t.memberExpression(id, t.stringLiteral(memberName), /*computed*/ true),
|
||||
memberValue,
|
||||
);
|
||||
const outer = t.assignmentExpression(
|
||||
"=",
|
||||
t.memberExpression(id, inner, /*computed*/ true),
|
||||
t.stringLiteral(memberName),
|
||||
);
|
||||
return t.expressionStatement(outer);
|
||||
});
|
||||
|
||||
// E || (E = {})
|
||||
const callArg = t.logicalExpression(
|
||||
"||",
|
||||
id,
|
||||
t.assignmentExpression("=", id, t.objectExpression([])),
|
||||
);
|
||||
const body = t.blockStatement(assignments);
|
||||
const callee = t.functionExpression(null, [id], body);
|
||||
return t.expressionStatement(t.callExpression(callee, [callArg]));
|
||||
}
|
||||
|
||||
/**
|
||||
* Maps the name of an enum member to its value.
|
||||
* We keep track of the previous enum members so you can write code like:
|
||||
* enum E {
|
||||
* X = 1 << 0,
|
||||
* Y = 1 << 1,
|
||||
* Z = X | Y,
|
||||
* }
|
||||
*/
|
||||
type PreviousEnumMembers = { [name: string]: number | typeof undefined };
|
||||
|
||||
function translateEnumValues(path, t) {
|
||||
const seen: PreviousEnumMembers = Object.create(null);
|
||||
// Start at -1 so the first enum member is its increment, 0.
|
||||
let prev: number | typeof undefined = -1;
|
||||
return path.node.members.map(member => {
|
||||
const name = t.isIdentifier(member.id) ? member.id.name : member.id.value;
|
||||
const initializer = member.initializer;
|
||||
let value: Expression;
|
||||
if (initializer) {
|
||||
const constValue = evaluate(initializer, seen);
|
||||
if (constValue !== undefined) {
|
||||
value = t.numericLiteral(constValue);
|
||||
prev = constValue;
|
||||
} else {
|
||||
value = initializer;
|
||||
prev = undefined;
|
||||
}
|
||||
} else {
|
||||
if (prev !== undefined) {
|
||||
prev++;
|
||||
value = t.numericLiteral(prev);
|
||||
} else {
|
||||
throw path.buildCodeFrameError("Enum member must have initializer.");
|
||||
}
|
||||
}
|
||||
|
||||
return [name, value];
|
||||
});
|
||||
}
|
||||
|
||||
// Based on the TypeScript repository's `evalConstant` in `checker.ts`.
|
||||
function evaluate(expr, seen: PreviousEnumMembers) {
|
||||
return evalConstant(expr);
|
||||
|
||||
function evalConstant(expr) {
|
||||
switch (expr.type) {
|
||||
case "UnaryExpression":
|
||||
return evalUnaryExpression(expr);
|
||||
case "BinaryExpression":
|
||||
return evalBinaryExpression(expr);
|
||||
case "NumericLiteral":
|
||||
return expr.value;
|
||||
case "ParenthesizedExpression":
|
||||
return evalConstant(expr.expression);
|
||||
case "Identifier":
|
||||
return seen[expr.name];
|
||||
default:
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
|
||||
function evalUnaryExpression({ argument, operator }) {
|
||||
const value = evalConstant(argument);
|
||||
if (value === undefined) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
switch (operator) {
|
||||
case "+":
|
||||
return value;
|
||||
case "-":
|
||||
return -value;
|
||||
case "~":
|
||||
return ~value;
|
||||
default:
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
|
||||
function evalBinaryExpression(expr) {
|
||||
const left = evalConstant(expr.left);
|
||||
if (left === undefined) {
|
||||
return undefined;
|
||||
}
|
||||
const right = evalConstant(expr.right);
|
||||
if (right === undefined) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
switch (expr.operator) {
|
||||
case "|":
|
||||
return left | right;
|
||||
case "&":
|
||||
return left & right;
|
||||
case ">>":
|
||||
return left >> right;
|
||||
case ">>>":
|
||||
return left >>> right;
|
||||
case "<<":
|
||||
return left << right;
|
||||
case "^":
|
||||
return left ^ right;
|
||||
case "*":
|
||||
return left * right;
|
||||
case "/":
|
||||
return left / right;
|
||||
case "+":
|
||||
return left + right;
|
||||
case "-":
|
||||
return left - right;
|
||||
case "%":
|
||||
return left % right;
|
||||
default:
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
}
|
||||
255
packages/babel-plugin-transform-typescript/src/index.js
Normal file
255
packages/babel-plugin-transform-typescript/src/index.js
Normal file
@ -0,0 +1,255 @@
|
||||
import syntaxTypeScript from "babel-plugin-syntax-typescript";
|
||||
|
||||
import transpileEnum from "./enum";
|
||||
|
||||
function isInType(path) {
|
||||
switch (path.parent.type) {
|
||||
case "TSTypeReference":
|
||||
case "TSQualifiedName":
|
||||
case "TSExpressionWithTypeArguments":
|
||||
case "TSTypeQuery":
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
interface State {
|
||||
programPath: any,
|
||||
}
|
||||
|
||||
export default function({ types: t }) {
|
||||
return {
|
||||
inherits: syntaxTypeScript,
|
||||
visitor: {
|
||||
//"Pattern" alias doesn't include Identifier or RestElement.
|
||||
Pattern: visitPattern,
|
||||
Identifier: visitPattern,
|
||||
RestElement: visitPattern,
|
||||
|
||||
Program(path, state: State) {
|
||||
state.programPath = path;
|
||||
},
|
||||
|
||||
ImportDeclaration(path, state: State) {
|
||||
// Note: this will allow both `import { } from "m"` and `import "m";`.
|
||||
// In TypeScript, the former would be elided.
|
||||
if (path.node.specifiers.length === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
let allElided = true;
|
||||
const importsToRemove: Path<Node>[] = [];
|
||||
|
||||
for (const specifier of path.node.specifiers) {
|
||||
const binding = path.scope.getBinding(specifier.local.name);
|
||||
if (isImportTypeOnly(binding, state.programPath)) {
|
||||
importsToRemove.push(binding.path);
|
||||
} else {
|
||||
allElided = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (allElided) {
|
||||
path.remove();
|
||||
} else {
|
||||
for (const importPath of importsToRemove) {
|
||||
importPath.remove();
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
TSDeclareFunction(path) {
|
||||
path.remove();
|
||||
},
|
||||
|
||||
TSDeclareMethod(path) {
|
||||
path.remove();
|
||||
},
|
||||
|
||||
VariableDeclaration(path) {
|
||||
if (path.node.declare) path.remove();
|
||||
},
|
||||
|
||||
ClassMethod(path) {
|
||||
const { node } = path;
|
||||
|
||||
if (node.accessibility) node.accessibility = null;
|
||||
if (node.abstract) node.abstract = null;
|
||||
if (node.optional) node.optional = null;
|
||||
|
||||
if (node.kind !== "constructor") {
|
||||
return;
|
||||
}
|
||||
|
||||
// Collect parameter properties
|
||||
const parameterProperties = [];
|
||||
for (const param of node.params) {
|
||||
if (param.type === "TSParameterProperty") {
|
||||
parameterProperties.push(param.parameter);
|
||||
}
|
||||
}
|
||||
|
||||
if (!parameterProperties.length) {
|
||||
return;
|
||||
}
|
||||
|
||||
const assigns = parameterProperties.map(p => {
|
||||
let name;
|
||||
if (t.isIdentifier(p)) {
|
||||
name = p.name;
|
||||
} else if (t.isAssignmentPattern(p) && t.isIdentifier(p.left)) {
|
||||
name = p.left.name;
|
||||
} else {
|
||||
throw path.buildCodeFrameError(
|
||||
"Parameter properties can not be destructuring patterns.",
|
||||
);
|
||||
}
|
||||
|
||||
const id = t.identifier(name);
|
||||
const thisDotName = t.memberExpression(t.thisExpression(), id);
|
||||
const assign = t.assignmentExpression("=", thisDotName, id);
|
||||
return t.expressionStatement(assign);
|
||||
});
|
||||
|
||||
const statements = node.body.body;
|
||||
|
||||
const first = statements[0];
|
||||
const startsWithSuperCall =
|
||||
first !== undefined &&
|
||||
t.isExpressionStatement(first) &&
|
||||
t.isCallExpression(first.expression) &&
|
||||
t.isSuper(first.expression.callee);
|
||||
|
||||
// Make sure to put parameter properties *after* the `super` call.
|
||||
// TypeScript will enforce that a 'super()' call is the first statement
|
||||
// when there are parameter properties.
|
||||
node.body.body = startsWithSuperCall
|
||||
? [first, ...assigns, ...statements.slice(1)]
|
||||
: [...assigns, ...statements];
|
||||
|
||||
// Rest handled by Function visitor
|
||||
},
|
||||
|
||||
TSParameterProperty(path) {
|
||||
path.replaceWith(path.node.parameter);
|
||||
},
|
||||
|
||||
ClassProperty(path) {
|
||||
const { node } = path;
|
||||
if (!node.value) {
|
||||
path.remove();
|
||||
return;
|
||||
}
|
||||
|
||||
if (node.accessibility) node.accessibility = null;
|
||||
if (node.abstract) node.abstract = null;
|
||||
if (node.optional) node.optional = null;
|
||||
if (node.typeAnnotation) node.typeAnnotation = null;
|
||||
},
|
||||
|
||||
TSIndexSignature(path) {
|
||||
path.remove();
|
||||
},
|
||||
|
||||
ClassDeclaration(path) {
|
||||
const { node } = path;
|
||||
if (node.declare) {
|
||||
path.remove();
|
||||
return;
|
||||
}
|
||||
if (node.abstract) node.abstract = null;
|
||||
},
|
||||
|
||||
Class({ node }) {
|
||||
if (node.typeParameters) node.typeParameters = null;
|
||||
if (node.superTypeParameters) node.superTypeParameters = null;
|
||||
if (node.implements) node.implements = null;
|
||||
},
|
||||
|
||||
Function({ node }) {
|
||||
if (node.typeParameters) node.typeParameters = null;
|
||||
if (node.returnType) node.returnType = null;
|
||||
|
||||
const p0 = node.params[0];
|
||||
if (p0 && t.isIdentifier(p0) && p0.name === "this") {
|
||||
node.params.shift();
|
||||
}
|
||||
},
|
||||
|
||||
TSModuleDeclaration(path) {
|
||||
if (!path.node.declare && path.node.id.type !== "StringLiteral") {
|
||||
throw path.buildCodeFrameError("Namespaces are not supported.");
|
||||
}
|
||||
path.remove();
|
||||
},
|
||||
|
||||
TSInterfaceDeclaration(path) {
|
||||
path.remove();
|
||||
},
|
||||
|
||||
TSTypeAliasDeclaration(path) {
|
||||
path.remove();
|
||||
},
|
||||
|
||||
TSEnumDeclaration(path) {
|
||||
transpileEnum(path, t);
|
||||
},
|
||||
|
||||
TSImportEqualsDeclaration(path) {
|
||||
throw path.buildCodeFrameError("`import =` is not supported.");
|
||||
},
|
||||
|
||||
TSExportAssignment(path) {
|
||||
throw path.buildCodeFrameError("`export =` is not supported.");
|
||||
},
|
||||
|
||||
TSTypeAssertion(path) {
|
||||
path.replaceWith(path.node.expression);
|
||||
},
|
||||
|
||||
TSAsExpression(path) {
|
||||
path.replaceWith(path.node.expression);
|
||||
},
|
||||
|
||||
TSNonNullExpression(path) {
|
||||
path.replaceWith(path.node.expression);
|
||||
},
|
||||
|
||||
CallExpression(path) {
|
||||
path.node.typeParameters = null;
|
||||
},
|
||||
|
||||
NewExpression(path) {
|
||||
path.node.typeParameters = null;
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
function visitPattern({ node }) {
|
||||
if (node.typeAnnotation) node.typeAnnotation = null;
|
||||
if (t.isIdentifier(node) && node.optional) node.optional = null;
|
||||
// 'access' and 'readonly' are only for parameter properties, so constructor visitor will handle them.
|
||||
}
|
||||
|
||||
function isImportTypeOnly(binding, programPath) {
|
||||
for (const path of binding.referencePaths) {
|
||||
if (!isInType(path)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (binding.identifier.name != "React") {
|
||||
return true;
|
||||
}
|
||||
|
||||
// "React" is referenced as a value if there are any JSX elements in the code.
|
||||
let sourceFileHasJsx = false;
|
||||
programPath.traverse({
|
||||
JSXElement() {
|
||||
sourceFileHasJsx = true;
|
||||
},
|
||||
});
|
||||
return !sourceFileHasJsx;
|
||||
}
|
||||
}
|
||||
1
packages/babel-plugin-transform-typescript/test/fixtures/cast/as-expression/actual.js
vendored
Normal file
1
packages/babel-plugin-transform-typescript/test/fixtures/cast/as-expression/actual.js
vendored
Normal file
@ -0,0 +1 @@
|
||||
x as T;
|
||||
1
packages/babel-plugin-transform-typescript/test/fixtures/cast/as-expression/expected.js
vendored
Normal file
1
packages/babel-plugin-transform-typescript/test/fixtures/cast/as-expression/expected.js
vendored
Normal file
@ -0,0 +1 @@
|
||||
x;
|
||||
1
packages/babel-plugin-transform-typescript/test/fixtures/cast/non-null-assertion/actual.js
vendored
Normal file
1
packages/babel-plugin-transform-typescript/test/fixtures/cast/non-null-assertion/actual.js
vendored
Normal file
@ -0,0 +1 @@
|
||||
x!;
|
||||
1
packages/babel-plugin-transform-typescript/test/fixtures/cast/non-null-assertion/expected.js
vendored
Normal file
1
packages/babel-plugin-transform-typescript/test/fixtures/cast/non-null-assertion/expected.js
vendored
Normal file
@ -0,0 +1 @@
|
||||
x;
|
||||
1
packages/babel-plugin-transform-typescript/test/fixtures/cast/type-assertion/actual.js
vendored
Normal file
1
packages/babel-plugin-transform-typescript/test/fixtures/cast/type-assertion/actual.js
vendored
Normal file
@ -0,0 +1 @@
|
||||
<T> x;
|
||||
1
packages/babel-plugin-transform-typescript/test/fixtures/cast/type-assertion/expected.js
vendored
Normal file
1
packages/babel-plugin-transform-typescript/test/fixtures/cast/type-assertion/expected.js
vendored
Normal file
@ -0,0 +1 @@
|
||||
x;
|
||||
1
packages/babel-plugin-transform-typescript/test/fixtures/class/head/actual.js
vendored
Normal file
1
packages/babel-plugin-transform-typescript/test/fixtures/class/head/actual.js
vendored
Normal file
@ -0,0 +1 @@
|
||||
abstract class C<T> extends D<T> implements I {}
|
||||
1
packages/babel-plugin-transform-typescript/test/fixtures/class/head/expected.js
vendored
Normal file
1
packages/babel-plugin-transform-typescript/test/fixtures/class/head/expected.js
vendored
Normal file
@ -0,0 +1 @@
|
||||
class C extends D {}
|
||||
3
packages/babel-plugin-transform-typescript/test/fixtures/class/index-signature/actual.js
vendored
Normal file
3
packages/babel-plugin-transform-typescript/test/fixtures/class/index-signature/actual.js
vendored
Normal file
@ -0,0 +1,3 @@
|
||||
class C {
|
||||
[s: string]: number;
|
||||
}
|
||||
1
packages/babel-plugin-transform-typescript/test/fixtures/class/index-signature/expected.js
vendored
Normal file
1
packages/babel-plugin-transform-typescript/test/fixtures/class/index-signature/expected.js
vendored
Normal file
@ -0,0 +1 @@
|
||||
class C {}
|
||||
4
packages/babel-plugin-transform-typescript/test/fixtures/class/methods/actual.js
vendored
Normal file
4
packages/babel-plugin-transform-typescript/test/fixtures/class/methods/actual.js
vendored
Normal file
@ -0,0 +1,4 @@
|
||||
class C {
|
||||
m(): void;
|
||||
public m(x?: number, ...y: number[]): void {}
|
||||
}
|
||||
4
packages/babel-plugin-transform-typescript/test/fixtures/class/methods/expected.js
vendored
Normal file
4
packages/babel-plugin-transform-typescript/test/fixtures/class/methods/expected.js
vendored
Normal file
@ -0,0 +1,4 @@
|
||||
class C {
|
||||
m(x, ...y) {}
|
||||
|
||||
}
|
||||
@ -0,0 +1,5 @@
|
||||
class C extends Object {
|
||||
constructor(public x) {
|
||||
super();
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,7 @@
|
||||
class C extends Object {
|
||||
constructor(x) {
|
||||
super();
|
||||
this.x = x;
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,3 @@
|
||||
class C {
|
||||
constructor(public x, public y = 0, public z: number = 0) {}
|
||||
}
|
||||
@ -0,0 +1,8 @@
|
||||
class C {
|
||||
constructor(x, y = 0, z = 0) {
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
this.z = z;
|
||||
}
|
||||
|
||||
}
|
||||
4
packages/babel-plugin-transform-typescript/test/fixtures/class/properties/actual.js
vendored
Normal file
4
packages/babel-plugin-transform-typescript/test/fixtures/class/properties/actual.js
vendored
Normal file
@ -0,0 +1,4 @@
|
||||
class C {
|
||||
public a?: number;
|
||||
private b: number = 0;
|
||||
}
|
||||
3
packages/babel-plugin-transform-typescript/test/fixtures/class/properties/expected.js
vendored
Normal file
3
packages/babel-plugin-transform-typescript/test/fixtures/class/properties/expected.js
vendored
Normal file
@ -0,0 +1,3 @@
|
||||
class C {
|
||||
b = 0;
|
||||
}
|
||||
10
packages/babel-plugin-transform-typescript/test/fixtures/declarations/erased/actual.js
vendored
Normal file
10
packages/babel-plugin-transform-typescript/test/fixtures/declarations/erased/actual.js
vendored
Normal file
@ -0,0 +1,10 @@
|
||||
declare const x: number;
|
||||
declare function f(): void;
|
||||
declare class C {}
|
||||
declare enum E {}
|
||||
declare module "m" {}
|
||||
declare module M {}
|
||||
declare namespace N {}
|
||||
export interface I {}
|
||||
export type T = number;
|
||||
export class C2 {}
|
||||
1
packages/babel-plugin-transform-typescript/test/fixtures/declarations/erased/expected.js
vendored
Normal file
1
packages/babel-plugin-transform-typescript/test/fixtures/declarations/erased/expected.js
vendored
Normal file
@ -0,0 +1 @@
|
||||
export class C2 {}
|
||||
1
packages/babel-plugin-transform-typescript/test/fixtures/enum/const/actual.js
vendored
Normal file
1
packages/babel-plugin-transform-typescript/test/fixtures/enum/const/actual.js
vendored
Normal file
@ -0,0 +1 @@
|
||||
const enum E {}
|
||||
1
packages/babel-plugin-transform-typescript/test/fixtures/enum/const/options.json
vendored
Normal file
1
packages/babel-plugin-transform-typescript/test/fixtures/enum/const/options.json
vendored
Normal file
@ -0,0 +1 @@
|
||||
{ "throws": "'const' enums are not supported." }
|
||||
10
packages/babel-plugin-transform-typescript/test/fixtures/enum/constant-folding/actual.js
vendored
Normal file
10
packages/babel-plugin-transform-typescript/test/fixtures/enum/constant-folding/actual.js
vendored
Normal file
@ -0,0 +1,10 @@
|
||||
enum E {
|
||||
a,
|
||||
b = 2 + 3,
|
||||
c = 2 - 3,
|
||||
d = 2 * 3,
|
||||
e = 2 / 3,
|
||||
f = -1,
|
||||
g = 1 + 2 - 3 * 4 / -5,
|
||||
h,
|
||||
}
|
||||
12
packages/babel-plugin-transform-typescript/test/fixtures/enum/constant-folding/expected.js
vendored
Normal file
12
packages/babel-plugin-transform-typescript/test/fixtures/enum/constant-folding/expected.js
vendored
Normal file
@ -0,0 +1,12 @@
|
||||
var E;
|
||||
|
||||
(function (E) {
|
||||
E[E["a"] = 0] = "a";
|
||||
E[E["b"] = 5] = "b";
|
||||
E[E["c"] = -1] = "c";
|
||||
E[E["d"] = 6] = "d";
|
||||
E[E["e"] = 0.6666666666666666] = "e";
|
||||
E[E["f"] = -1] = "f";
|
||||
E[E["g"] = 5.4] = "g";
|
||||
E[E["h"] = 6.4] = "h";
|
||||
})(E || (E = {}));
|
||||
6
packages/babel-plugin-transform-typescript/test/fixtures/enum/export/actual.js
vendored
Normal file
6
packages/babel-plugin-transform-typescript/test/fixtures/enum/export/actual.js
vendored
Normal file
@ -0,0 +1,6 @@
|
||||
export enum E {
|
||||
A = 1
|
||||
}
|
||||
export enum E {
|
||||
B = 2
|
||||
}
|
||||
9
packages/babel-plugin-transform-typescript/test/fixtures/enum/export/expected.js
vendored
Normal file
9
packages/babel-plugin-transform-typescript/test/fixtures/enum/export/expected.js
vendored
Normal file
@ -0,0 +1,9 @@
|
||||
export let E;
|
||||
|
||||
(function (E) {
|
||||
E[E["A"] = 1] = "A";
|
||||
})(E || (E = {}));
|
||||
|
||||
(function (E) {
|
||||
E[E["B"] = 2] = "B";
|
||||
})(E || (E = {}));
|
||||
4
packages/babel-plugin-transform-typescript/test/fixtures/enum/inferred/actual.js
vendored
Normal file
4
packages/babel-plugin-transform-typescript/test/fixtures/enum/inferred/actual.js
vendored
Normal file
@ -0,0 +1,4 @@
|
||||
enum E {
|
||||
x,
|
||||
y,
|
||||
}
|
||||
6
packages/babel-plugin-transform-typescript/test/fixtures/enum/inferred/expected.js
vendored
Normal file
6
packages/babel-plugin-transform-typescript/test/fixtures/enum/inferred/expected.js
vendored
Normal file
@ -0,0 +1,6 @@
|
||||
var E;
|
||||
|
||||
(function (E) {
|
||||
E[E["x"] = 0] = "x";
|
||||
E[E["y"] = 1] = "y";
|
||||
})(E || (E = {}));
|
||||
@ -0,0 +1,4 @@
|
||||
enum E {
|
||||
a = Math.sin(1),
|
||||
b,
|
||||
}
|
||||
@ -0,0 +1,3 @@
|
||||
{
|
||||
"throws": "Enum member must have initializer."
|
||||
}
|
||||
5
packages/babel-plugin-transform-typescript/test/fixtures/enum/non-scoped/actual.js
vendored
Normal file
5
packages/babel-plugin-transform-typescript/test/fixtures/enum/non-scoped/actual.js
vendored
Normal file
@ -0,0 +1,5 @@
|
||||
enum E {
|
||||
x = 1,
|
||||
"y" = 2,
|
||||
}
|
||||
enum E { z = 3 }
|
||||
10
packages/babel-plugin-transform-typescript/test/fixtures/enum/non-scoped/expected.js
vendored
Normal file
10
packages/babel-plugin-transform-typescript/test/fixtures/enum/non-scoped/expected.js
vendored
Normal file
@ -0,0 +1,10 @@
|
||||
var E;
|
||||
|
||||
(function (E) {
|
||||
E[E["x"] = 1] = "x";
|
||||
E[E["y"] = 2] = "y";
|
||||
})(E || (E = {}));
|
||||
|
||||
(function (E) {
|
||||
E[E["z"] = 3] = "z";
|
||||
})(E || (E = {}));
|
||||
4
packages/babel-plugin-transform-typescript/test/fixtures/enum/scoped/actual.js
vendored
Normal file
4
packages/babel-plugin-transform-typescript/test/fixtures/enum/scoped/actual.js
vendored
Normal file
@ -0,0 +1,4 @@
|
||||
{
|
||||
// Uses 'let' within a scope
|
||||
enum E {}
|
||||
}
|
||||
6
packages/babel-plugin-transform-typescript/test/fixtures/enum/scoped/expected.js
vendored
Normal file
6
packages/babel-plugin-transform-typescript/test/fixtures/enum/scoped/expected.js
vendored
Normal file
@ -0,0 +1,6 @@
|
||||
{
|
||||
// Uses 'let' within a scope
|
||||
let E;
|
||||
|
||||
(function (E) {})(E || (E = {}));
|
||||
}
|
||||
1
packages/babel-plugin-transform-typescript/test/fixtures/exports/export=/actual.js
vendored
Normal file
1
packages/babel-plugin-transform-typescript/test/fixtures/exports/export=/actual.js
vendored
Normal file
@ -0,0 +1 @@
|
||||
export = 0;
|
||||
3
packages/babel-plugin-transform-typescript/test/fixtures/exports/export=/options.json
vendored
Normal file
3
packages/babel-plugin-transform-typescript/test/fixtures/exports/export=/options.json
vendored
Normal file
@ -0,0 +1,3 @@
|
||||
{
|
||||
"throws": "`export =` is not supported."
|
||||
}
|
||||
3
packages/babel-plugin-transform-typescript/test/fixtures/function/overloads/actual.js
vendored
Normal file
3
packages/babel-plugin-transform-typescript/test/fixtures/function/overloads/actual.js
vendored
Normal file
@ -0,0 +1,3 @@
|
||||
function f(): void;
|
||||
function f(): void {
|
||||
}
|
||||
1
packages/babel-plugin-transform-typescript/test/fixtures/function/overloads/expected.js
vendored
Normal file
1
packages/babel-plugin-transform-typescript/test/fixtures/function/overloads/expected.js
vendored
Normal file
@ -0,0 +1 @@
|
||||
function f() {}
|
||||
2
packages/babel-plugin-transform-typescript/test/fixtures/function/parameters/actual.js
vendored
Normal file
2
packages/babel-plugin-transform-typescript/test/fixtures/function/parameters/actual.js
vendored
Normal file
@ -0,0 +1,2 @@
|
||||
function f<T>(x?: T, ...y: T[]): T {}
|
||||
function g(x: number = 0): number {}
|
||||
3
packages/babel-plugin-transform-typescript/test/fixtures/function/parameters/expected.js
vendored
Normal file
3
packages/babel-plugin-transform-typescript/test/fixtures/function/parameters/expected.js
vendored
Normal file
@ -0,0 +1,3 @@
|
||||
function f(x, ...y) {}
|
||||
|
||||
function g(x = 0) {}
|
||||
7
packages/babel-plugin-transform-typescript/test/fixtures/function/this-parameter/actual.js
vendored
Normal file
7
packages/babel-plugin-transform-typescript/test/fixtures/function/this-parameter/actual.js
vendored
Normal file
@ -0,0 +1,7 @@
|
||||
function f(this: {}) {}
|
||||
const o = {
|
||||
m(this: {}) {}
|
||||
};
|
||||
class C {
|
||||
m(this: {}) {}
|
||||
}
|
||||
11
packages/babel-plugin-transform-typescript/test/fixtures/function/this-parameter/expected.js
vendored
Normal file
11
packages/babel-plugin-transform-typescript/test/fixtures/function/this-parameter/expected.js
vendored
Normal file
@ -0,0 +1,11 @@
|
||||
function f() {}
|
||||
|
||||
const o = {
|
||||
m() {}
|
||||
|
||||
};
|
||||
|
||||
class C {
|
||||
m() {}
|
||||
|
||||
}
|
||||
@ -0,0 +1,2 @@
|
||||
import {} from "a";
|
||||
import "b";
|
||||
@ -0,0 +1,2 @@
|
||||
import "a";
|
||||
import "b";
|
||||
3
packages/babel-plugin-transform-typescript/test/fixtures/imports/elide-react-no-2/actual.js
vendored
Normal file
3
packages/babel-plugin-transform-typescript/test/fixtures/imports/elide-react-no-2/actual.js
vendored
Normal file
@ -0,0 +1,3 @@
|
||||
// Don't elide React if a JSX element appears somewhere.
|
||||
import * as React from "react";
|
||||
<div/>;
|
||||
@ -0,0 +1,3 @@
|
||||
// Don't elide React if a JSX element appears somewhere.
|
||||
import * as React from "react";
|
||||
<div />;
|
||||
@ -0,0 +1,3 @@
|
||||
{
|
||||
"plugins": ["syntax-jsx"]
|
||||
}
|
||||
3
packages/babel-plugin-transform-typescript/test/fixtures/imports/elide-react-no/actual.js
vendored
Normal file
3
packages/babel-plugin-transform-typescript/test/fixtures/imports/elide-react-no/actual.js
vendored
Normal file
@ -0,0 +1,3 @@
|
||||
// Don't elide React if a JSX element appears somewhere.
|
||||
import * as React from "react";
|
||||
<div></div>;
|
||||
3
packages/babel-plugin-transform-typescript/test/fixtures/imports/elide-react-no/expected.js
vendored
Normal file
3
packages/babel-plugin-transform-typescript/test/fixtures/imports/elide-react-no/expected.js
vendored
Normal file
@ -0,0 +1,3 @@
|
||||
// Don't elide React if a JSX element appears somewhere.
|
||||
import * as React from "react";
|
||||
<div></div>;
|
||||
3
packages/babel-plugin-transform-typescript/test/fixtures/imports/elide-react-no/options.json
vendored
Normal file
3
packages/babel-plugin-transform-typescript/test/fixtures/imports/elide-react-no/options.json
vendored
Normal file
@ -0,0 +1,3 @@
|
||||
{
|
||||
"plugins": ["syntax-jsx"]
|
||||
}
|
||||
2
packages/babel-plugin-transform-typescript/test/fixtures/imports/elide-react/actual.js
vendored
Normal file
2
packages/babel-plugin-transform-typescript/test/fixtures/imports/elide-react/actual.js
vendored
Normal file
@ -0,0 +1,2 @@
|
||||
import * as React from "react";
|
||||
const x: React.T = 0;
|
||||
1
packages/babel-plugin-transform-typescript/test/fixtures/imports/elide-react/expected.js
vendored
Normal file
1
packages/babel-plugin-transform-typescript/test/fixtures/imports/elide-react/expected.js
vendored
Normal file
@ -0,0 +1 @@
|
||||
const x = 0;
|
||||
2
packages/babel-plugin-transform-typescript/test/fixtures/imports/elide-typeof/actual.js
vendored
Normal file
2
packages/babel-plugin-transform-typescript/test/fixtures/imports/elide-typeof/actual.js
vendored
Normal file
@ -0,0 +1,2 @@
|
||||
import { A } from "mod";
|
||||
const x: typeof A = 0;
|
||||
1
packages/babel-plugin-transform-typescript/test/fixtures/imports/elide-typeof/expected.js
vendored
Normal file
1
packages/babel-plugin-transform-typescript/test/fixtures/imports/elide-typeof/expected.js
vendored
Normal file
@ -0,0 +1 @@
|
||||
const x = 0;
|
||||
6
packages/babel-plugin-transform-typescript/test/fixtures/imports/elision-locations/actual.js
vendored
Normal file
6
packages/babel-plugin-transform-typescript/test/fixtures/imports/elision-locations/actual.js
vendored
Normal file
@ -0,0 +1,6 @@
|
||||
import { A, B, C, D, E, F, G, H } from "m";
|
||||
|
||||
class Class extends A<B> implements C<D> {}
|
||||
interface Iface extends E<F> {}
|
||||
const x: G = 0;
|
||||
const y: H.T = 0;
|
||||
@ -0,0 +1,6 @@
|
||||
import { A } from "m";
|
||||
|
||||
class Class extends A {}
|
||||
|
||||
const x = 0;
|
||||
const y = 0;
|
||||
@ -0,0 +1,2 @@
|
||||
import * as A from "lib";
|
||||
const x: A.B = 0;
|
||||
@ -0,0 +1 @@
|
||||
const x = 0;
|
||||
2
packages/babel-plugin-transform-typescript/test/fixtures/imports/elision-rename/actual.js
vendored
Normal file
2
packages/babel-plugin-transform-typescript/test/fixtures/imports/elision-rename/actual.js
vendored
Normal file
@ -0,0 +1,2 @@
|
||||
import { A as B } from "lib";
|
||||
const x: B = 0;
|
||||
1
packages/babel-plugin-transform-typescript/test/fixtures/imports/elision-rename/expected.js
vendored
Normal file
1
packages/babel-plugin-transform-typescript/test/fixtures/imports/elision-rename/expected.js
vendored
Normal file
@ -0,0 +1 @@
|
||||
const x = 0;
|
||||
7
packages/babel-plugin-transform-typescript/test/fixtures/imports/elision/actual.js
vendored
Normal file
7
packages/babel-plugin-transform-typescript/test/fixtures/imports/elision/actual.js
vendored
Normal file
@ -0,0 +1,7 @@
|
||||
import A, { B, Used } from "lib";
|
||||
import Used2, { C } from "lib";
|
||||
import * as D from "lib";
|
||||
import * as Used3 from "lib";
|
||||
const x: A = Used;
|
||||
const y: B = Used2;
|
||||
const z: C | D = Used3;
|
||||
6
packages/babel-plugin-transform-typescript/test/fixtures/imports/elision/expected.js
vendored
Normal file
6
packages/babel-plugin-transform-typescript/test/fixtures/imports/elision/expected.js
vendored
Normal file
@ -0,0 +1,6 @@
|
||||
import { Used } from "lib";
|
||||
import Used2 from "lib";
|
||||
import * as Used3 from "lib";
|
||||
const x = Used;
|
||||
const y = Used2;
|
||||
const z = Used3;
|
||||
2
packages/babel-plugin-transform-typescript/test/fixtures/imports/import=/actual.js
vendored
Normal file
2
packages/babel-plugin-transform-typescript/test/fixtures/imports/import=/actual.js
vendored
Normal file
@ -0,0 +1,2 @@
|
||||
import lib = require("lib");
|
||||
lib();
|
||||
3
packages/babel-plugin-transform-typescript/test/fixtures/imports/import=/options.json
vendored
Normal file
3
packages/babel-plugin-transform-typescript/test/fixtures/imports/import=/options.json
vendored
Normal file
@ -0,0 +1,3 @@
|
||||
{
|
||||
"throws": "`import =` is not supported."
|
||||
}
|
||||
1
packages/babel-plugin-transform-typescript/test/fixtures/namespace/fails/actual.js
vendored
Normal file
1
packages/babel-plugin-transform-typescript/test/fixtures/namespace/fails/actual.js
vendored
Normal file
@ -0,0 +1 @@
|
||||
namespace N {}
|
||||
3
packages/babel-plugin-transform-typescript/test/fixtures/namespace/fails/options.json
vendored
Normal file
3
packages/babel-plugin-transform-typescript/test/fixtures/namespace/fails/options.json
vendored
Normal file
@ -0,0 +1,3 @@
|
||||
{
|
||||
"throws": "Namespaces are not supported."
|
||||
}
|
||||
3
packages/babel-plugin-transform-typescript/test/fixtures/options.json
vendored
Normal file
3
packages/babel-plugin-transform-typescript/test/fixtures/options.json
vendored
Normal file
@ -0,0 +1,3 @@
|
||||
{
|
||||
"plugins": ["transform-typescript"]
|
||||
}
|
||||
1
packages/babel-plugin-transform-typescript/test/fixtures/type-arguments/call/actual.js
vendored
Normal file
1
packages/babel-plugin-transform-typescript/test/fixtures/type-arguments/call/actual.js
vendored
Normal file
@ -0,0 +1 @@
|
||||
f<T>();
|
||||
1
packages/babel-plugin-transform-typescript/test/fixtures/type-arguments/call/expected.js
vendored
Normal file
1
packages/babel-plugin-transform-typescript/test/fixtures/type-arguments/call/expected.js
vendored
Normal file
@ -0,0 +1 @@
|
||||
f();
|
||||
1
packages/babel-plugin-transform-typescript/test/fixtures/type-arguments/new/actual.js
vendored
Normal file
1
packages/babel-plugin-transform-typescript/test/fixtures/type-arguments/new/actual.js
vendored
Normal file
@ -0,0 +1 @@
|
||||
new C<T>();
|
||||
1
packages/babel-plugin-transform-typescript/test/fixtures/type-arguments/new/expected.js
vendored
Normal file
1
packages/babel-plugin-transform-typescript/test/fixtures/type-arguments/new/expected.js
vendored
Normal file
@ -0,0 +1 @@
|
||||
new C();
|
||||
@ -0,0 +1,3 @@
|
||||
const n: number = 0;
|
||||
const [a, b]: any = 0;
|
||||
const { x, y }: any = 0;
|
||||
@ -0,0 +1,6 @@
|
||||
const n = 0;
|
||||
const [a, b] = 0;
|
||||
const {
|
||||
x,
|
||||
y
|
||||
} = 0;
|
||||
2
packages/babel-plugin-transform-typescript/test/index.js
Normal file
2
packages/babel-plugin-transform-typescript/test/index.js
Normal file
@ -0,0 +1,2 @@
|
||||
import runner from "babel-helper-plugin-test-runner";
|
||||
runner(__dirname);
|
||||
54
packages/babel-preset-typescript/README.md
Normal file
54
packages/babel-preset-typescript/README.md
Normal file
@ -0,0 +1,54 @@
|
||||
# babel-preset-typescript
|
||||
|
||||
> Babel preset for TypeScript.
|
||||
|
||||
This preset includes the following plugins:
|
||||
|
||||
- [transform-typescript](https://babeljs.io/docs/plugins/transform-typescript/)
|
||||
- [syntax-object-rest-spread](https://babeljs.io/docs/plugins/syntax-object-rest-spread/)
|
||||
|
||||
## Example
|
||||
|
||||
**In**
|
||||
|
||||
```javascript
|
||||
const x: number = 0;
|
||||
```
|
||||
|
||||
**Out**
|
||||
|
||||
```javascript
|
||||
const x = 0;
|
||||
```
|
||||
|
||||
## Installation
|
||||
|
||||
```sh
|
||||
npm install --save-dev babel-preset-typescript
|
||||
```
|
||||
|
||||
## Usage
|
||||
|
||||
### Via `.babelrc` (Recommended)
|
||||
|
||||
**.babelrc**
|
||||
|
||||
```json
|
||||
{
|
||||
"presets": ["typescript"]
|
||||
}
|
||||
```
|
||||
|
||||
### Via CLI
|
||||
|
||||
```sh
|
||||
babel --presets typescript script.ts
|
||||
```
|
||||
|
||||
### Via Node API
|
||||
|
||||
```javascript
|
||||
require("babel-core").transform("code", {
|
||||
presets: ["typescript"]
|
||||
});
|
||||
```
|
||||
16
packages/babel-preset-typescript/package.json
Normal file
16
packages/babel-preset-typescript/package.json
Normal file
@ -0,0 +1,16 @@
|
||||
{
|
||||
"name": "babel-preset-typescript",
|
||||
"version": "7.0.0-alpha.17",
|
||||
"description": "Babel preset for TypeScript.",
|
||||
"repository": "https://github.com/babel/babel/tree/master/packages/babel-preset-typescript",
|
||||
"license": "MIT",
|
||||
"main": "lib/index.js",
|
||||
"keywords": [
|
||||
"babel-preset",
|
||||
"typescript"
|
||||
],
|
||||
"dependencies": {
|
||||
"babel-plugin-transform-typescript": "7.0.0-alpha.17",
|
||||
"babel-plugin-syntax-object-rest-spread": "7.0.0-alpha.17"
|
||||
}
|
||||
}
|
||||
8
packages/babel-preset-typescript/src/index.js
Normal file
8
packages/babel-preset-typescript/src/index.js
Normal file
@ -0,0 +1,8 @@
|
||||
import transformTypeScript from "babel-plugin-transform-typescript";
|
||||
import syntaxObjectRestSpread from "babel-plugin-syntax-object-rest-spread";
|
||||
|
||||
export default function() {
|
||||
return {
|
||||
plugins: [transformTypeScript, syntaxObjectRestSpread],
|
||||
};
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user