mirror of
https://github.com/oxc-project/oxc.git
synced 2026-09-14 19:36:11 +08:00
2aedd52ce6
Fixes #20525, (thanks @oxura !) ```sh # Many files that route to the Prettier `formatFile` callback and fail to parse mkdir -p /tmp/repro for i in $(seq 1 500); do printf '<template><div></template>' > /tmp/repro/broken$i.vue; done # Run repeatedly with default concurrency for run in $(seq 1 10); do node apps/oxfmt/dist/cli.js --write /tmp/repro; done ``` Within a few runs it crashes non-deterministically (exit codes varied: 133 / 138 / 139, and sometimes 2 = clean error report), with the same fatal as #20525: ``` # Fatal error in , line 0 # Check failed: object_ != kGlobalHandleZapValue. (or: node->IsInUse()) ... napi_reference_unref <napi::error::Error as ...Drop>::drop core::ptr::drop_in_place<napi::error::Error> oxfmt::core::external_formatter::wrap_format_file::{{closure}} ``` Each broken file makes the `formatFile` callback reject; the resulting `napi::Error` is dropped on the TSFN await path and reaches `napi_reference_unref` during teardown → V8 fatal check. After this fix (callback resolves errors as data), the same workload runs clean.
70 lines
1.8 KiB
TypeScript
70 lines
1.8 KiB
TypeScript
import { describe, expect, it } from "vitest";
|
|
import { format } from "../../dist/index.js";
|
|
|
|
describe("Format non-js", () => {
|
|
it("should format json with options", async () => {
|
|
const jsoncCode = `
|
|
{
|
|
// Package name
|
|
"foo": "my",
|
|
// Trailing comma test
|
|
"bar": "1",
|
|
}
|
|
`.trim();
|
|
const result = await format("foo.jsonc", jsoncCode, {
|
|
insertFinalNewline: false,
|
|
});
|
|
expect(result.code).toBe(`${jsoncCode}`);
|
|
expect(result.errors).toStrictEqual([]);
|
|
});
|
|
|
|
it("should format vue with options", async () => {
|
|
const vueCode = `
|
|
<template><div>Vue</div></template>
|
|
<style>div{color:red;}</style>
|
|
`.trim();
|
|
const result = await format("Component.vue", vueCode, {
|
|
vueIndentScriptAndStyle: true,
|
|
});
|
|
expect(result.code).toBe(
|
|
`
|
|
<template><div>Vue</div></template>
|
|
<style>
|
|
div {
|
|
color: red;
|
|
}
|
|
</style>
|
|
`.trimStart(),
|
|
);
|
|
expect(result.errors).toStrictEqual([]);
|
|
});
|
|
|
|
it("should surface Prettier parse errors as-is", async () => {
|
|
const brokenVue = `<template><div></template>`;
|
|
const result = await format("broken.vue", brokenVue, {});
|
|
|
|
expect(result.code).toBe(brokenVue);
|
|
expect(result.errors[0]?.message).toMatch(/Unexpected closing tag/);
|
|
});
|
|
});
|
|
|
|
describe("Format empty", () => {
|
|
it("should format empty string", async () => {
|
|
let result = await format("empty.js", "", {});
|
|
expect(result.code).toBe("");
|
|
expect(result.errors).toStrictEqual([]);
|
|
|
|
result = await format("empty.toml", " ", {});
|
|
expect(result.code).toBe("");
|
|
expect(result.errors).toStrictEqual([]);
|
|
|
|
result = await format("empty.json", "\n\n", {});
|
|
expect(result.code).toBe("");
|
|
expect(result.errors).toStrictEqual([]);
|
|
|
|
result = await format("empty.md", " \n ", {});
|
|
expect(result.code).toBe("");
|
|
expect(result.errors).toStrictEqual([]);
|
|
});
|
|
});
|