Test complete
This commit is contained in:
parent
6f28290529
commit
21003af738
45
a.js
Executable file
45
a.js
Executable file
@ -0,0 +1,45 @@
|
|||||||
|
#!/usr/bin/env node
|
||||||
|
const fs = require("fs")
|
||||||
|
const babel = require("@babel/core")
|
||||||
|
|
||||||
|
const code = `
|
||||||
|
export class A {
|
||||||
|
#a: string;
|
||||||
|
}
|
||||||
|
`
|
||||||
|
|
||||||
|
const res = babel.transform(code, {
|
||||||
|
filename: "a.ts",
|
||||||
|
presets: [
|
||||||
|
["@babel/preset-env", { targets: { node: 14 } }],
|
||||||
|
["@babel/preset-typescript"],
|
||||||
|
],
|
||||||
|
plugins: [
|
||||||
|
({ types: t }) => ({
|
||||||
|
visitor: {
|
||||||
|
ClassDeclaration(path, state) {
|
||||||
|
state.a ??= new WeakSet()
|
||||||
|
if (state.a.has(path.node)) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
state.a.add(path.node)
|
||||||
|
|
||||||
|
path.parentPath.replaceWithMultiple([
|
||||||
|
t.exportNamedDeclaration(
|
||||||
|
t.variableDeclaration("let", [
|
||||||
|
t.variableDeclarator(path.node.id, {
|
||||||
|
...path.node,
|
||||||
|
type: "ClassExpression",
|
||||||
|
}),
|
||||||
|
]),
|
||||||
|
[],
|
||||||
|
null
|
||||||
|
),
|
||||||
|
])
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
})
|
||||||
|
|
||||||
|
console.log(res.code)
|
@ -6,11 +6,12 @@
|
|||||||
"scripts": {
|
"scripts": {
|
||||||
"test": "mocha test/**/*.ts",
|
"test": "mocha test/**/*.ts",
|
||||||
"build": "./scripts/build.js",
|
"build": "./scripts/build.js",
|
||||||
"postinstall": "mkdir -p lib; cd test/snapshots && ls | sed \"s/.*/'&'/\" | paste -sd '|' | sed -e \"s/^/export type Snapshot = /\" - > ../snapshots.d.ts"
|
"postinstall": "mkdir -p lib; ./scripts/codegen.js test/snapshots > test/snapshots.d.ts"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@babel/core": "^7.14.8",
|
"@babel/core": "^7.14.8",
|
||||||
"@babel/plugin-transform-modules-commonjs": "^7.14.5",
|
"@babel/plugin-transform-modules-commonjs": "^7.14.5",
|
||||||
|
"@babel/preset-env": "^7.14.8",
|
||||||
"@babel/preset-typescript": "^7.14.5",
|
"@babel/preset-typescript": "^7.14.5",
|
||||||
"@babel/register": "^7.14.5",
|
"@babel/register": "^7.14.5",
|
||||||
"@babel/types": "^7.14.8",
|
"@babel/types": "^7.14.8",
|
||||||
|
993
pnpm-lock.yaml
generated
993
pnpm-lock.yaml
generated
File diff suppressed because it is too large
Load Diff
5
scripts/codegen.js
Executable file
5
scripts/codegen.js
Executable file
@ -0,0 +1,5 @@
|
|||||||
|
#!/usr/bin/env node
|
||||||
|
const fs = require("fs")
|
||||||
|
const [arg] = process.argv.slice(2)
|
||||||
|
const files = fs.readdirSync(arg).filter(name => name[0] !== ".")
|
||||||
|
console.log("export type Snapshot = " + files.map(v => JSON.stringify(v)).join(" | "))
|
50
src/index.ts
50
src/index.ts
@ -50,9 +50,10 @@ export default ({ types: t }: typeof babel): babel.PluginObj<State> => ({
|
|||||||
if (state.visited.has(path.node)) return
|
if (state.visited.has(path.node)) return
|
||||||
state.visited.add(path.node)
|
state.visited.add(path.node)
|
||||||
|
|
||||||
const modifiers: (t.Expression | t.Statement)[] = []
|
const suffix: (t.Expression | t.Statement)[] = []
|
||||||
const classDecorators: t.Expression[] = []
|
const classDecorators: t.Expression[] = []
|
||||||
const prefixes: t.Statement[] = []
|
const prefixes: t.Statement[] = []
|
||||||
|
let replace = true
|
||||||
|
|
||||||
const classID = path.node.id
|
const classID = path.node.id
|
||||||
|
|
||||||
@ -66,9 +67,14 @@ export default ({ types: t }: typeof babel): babel.PluginObj<State> => ({
|
|||||||
|
|
||||||
for (const child of path.node.body.body) {
|
for (const child of path.node.body.body) {
|
||||||
switch (child.type) {
|
switch (child.type) {
|
||||||
|
case "ClassPrivateMethod":
|
||||||
|
case "ClassPrivateProperty":
|
||||||
|
replace = false
|
||||||
|
break
|
||||||
|
|
||||||
case "ClassProperty":
|
case "ClassProperty":
|
||||||
if (!child.decorators) break
|
if (!child.decorators) break
|
||||||
modifiers.push(
|
suffix.push(
|
||||||
t.callExpression(state.__decorate(), [
|
t.callExpression(state.__decorate(), [
|
||||||
t.arrayExpression(child.decorators.map(d => d.expression)),
|
t.arrayExpression(child.decorators.map(d => d.expression)),
|
||||||
child.static
|
child.static
|
||||||
@ -119,7 +125,7 @@ export default ({ types: t }: typeof babel): babel.PluginObj<State> => ({
|
|||||||
|
|
||||||
if (!list.length) break
|
if (!list.length) break
|
||||||
|
|
||||||
modifiers.push(
|
suffix.push(
|
||||||
t.callExpression(state.__decorate(), [
|
t.callExpression(state.__decorate(), [
|
||||||
t.arrayExpression(list),
|
t.arrayExpression(list),
|
||||||
t.memberExpression(classID, t.identifier("prototype")),
|
t.memberExpression(classID, t.identifier("prototype")),
|
||||||
@ -133,16 +139,16 @@ export default ({ types: t }: typeof babel): babel.PluginObj<State> => ({
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!classDecorators.length && !modifiers.length && !prefixes.length) return
|
if (!classDecorators.length && !suffix.length && !prefixes.length) return
|
||||||
|
let replaceWith: t.Statement | undefined
|
||||||
|
|
||||||
const replacees: t.Statement[] = prefixes.slice()
|
|
||||||
if (classDecorators.length) {
|
if (classDecorators.length) {
|
||||||
replacees.push(
|
if (replace) {
|
||||||
t.variableDeclaration("let", [
|
replaceWith = t.variableDeclaration("let", [
|
||||||
t.variableDeclarator(classID, { ...path.node, type: "ClassExpression" }),
|
t.variableDeclarator(classID, { ...path.node, type: "ClassExpression" }),
|
||||||
])
|
])
|
||||||
)
|
}
|
||||||
modifiers.push(
|
suffix.push(
|
||||||
t.assignmentExpression(
|
t.assignmentExpression(
|
||||||
"=",
|
"=",
|
||||||
classID,
|
classID,
|
||||||
@ -154,27 +160,35 @@ export default ({ types: t }: typeof babel): babel.PluginObj<State> => ({
|
|||||||
)
|
)
|
||||||
|
|
||||||
if (isNamedExport) {
|
if (isNamedExport) {
|
||||||
modifiers.push(
|
suffix.push(
|
||||||
t.exportNamedDeclaration(undefined, [t.exportSpecifier(classID, classID)])
|
t.exportNamedDeclaration(undefined, [t.exportSpecifier(classID, classID)])
|
||||||
)
|
)
|
||||||
} else if (isDefaultExport) {
|
} else if (isDefaultExport) {
|
||||||
modifiers.push(t.exportDefaultDeclaration(classID))
|
suffix.push(t.exportDefaultDeclaration(classID))
|
||||||
}
|
}
|
||||||
} else {
|
} else if (replace) {
|
||||||
let node: t.Statement = path.node
|
let node: t.Statement = path.node
|
||||||
if (isNamedExport) {
|
if (isNamedExport) {
|
||||||
node = t.exportNamedDeclaration(node, [], null)
|
node = t.exportNamedDeclaration(node, [], null)
|
||||||
} else if (isDefaultExport) {
|
} else if (isDefaultExport) {
|
||||||
node = t.exportDefaultDeclaration(node)
|
node = t.exportDefaultDeclaration(node)
|
||||||
}
|
}
|
||||||
replacees.push(node)
|
replaceWith = node
|
||||||
}
|
}
|
||||||
|
|
||||||
replacees.push(
|
const pathInContext = isNamedExport || isDefaultExport ? path.parentPath : path
|
||||||
...modifiers.map(e => (t.isStatement(e) ? e : t.expressionStatement(e)))
|
if (prefixes.length) {
|
||||||
)
|
pathInContext.insertBefore(prefixes)
|
||||||
const replacementTarget = isNamedExport || isDefaultExport ? path.parentPath : path
|
}
|
||||||
replacementTarget.replaceWithMultiple(replacees)
|
if (suffix.length) {
|
||||||
|
const nodes = suffix.map(s => (t.isStatement(s) ? s : t.expressionStatement(s)))
|
||||||
|
if (replace) {
|
||||||
|
const [newPath] = pathInContext.replaceWith(replaceWith!)
|
||||||
|
newPath.insertAfter(nodes)
|
||||||
|
} else {
|
||||||
|
pathInContext.insertAfter(nodes)
|
||||||
|
}
|
||||||
|
}
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import { readFileSync } from "fs"
|
import { readFileSync, existsSync } from "fs"
|
||||||
import { describe, it } from "mocha"
|
import { describe, it } from "mocha"
|
||||||
import { resolve } from "path"
|
import { resolve } from "path"
|
||||||
import { expect } from "chai"
|
import { expect } from "chai"
|
||||||
@ -14,13 +14,20 @@ const equal = (name: Snapshot) => {
|
|||||||
const folder = resolve(__dirname, "snapshots", name)
|
const folder = resolve(__dirname, "snapshots", name)
|
||||||
const actual = readFileSync(resolve(folder, "input.txt"), "utf-8")
|
const actual = readFileSync(resolve(folder, "input.txt"), "utf-8")
|
||||||
const expected = readFileSync(resolve(folder, "output.txt"), "utf-8")
|
const expected = readFileSync(resolve(folder, "output.txt"), "utf-8")
|
||||||
|
const babelrc: babel.TransformOptions = existsSync(resolve(folder, ".babelrc"))
|
||||||
|
? JSON.parse(readFileSync(resolve(folder, ".babelrc"), "utf-8"))
|
||||||
|
: {}
|
||||||
|
|
||||||
const transformed = transform(actual, {
|
const transformed = transform(actual, {
|
||||||
parserOpts: {
|
parserOpts: {
|
||||||
|
...babelrc.parserOpts,
|
||||||
plugins: ["decorators-legacy", "typescript"],
|
plugins: ["decorators-legacy", "typescript"],
|
||||||
},
|
},
|
||||||
babelrc: false,
|
babelrc: false,
|
||||||
configFile: false,
|
configFile: false,
|
||||||
|
presets: babelrc.presets,
|
||||||
plugins: [
|
plugins: [
|
||||||
|
...(babelrc.plugins ?? []),
|
||||||
plugin,
|
plugin,
|
||||||
{
|
{
|
||||||
visitor: {
|
visitor: {
|
||||||
@ -52,11 +59,15 @@ describe("tsc-decorator", () => {
|
|||||||
equal("computedProperties")
|
equal("computedProperties")
|
||||||
})
|
})
|
||||||
|
|
||||||
it("works with class/consrtuctor decorators", () => {
|
it("works with class/constructor decorators", () => {
|
||||||
equal("constructor")
|
equal("constructor")
|
||||||
})
|
})
|
||||||
|
|
||||||
it("does not interfere with export declarations", () => {
|
it("does not interfere with export declarations", () => {
|
||||||
equal("exports")
|
equal("exports")
|
||||||
})
|
})
|
||||||
|
|
||||||
|
it("works with private properties", () => {
|
||||||
|
equal("privateProperties")
|
||||||
|
})
|
||||||
})
|
})
|
||||||
|
3
test/snapshots/privateProperties/.babelrc
Normal file
3
test/snapshots/privateProperties/.babelrc
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
{
|
||||||
|
"presets": [["@babel/preset-env", { "targets": { "node": 14 } }]]
|
||||||
|
}
|
4
test/snapshots/privateProperties/input.txt
Normal file
4
test/snapshots/privateProperties/input.txt
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
@Service()
|
||||||
|
export class B {
|
||||||
|
#remote: Service
|
||||||
|
}
|
22
test/snapshots/privateProperties/output.txt
Normal file
22
test/snapshots/privateProperties/output.txt
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
"use strict";
|
||||||
|
Object.defineProperty(exports, "__esModule", {
|
||||||
|
value: true,
|
||||||
|
});
|
||||||
|
|
||||||
|
exports.B = exports.B = void 0;
|
||||||
|
|
||||||
|
var _tslib = require("tslib");
|
||||||
|
var _remote = /*#__PURE__*/ new WeakMap();
|
||||||
|
|
||||||
|
exports.B = exports.B = B = (0, _tslib.__decorate)([Service()], B);
|
||||||
|
|
||||||
|
class B {
|
||||||
|
constructor() {
|
||||||
|
_remote.set(this, {
|
||||||
|
writable: true,
|
||||||
|
value: void 0,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
exports.B = exports.B = B;
|
Loading…
x
Reference in New Issue
Block a user