fix(compiler): reject dynamic api access in client functions
Usage-driven emission can only see api.<name> calls. api["name"]() or passing api to a helper is invisible to it, silently drops the block from the browser bundle, and fails at runtime instead of build time. Detect that dynamic/indirect use (masking strings and comments first, reusing the tokenizer's skipLiteralOrComment) and refuse to compile instead, naming the offending function.
This commit is contained in:
@@ -58,3 +58,43 @@ test("declared field types never reach the browser module", () => {
|
||||
|
||||
expect(browser).not.toContain("name?: string");
|
||||
});
|
||||
|
||||
test("dynamic bracket access on api is a compile error naming the construct", () => {
|
||||
expect(() => generateTargets(parse(withCalls(` await api["used"]({ name: "a" })`)))).toThrow(
|
||||
/api/,
|
||||
);
|
||||
});
|
||||
|
||||
test("passing api to a helper is a compile error", () => {
|
||||
expect(() => generateTargets(parse(withCalls(` callHelper(api)`)))).toThrow(/api/);
|
||||
});
|
||||
|
||||
test("a plain api.name(...) call still compiles", () => {
|
||||
expect(() =>
|
||||
generateTargets(parse(withCalls(` await api.used({ name: "a" })`))),
|
||||
).not.toThrow();
|
||||
});
|
||||
|
||||
test("an identifier that merely contains 'api' does not trigger the dynamic-access error", () => {
|
||||
expect(() =>
|
||||
generateTargets(
|
||||
parse(
|
||||
withCalls(
|
||||
` const rapidCheck = 1; this.apiary = rapidCheck; await api.used({ name: "a" })`,
|
||||
),
|
||||
),
|
||||
),
|
||||
).not.toThrow();
|
||||
});
|
||||
|
||||
test("the word 'api' inside a comment or string literal does not trigger the dynamic-access error", () => {
|
||||
expect(() =>
|
||||
generateTargets(
|
||||
parse(
|
||||
withCalls(
|
||||
` // this mentions api in a comment\n const note = "the api is great";\n await api.used({ name: "a" })`,
|
||||
),
|
||||
),
|
||||
),
|
||||
).not.toThrow();
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user