mirror of
https://github.com/hanzoai/babel.git
synced 2026-09-24 16:56:45 +00:00
298 lines
7.1 KiB
JavaScript
298 lines
7.1 KiB
JavaScript
import {
|
|
getPotentiallyBuggyFieldsIndexes,
|
|
getNameOrLengthStaticFieldsIndexes,
|
|
toRanges,
|
|
} from "../lib/util.js";
|
|
|
|
import { parseSync, traverse } from "@babel/core";
|
|
|
|
function classPath(input) {
|
|
let targetPath;
|
|
traverse(parseSync(input, { filename: "example.js", configFile: false }), {
|
|
Class(path) {
|
|
targetPath = path;
|
|
path.stop();
|
|
},
|
|
});
|
|
return targetPath;
|
|
}
|
|
|
|
describe("getPotentiallyBuggyFieldsIndexes", () => {
|
|
const cases = {
|
|
"'name' static field": {
|
|
code: `class A { static name = 2 }`,
|
|
indexes: [0],
|
|
},
|
|
"'length' static field": {
|
|
code: `class A { static length = 2 }`,
|
|
indexes: [0],
|
|
},
|
|
"'name' instance field": {
|
|
code: `class A { name = 2 }`,
|
|
indexes: [],
|
|
},
|
|
"'length' instance field": {
|
|
code: `class A { length = 2 }`,
|
|
indexes: [],
|
|
},
|
|
"'#name' static field": {
|
|
code: `class A { static #name = 2 }`,
|
|
indexes: [],
|
|
},
|
|
"'#length' static field": {
|
|
code: `class A { static #length = 2 }`,
|
|
indexes: [],
|
|
},
|
|
"'name' static field after other elements": {
|
|
code: `class A {
|
|
foo() {}
|
|
bar = 1;
|
|
static baz() {}
|
|
static name = 2
|
|
}`,
|
|
indexes: [3],
|
|
},
|
|
"'length' static field after other elements": {
|
|
code: `class A {
|
|
foo() {}
|
|
bar = 1;
|
|
static baz() {}
|
|
static length = 2
|
|
}`,
|
|
indexes: [3],
|
|
},
|
|
"computed static field": {
|
|
code: `class A {
|
|
static [len];
|
|
}`,
|
|
indexes: [0],
|
|
},
|
|
"static field after static block": {
|
|
code: `class A {
|
|
static safe = 2;
|
|
static { defineReadOnly(A, "unsafe") }
|
|
static unsafe = 3;
|
|
static unsafe2 = 4;
|
|
}`,
|
|
indexes: [2, 3],
|
|
},
|
|
"static field after ref + side effect in private static field": {
|
|
code: `class A {
|
|
static safe = 2;
|
|
static #y = 0;
|
|
static safe2 = 1;
|
|
static #x = defineReadOnly(A, "unsafe");
|
|
static unsafe = 3;
|
|
static unsafe2 = 4;
|
|
}`,
|
|
indexes: [4, 5],
|
|
},
|
|
"static field after ref + side effect in public static field": {
|
|
code: `class A {
|
|
static safe = 2;
|
|
static #y = 0;
|
|
static safe2 = 1;
|
|
static unsafe = defineReadOnly(A, "unsafe");
|
|
static unsafe2 = 3;
|
|
static unsafe3 = 4;
|
|
}`,
|
|
indexes: [3, 4, 5],
|
|
},
|
|
"static field after this + side effect in private static field": {
|
|
code: `class A {
|
|
static safe = 2;
|
|
static #y = 0;
|
|
static safe2 = 1;
|
|
static #x = defineReadOnly(this, "unsafe");
|
|
static unsafe = 3;
|
|
static unsafe2 = 4;
|
|
}`,
|
|
indexes: [4, 5],
|
|
},
|
|
"static field after this + side effect in public static field": {
|
|
code: `class A {
|
|
static safe = 2;
|
|
static #y = 0;
|
|
static safe2 = 1;
|
|
static unsafe = defineReadOnly(this, "unsafe");
|
|
static unsafe2 = 3;
|
|
static unsafe3 = 4;
|
|
}`,
|
|
indexes: [3, 4, 5],
|
|
},
|
|
"static field after side effect in private static field without refs": {
|
|
code: `class A {
|
|
static safe = 2;
|
|
static #y = 0;
|
|
static safe2 = 1;
|
|
static #x = defineReadOnly("unsafe");
|
|
static safe3 = 3;
|
|
}`,
|
|
indexes: [],
|
|
},
|
|
"static field after side effect in public static field without refs": {
|
|
code: `class A {
|
|
static safe = 2;
|
|
static #y = 0;
|
|
static safe2 = 1;
|
|
static safe3 = defineReadOnly("unsafe");
|
|
static safe4 = 3;
|
|
}`,
|
|
indexes: [],
|
|
},
|
|
"static field after refs in private static field without side-effects": {
|
|
code: `class A {
|
|
static safe = 2;
|
|
static #y = 0;
|
|
static safe2 = 1;
|
|
static #x = A;
|
|
static safe3 = 3;
|
|
}`,
|
|
indexes: [],
|
|
},
|
|
"static field after refs in public static field without side-effects": {
|
|
code: `class A {
|
|
static safe = 2;
|
|
static #y = 0;
|
|
static safe2 = A;
|
|
static safe3 = 3;
|
|
}`,
|
|
indexes: [],
|
|
},
|
|
"static field after refs after side effects": {
|
|
code: `class A {
|
|
static safe0 = 0;
|
|
static safe1 = sideEffect();
|
|
static safe2 = 2;
|
|
static unsafe3 = sideEffect(A);
|
|
static unsafe4 = 3;
|
|
}`,
|
|
indexes: [3, 4],
|
|
},
|
|
"static field side effect after refs in computed key": {
|
|
code: `class A {
|
|
static safe0 = 0;
|
|
static unsafe1 = sideEffect(getA());
|
|
static unsage2 = 1;
|
|
static [(getA = () => A, "unsafe3")] = 0;
|
|
}`,
|
|
indexes: [1, 2, 3],
|
|
},
|
|
"complex example": {
|
|
code: `class A {
|
|
static a = 0;
|
|
b() {}
|
|
static name = 2;
|
|
static c = foo();
|
|
static d() {}
|
|
static e = 5;
|
|
f = 6;
|
|
static ["len" + "gth"] = 7;
|
|
static g = 8;
|
|
static h = doSomething(this);
|
|
static i = 10;
|
|
static #j = 11;
|
|
k() {}
|
|
static {}
|
|
static l = 14;
|
|
static m = 15;
|
|
n = 16;
|
|
}`,
|
|
indexes: [2, 7, 9, 10, 14, 15],
|
|
},
|
|
};
|
|
|
|
test.each(Object.keys(cases))("%s", name => {
|
|
const { code, indexes } = cases[name];
|
|
const path = classPath(code);
|
|
|
|
expect(getPotentiallyBuggyFieldsIndexes(path)).toEqual(indexes);
|
|
});
|
|
});
|
|
|
|
describe("getNameOrLengthStaticFieldsIndexes", () => {
|
|
const cases = {
|
|
"'name' static field": {
|
|
code: `class A { static name = 2 }`,
|
|
indexes: [0],
|
|
},
|
|
"'length' static field": {
|
|
code: `class A { static length = 2 }`,
|
|
indexes: [0],
|
|
},
|
|
"'name' instance field": {
|
|
code: `class A { name = 2 }`,
|
|
indexes: [],
|
|
},
|
|
"'length' instance field": {
|
|
code: `class A { length = 2 }`,
|
|
indexes: [],
|
|
},
|
|
"'#name' static field": {
|
|
code: `class A { static #name = 2 }`,
|
|
indexes: [],
|
|
},
|
|
"'#length' static field": {
|
|
code: `class A { static #length = 2 }`,
|
|
indexes: [],
|
|
},
|
|
"'name' static field after other elements": {
|
|
code: `class A {
|
|
foo() {}
|
|
bar = 1;
|
|
static baz() {}
|
|
static name = 2
|
|
}`,
|
|
indexes: [3],
|
|
},
|
|
"'length' static field after other elements": {
|
|
code: `class A {
|
|
foo() {}
|
|
bar = 1;
|
|
static baz() {}
|
|
static length = 2
|
|
}`,
|
|
indexes: [3],
|
|
},
|
|
"computed static field": {
|
|
code: `class A {
|
|
static [foo];
|
|
}`,
|
|
indexes: [],
|
|
},
|
|
"both name and length": {
|
|
code: `class A {
|
|
static name = 0;
|
|
static length = 1;
|
|
}`,
|
|
indexes: [0, 1],
|
|
},
|
|
};
|
|
|
|
test.each(Object.keys(cases))("%s", name => {
|
|
const { code, indexes } = cases[name];
|
|
const path = classPath(code);
|
|
|
|
expect(getNameOrLengthStaticFieldsIndexes(path)).toEqual(indexes);
|
|
});
|
|
});
|
|
|
|
describe("toRanges", () => {
|
|
test.each([
|
|
{ from: [], to: [] },
|
|
{ from: [0], to: [[0, 1]] },
|
|
{ from: [10], to: [[10, 11]] },
|
|
{ from: [2, 3, 4], to: [[2, 5]] },
|
|
{
|
|
from: [2, 3, 6, 7, 8, 10],
|
|
to: [
|
|
[2, 4],
|
|
[6, 9],
|
|
[10, 11],
|
|
],
|
|
},
|
|
])("$from", ({ from, to }) => {
|
|
expect(toRanges(from)).toEqual(to);
|
|
});
|
|
});
|