diff --git a/changelog_unreleased/api/12574.md b/changelog_unreleased/api/12574.md new file mode 100644 index 000000000..1738f233a --- /dev/null +++ b/changelog_unreleased/api/12574.md @@ -0,0 +1,7 @@ +#### [BREAKING] Change public apis to asynchronous (#12574 by @fisker) + +- `prettier.format()` returns `Promise` +- `prettier.formatWithCursor()` returns `Promise<{formatted: string, cursorOffset: number}>` +- `prettier.check()` returns `Promise` + +More changes are coming... diff --git a/docs/api.md b/docs/api.md index 57462399b..d4097ec19 100644 --- a/docs/api.md +++ b/docs/api.md @@ -14,13 +14,13 @@ const prettier = require("prettier"); `format` is used to format text using Prettier. `options.parser` must be set according to the language you are formatting (see the [list of available parsers](options.md#parser)). Alternatively, `options.filepath` can be specified for Prettier to infer the parser from the file extension. Other [options](options.md) may be provided to override the defaults. ```js -prettier.format("foo ( );", { semi: false, parser: "babel" }); +await prettier.format("foo ( );", { semi: false, parser: "babel" }); // -> "foo()" ``` ## `prettier.check(source [, options])` -`check` checks to see if the file has been formatted with Prettier given those options and returns a `Boolean`. This is similar to the `--check` or `--list-different` parameter in the CLI and is useful for running Prettier in CI scenarios. +`check` checks to see if the file has been formatted with Prettier given those options and returns a `Promise`. This is similar to the `--check` or `--list-different` parameter in the CLI and is useful for running Prettier in CI scenarios. ## `prettier.formatWithCursor(source [, options])` @@ -29,7 +29,7 @@ prettier.format("foo ( );", { semi: false, parser: "babel" }); The `cursorOffset` option should be provided, to specify where the cursor is. This option cannot be used with `rangeStart` and `rangeEnd`. ```js -prettier.formatWithCursor(" 1", { cursorOffset: 2, parser: "babel" }); +await prettier.formatWithCursor(" 1", { cursorOffset: 2, parser: "babel" }); // -> { formatted: '1;\n', cursorOffset: 1 } ``` diff --git a/src/cli/file-info.js b/src/cli/file-info.js index 4f037bab4..0573a8f45 100644 --- a/src/cli/file-info.js +++ b/src/cli/file-info.js @@ -20,7 +20,7 @@ async function logFileInfoOrDie(context) { resolveConfig: config !== false, }); - printToScreen(prettier.format(stringify(fileInfo), { parser: "json" })); + printToScreen(await prettier.format(stringify(fileInfo), { parser: "json" })); } export default logFileInfoOrDie; diff --git a/src/cli/format.js b/src/cli/format.js index 6a42ba810..e8cbea6a2 100644 --- a/src/cli/format.js +++ b/src/cli/format.js @@ -74,7 +74,7 @@ function writeOutput(context, result, options) { } } -function listDifferent(context, input, options, filename) { +async function listDifferent(context, input, options, filename) { if (!context.argv.check && !context.argv.listDifferent) { return; } @@ -85,7 +85,7 @@ function listDifferent(context, input, options, filename) { "No parser and no file path given, couldn't infer a parser." ); } - if (!prettier.check(input, options)) { + if (!(await prettier.check(input, options))) { if (!context.argv.write) { context.logger.log(filename); process.exitCode = 1; @@ -117,13 +117,15 @@ async function format(context, input, opt) { if (context.argv.debugPrintDoc) { const doc = prettier.__debug.printToDoc(input, opt); - return { formatted: prettier.__debug.formatDoc(doc) + "\n" }; + return { formatted: (await prettier.__debug.formatDoc(doc)) + "\n" }; } if (context.argv.debugPrintComments) { return { - formatted: prettier.format( - JSON.stringify(prettier.formatWithCursor(input, opt).comments || []), + formatted: await prettier.format( + JSON.stringify( + (await prettier.formatWithCursor(input, opt)).comments || [] + ), { parser: "json" } ), }; @@ -137,8 +139,8 @@ async function format(context, input, opt) { } if (context.argv.debugCheck) { - const pp = prettier.format(input, opt); - const pppp = prettier.format(pp, opt); + const pp = await prettier.format(input, opt); + const pppp = await prettier.format(pp, opt); if (pp !== pppp) { throw new errors.DebugError( "prettier(input) !== prettier(prettier(input))\n" + @@ -187,22 +189,28 @@ async function format(context, input, opt) { "'--debug-benchmark' option found, measuring formatWithCursor with 'benchmark' module." ); const suite = new benchmark.Suite(); - suite - .add("format", () => { - prettier.formatWithCursor(input, opt); - }) - .on("cycle", (event) => { - const results = { - benchmark: String(event.target), - hz: event.target.hz, - ms: event.target.times.cycle * 1000, - }; - context.logger.debug( - "'--debug-benchmark' measurements for formatWithCursor: " + - JSON.stringify(results, null, 2) - ); - }) - .run({ async: false }); + suite.add("format", { + defer: true, + async fn(deferred) { + await prettier.formatWithCursor(input, opt); + deferred.resolve(); + }, + }); + const result = await new Promise((resolve) => { + suite + .on("complete", (event) => { + resolve({ + benchmark: String(event.target), + hz: event.target.hz, + ms: event.target.times.cycle * 1000, + }); + }) + .run({ async: false }); + }); + context.logger.debug( + "'--debug-benchmark' measurements for formatWithCursor: " + + JSON.stringify(result, null, 2) + ); } else if (context.argv.debugRepeat > 0) { const repeat = context.argv.debugRepeat; context.logger.debug( @@ -214,7 +222,7 @@ async function format(context, input, opt) { for (let i = 0; i < repeat; ++i) { // should be using `performance.now()`, but only `Date` is cross-platform enough const startMs = Date.now(); - prettier.formatWithCursor(input, opt); + await prettier.formatWithCursor(input, opt); totalMs += Date.now() - startMs; } const averageMs = totalMs / repeat; @@ -269,7 +277,7 @@ async function formatStdin(context) { const options = await getOptionsForFile(context, filepath); - if (listDifferent(context, input, options, "(stdin)")) { + if (await listDifferent(context, input, options, "(stdin)")) { return; } diff --git a/src/cli/index.js b/src/cli/index.js index 4b4424739..d27825b3b 100644 --- a/src/cli/index.js +++ b/src/cli/index.js @@ -79,7 +79,7 @@ async function main(rawArguments, logger) { if (context.argv.supportInfo) { printToScreen( - prettier.format(stringify(prettier.getSupportInfo()), { + await prettier.format(stringify(prettier.getSupportInfo()), { parser: "json", }) ); diff --git a/src/index.js b/src/index.js index 3d6f03d45..0a057ccc8 100644 --- a/src/index.js +++ b/src/index.js @@ -68,12 +68,13 @@ const formatWithCursor = withPlugins(core.formatWithCursor); const prettier = { formatWithCursor, - format(text, opts) { - return formatWithCursor(text, opts).formatted; + async format(text, opts) { + const { formatted } = await formatWithCursor(text, opts); + return formatted; }, - check(text, opts) { - const { formatted } = formatWithCursor(text, opts); + async check(text, opts) { + const { formatted } = await formatWithCursor(text, opts); return formatted === text; }, diff --git a/src/main/core.js b/src/main/core.js index 0f2fa24e5..4820f6640 100644 --- a/src/main/core.js +++ b/src/main/core.js @@ -275,7 +275,8 @@ function hasPragma(text, options) { return !selectedParser.hasPragma || selectedParser.hasPragma(text); } -function formatWithCursor(originalText, originalOptions) { +// eslint-disable-next-line require-await +async function formatWithCursor(originalText, originalOptions) { let { hasBOM, text, options } = normalizeInputAndOptions( originalText, normalizeOptions(originalOptions) @@ -341,11 +342,14 @@ const prettier = { }, // Doesn't handle shebang for now - formatDoc(doc, options) { - return formatWithCursor(printDocToDebug(doc), { + async formatDoc(doc, options) { + const text = printDocToDebug(doc); + const { formatted } = await formatWithCursor(text, { ...options, parser: "__js_expression", - }).formatted; + }); + + return formatted; }, printToDoc(originalText, options) { diff --git a/src/standalone.js b/src/standalone.js index 7aec3f8be..cb77d319a 100644 --- a/src/standalone.js +++ b/src/standalone.js @@ -33,12 +33,13 @@ const formatWithCursor = withPlugins(core.formatWithCursor); const prettierStandalone = { formatWithCursor, - format(text, opts) { - return formatWithCursor(text, opts).formatted; + async format(text, opts) { + const { formatted } = await formatWithCursor(text, opts); + return formatted; }, - check(text, opts) { - const { formatted } = formatWithCursor(text, opts); + async check(text, opts) { + const { formatted } = await formatWithCursor(text, opts); return formatted === text; }, diff --git a/tests/config/format-test.js b/tests/config/format-test.js index c52f9672c..8925b4b60 100644 --- a/tests/config/format-test.js +++ b/tests/config/format-test.js @@ -12,7 +12,7 @@ const { __dirname } = createEsmUtils(import.meta); let prettier; -const { FULL_TEST } = process.env; +const { FULL_TEST, TEST_STANDALONE } = process.env; const BOM = "\uFEFF"; const CURSOR_PLACEHOLDER = "<|>"; @@ -119,6 +119,19 @@ const isTestDirectory = (dirname, name) => path.join(__dirname, "../format", name) + path.sep ); +const ensurePromise = (value) => { + const isPromise = TEST_STANDALONE + ? // In standalone test, promise is from another context + Object.prototype.toString.call(value) === "[object Promise]" + : value instanceof Promise; + + if (!isPromise) { + throw new TypeError("Expected value to be a 'Promise'."); + } + + return value; +}; + function runSpec(fixtures, parsers, options) { let { importMeta, snippets = [] } = fixtures.importMeta ? fixtures @@ -462,7 +475,6 @@ const insertCursor = (text, cursorOffset) => CURSOR_PLACEHOLDER + text.slice(cursorOffset) : text; -// eslint-disable-next-line require-await async function format(originalText, originalOptions) { const { text: input, options } = replacePlaceholders( originalText, @@ -470,9 +482,8 @@ async function format(originalText, originalOptions) { ); const inputWithCursor = insertCursor(input, options.cursorOffset); - const { formatted: output, cursorOffset } = prettier.formatWithCursor( - input, - options + const { formatted: output, cursorOffset } = await ensurePromise( + prettier.formatWithCursor(input, options) ); const outputWithCursor = insertCursor(output, cursorOffset); const eolVisualizedOutput = visualizeEndOfLine(outputWithCursor); diff --git a/tests/format/js/cursor/jsfmt.spec.js b/tests/format/js/cursor/jsfmt.spec.js index 6e284dc1f..8294ec943 100644 --- a/tests/format/js/cursor/jsfmt.spec.js +++ b/tests/format/js/cursor/jsfmt.spec.js @@ -5,36 +5,36 @@ const { prettier } = run_spec; run_spec(import.meta, ["babel", "typescript", "flow"]); -test("translates cursor correctly in basic case", () => { +test("translates cursor correctly in basic case", async () => { expect( - prettier.formatWithCursor(" 1", { parser: "babel", cursorOffset: 2 }) + await prettier.formatWithCursor(" 1", { parser: "babel", cursorOffset: 2 }) ).toMatchObject({ formatted: "1;\n", cursorOffset: 1, }); }); -test("positions cursor relative to closest node, not SourceElement", () => { +test("positions cursor relative to closest node, not SourceElement", async () => { const code = "return 15"; expect( - prettier.formatWithCursor(code, { parser: "babel", cursorOffset: 15 }) + await prettier.formatWithCursor(code, { parser: "babel", cursorOffset: 15 }) ).toMatchObject({ formatted: "return 15;\n", cursorOffset: 7, }); }); -test("keeps cursor inside formatted node", () => { +test("keeps cursor inside formatted node", async () => { const code = "return 15"; expect( - prettier.formatWithCursor(code, { parser: "babel", cursorOffset: 14 }) + await prettier.formatWithCursor(code, { parser: "babel", cursorOffset: 14 }) ).toMatchObject({ formatted: "return 15;\n", cursorOffset: 7, }); }); -test("doesn't insert second placeholder for nonexistent TypeAnnotation", () => { +test("doesn't insert second placeholder for nonexistent TypeAnnotation", async () => { const code = "\n" + outdent` @@ -43,7 +43,7 @@ test("doesn't insert second placeholder for nonexistent TypeAnnotation", () => { }) `; expect( - prettier.formatWithCursor(code, { parser: "babel", cursorOffset: 24 }) + await prettier.formatWithCursor(code, { parser: "babel", cursorOffset: 24 }) ).toMatchObject({ formatted: outdent` @@ -55,11 +55,11 @@ test("doesn't insert second placeholder for nonexistent TypeAnnotation", () => { }); }); -test("cursorOffset === rangeStart", () => { +test("cursorOffset === rangeStart", async () => { const code = "1.0000\n2.0000\n3.0000"; expect( - prettier.formatWithCursor(code, { + await prettier.formatWithCursor(code, { parser: "babel", cursorOffset: 7, rangeStart: 7, diff --git a/tests/integration/__tests__/bundle.js b/tests/integration/__tests__/bundle.js index 52371b6d0..cb8723406 100644 --- a/tests/integration/__tests__/bundle.js +++ b/tests/integration/__tests__/bundle.js @@ -52,9 +52,9 @@ describe("standalone", () => { }); for (const parser of parserNames) { - test(parser, () => { + test(parser, async () => { const input = codeSamples(parser); - const umdOutput = standalone.format(input, { + const umdOutput = await standalone.format(input, { parser, plugins, }); @@ -63,7 +63,7 @@ describe("standalone", () => { expect(typeof umdOutput).toBe("string"); expect(umdOutput).not.toBe(input); - const esmOutput = esmStandalone.format(input, { + const esmOutput = await esmStandalone.format(input, { parser, plugins: esmPlugins, }); diff --git a/tests/integration/__tests__/debug-api.js b/tests/integration/__tests__/debug-api.js index 74b2eab59..2ca99d135 100644 --- a/tests/integration/__tests__/debug-api.js +++ b/tests/integration/__tests__/debug-api.js @@ -36,28 +36,28 @@ describe("API", () => { done(); }); - const formatResultFromDoc = formatDoc(doc, options); - test("prettier.formatDoc", () => { - expect(formatResultFromDoc).toMatchSnapshot(); - }); - const { formatted: stringFromDoc } = printDocToString(doc, options); test("prettier.printDocToString", () => { expect(stringFromDoc).toBe(formatted); }); - const doc2 = new Function( - `{ ${Object.keys(builders)} }`, - `return ${formatResultFromDoc}` - )(builders); - const { formatted: stringFromDoc2 } = printDocToString(doc2, options); - const formatResultFromDoc2 = formatDoc(doc2, options); - test("output of prettier.formatDoc can be reused as code", () => { + test("prettier.formatDoc", async () => { + const formatResultFromDoc = await formatDoc(doc, options); + expect(formatResultFromDoc).toMatchSnapshot(); + + const doc2 = new Function( + `{ ${Object.keys(builders)} }`, + `return ${formatResultFromDoc}` + )(builders); + + const { formatted: stringFromDoc2 } = printDocToString(doc2, options); expect(stringFromDoc2).toBe(formatted); + + const formatResultFromDoc2 = await formatDoc(doc2, options); expect(formatResultFromDoc2).toBe(formatResultFromDoc); }); - test("prettier.formatDoc prints things as expected", () => { + test("prettier.formatDoc prints things as expected", async () => { const { indent, hardline, @@ -70,31 +70,31 @@ describe("API", () => { label, } = builders; - expect(formatDoc([indent(hardline), indent(literalline)])).toBe( + expect(await formatDoc([indent(hardline), indent(literalline)])).toBe( "[indent(hardline), indent(literalline)]" ); - expect(formatDoc(fill(["foo", hardline, "bar", literalline, "baz"]))).toBe( - 'fill(["foo", hardline, "bar", literalline, "baz"])' - ); + expect( + await formatDoc(fill(["foo", hardline, "bar", literalline, "baz"])) + ).toBe('fill(["foo", hardline, "bar", literalline, "baz"])'); expect( - formatDoc( + await formatDoc( // The argument of fill must not be passed to cleanDoc because it's not a doc fill(cleanDoc(["foo", literalline, "bar"])) // invalid fill ) ).toBe('fill(["foo", literallineWithoutBreakParent, breakParent, "bar"])'); expect( - formatDoc(indentIfBreak(group(["1", line, "2"]), { groupId: "Q" })) + await formatDoc(indentIfBreak(group(["1", line, "2"]), { groupId: "Q" })) ).toBe('indentIfBreak(group(["1", line, "2"]), { groupId: "Q" })'); - expect(formatDoc(label("foo", group(["1", line, "2"])))).toBe( + expect(await formatDoc(label("foo", group(["1", line, "2"])))).toBe( 'label("foo", group(["1", line, "2"]))' ); - expect(formatDoc([ifBreak("a", "b"), ifBreak("a"), ifBreak("", "b")])).toBe( - '[ifBreak("a", "b"), ifBreak("a"), ifBreak("", "b")]' - ); + expect( + await formatDoc([ifBreak("a", "b"), ifBreak("a"), ifBreak("", "b")]) + ).toBe('[ifBreak("a", "b"), ifBreak("a"), ifBreak("", "b")]'); }); }); diff --git a/tests/integration/__tests__/format.js b/tests/integration/__tests__/format.js index f4090be0f..9d878e7fd 100644 --- a/tests/integration/__tests__/format.js +++ b/tests/integration/__tests__/format.js @@ -2,17 +2,17 @@ import prettier from "prettier-local"; import { outdent } from "outdent"; import fooPlugin from "../plugins/defaultOptions/plugin.cjs"; -test("yaml parser should handle CRLF correctly", () => { +test("yaml parser should handle CRLF correctly", async () => { const input = "a:\r\n 123\r\n"; expect( // use JSON.stringify to observe CRLF JSON.stringify( - prettier.format(input, { parser: "yaml", endOfLine: "auto" }) + await prettier.format(input, { parser: "yaml", endOfLine: "auto" }) ) ).toMatchSnapshot(); }); -test("typescript parser should throw the first error when both JSX and non-JSX mode failed", () => { +test("typescript parser should throw the first error when both JSX and non-JSX mode failed", async () => { const input = outdent` import React from "react"; @@ -23,43 +23,46 @@ test("typescript parser should throw the first error when both JSX and non-JSX m label: `; - expect(() => + await expect( prettier.format(input, { parser: "typescript" }) - ).toThrowErrorMatchingSnapshot(); + ).rejects.toThrowErrorMatchingSnapshot(); }); -test("html parser should handle CRLF correctly", () => { +test("html parser should handle CRLF correctly", async () => { const input = ""; expect( // use JSON.stringify to observe CRLF JSON.stringify( - prettier.format(input, { parser: "html", endOfLine: "auto" }) + await prettier.format(input, { parser: "html", endOfLine: "auto" }) ) ).toMatchSnapshot(); }); -test("markdown parser should handle CRLF correctly", () => { +test("markdown parser should handle CRLF correctly", async () => { const input = "```\r\n\r\n\r\n```"; expect( // use JSON.stringify to observe CRLF JSON.stringify( - prettier.format(input, { parser: "markdown", endOfLine: "auto" }) + await prettier.format(input, { parser: "markdown", endOfLine: "auto" }) ) ).toMatchSnapshot(); }); -test("should work with foo plugin instance", () => { +test("should work with foo plugin instance", async () => { const input = "a:\r\n 123\r\n"; expect( JSON.stringify( - prettier.format(input, { parser: "foo-parser", plugins: [fooPlugin] }) + await prettier.format(input, { + parser: "foo-parser", + plugins: [fooPlugin], + }) ) ).toMatchInlineSnapshot('""{\\"tabWidth\\":8,\\"bracketSpacing\\":false}""'); }); -test("'Adjacent JSX' error should not be swallowed by Babel's error recovery", () => { +test("'Adjacent JSX' error should not be swallowed by Babel's error recovery", async () => { const input = "\n"; - expect(() => + await expect( prettier.format(input, { parser: "babel" }) - ).toThrowErrorMatchingSnapshot(); + ).rejects.toThrowErrorMatchingSnapshot(); }); diff --git a/tests/integration/__tests__/infer-parser.js b/tests/integration/__tests__/infer-parser.js index 96f828b75..a4aa3e87f 100644 --- a/tests/integration/__tests__/infer-parser.js +++ b/tests/integration/__tests__/infer-parser.js @@ -179,14 +179,14 @@ describe("API with no path and no parser", () => { global.console = _console; }); - test("prettier.format", () => { - expect(prettier.format(" foo ( )")).toBe("foo();\n"); + test("prettier.format", async () => { + expect(await prettier.format(" foo ( )")).toBe("foo();\n"); expect(global.console.warn).toHaveBeenCalledTimes(1); expect(global.console.warn.mock.calls[0]).toMatchSnapshot(); }); - test("prettier.check", () => { - expect(prettier.check(" foo ( )")).toBe(false); + test("prettier.check", async () => { + expect(await prettier.check(" foo ( )")).toBe(false); expect(global.console.warn).toHaveBeenCalledTimes(1); expect(global.console.warn.mock.calls[0]).toMatchSnapshot(); }); diff --git a/tests/integration/__tests__/line-suffix-boundary.js b/tests/integration/__tests__/line-suffix-boundary.js index 9ab96c6e5..c1cf8773e 100644 --- a/tests/integration/__tests__/line-suffix-boundary.js +++ b/tests/integration/__tests__/line-suffix-boundary.js @@ -7,7 +7,7 @@ const { group, indent, line, lineSuffix, lineSuffixBoundary, softline } = prettier.doc.builders; describe("lineSuffixBoundary", () => { - test("should be correctly treated as a potential line break in `fits`", () => { + test("should be correctly treated as a potential line break in `fits`", async () => { const doc = group([ "let foo = [", indent([ @@ -30,6 +30,6 @@ describe("lineSuffixBoundary", () => { ]; `; - expect(printDoc(doc)).toBe(expected); + expect(await printDoc(doc)).toBe(expected); }); }); diff --git a/tests/integration/__tests__/parser-api.js b/tests/integration/__tests__/parser-api.js index 1d0665e46..500c9256a 100644 --- a/tests/integration/__tests__/parser-api.js +++ b/tests/integration/__tests__/parser-api.js @@ -1,8 +1,8 @@ import prettier from "prettier-local"; import runPrettier from "../run-prettier.js"; -test("allows custom parser provided as object", () => { - const output = prettier.format("1", { +test("allows custom parser provided as object", async () => { + const output = await prettier.format("1", { parser(text) { expect(text).toBe("1"); return { @@ -15,8 +15,8 @@ test("allows custom parser provided as object", () => { expect(output).toBe("2"); }); -test("allows usage of prettier's supported parsers", () => { - const output = prettier.format("foo ( )", { +test("allows usage of prettier's supported parsers", async () => { + const output = await prettier.format("foo ( )", { parser(text, parsers) { expect(typeof parsers.babel).toBe("function"); const ast = parsers.babel(text); @@ -27,10 +27,10 @@ test("allows usage of prettier's supported parsers", () => { expect(output).toBe("bar();\n"); }); -test("parsers should allow omit optional arguments", () => { +test("parsers should allow omit optional arguments", async () => { let parsers; try { - prettier.format("{}", { + await prettier.format("{}", { parser(text, builtinParsers) { parsers = builtinParsers; }, @@ -54,8 +54,8 @@ test("parsers should allow omit optional arguments", () => { } }); -test("allows add empty `trailingComments` array", () => { - const output = prettier.format("(foo /* comment */)( )", { +test("allows add empty `trailingComments` array", async () => { + const output = await prettier.format("(foo /* comment */)( )", { parser(text, parsers) { const ast = parsers.babel(text); diff --git a/tests/integration/__tests__/with-parser-inference.js b/tests/integration/__tests__/with-parser-inference.js index eddeb2f28..93e0f97df 100644 --- a/tests/integration/__tests__/with-parser-inference.js +++ b/tests/integration/__tests__/with-parser-inference.js @@ -21,33 +21,37 @@ describe("infers postcss parser with --list-different", () => { }); describe("infers parser from filename", () => { - test("json from .prettierrc", () => { - expect(prettier.format(" { } ", { filepath: "x/y/.prettierrc" })).toBe( - "{}\n" - ); - }); - - test("json from .stylelintrc", () => { - expect(prettier.format(" { } ", { filepath: "x/y/.stylelintrc" })).toBe( - "{}\n" - ); - }); - - test("yaml from .stylelintrc", () => { + test("json from .prettierrc", async () => { expect( - prettier.format(" extends: '' ", { filepath: "x/y/.stylelintrc" }) + await prettier.format(" { } ", { filepath: "x/y/.prettierrc" }) + ).toBe("{}\n"); + }); + + test("json from .stylelintrc", async () => { + expect( + await prettier.format(" { } ", { filepath: "x/y/.stylelintrc" }) + ).toBe("{}\n"); + }); + + test("yaml from .stylelintrc", async () => { + expect( + await prettier.format(" extends: '' ", { + filepath: "x/y/.stylelintrc", + }) ).toBe('extends: ""\n'); }); - test("babel from Jakefile", () => { + test("babel from Jakefile", async () => { expect( - prettier.format("let foo = ( x = 1 ) => x", { filepath: "x/y/Jakefile" }) + await prettier.format("let foo = ( x = 1 ) => x", { + filepath: "x/y/Jakefile", + }) ).toBe("let foo = (x = 1) => x;\n"); }); - test("json from .swcrc", () => { + test("json from .swcrc", async () => { expect( - prettier.format( + await prettier.format( /* indent */ ` { "jsc": { diff --git a/website/playground/PrettierFormat.js b/website/playground/PrettierFormat.js index 18263cf1e..84694fe84 100644 --- a/website/playground/PrettierFormat.js +++ b/website/playground/PrettierFormat.js @@ -26,7 +26,7 @@ export default class PrettierFormat extends React.Component { } } - format() { + async format() { const { worker, code, @@ -37,9 +37,13 @@ export default class PrettierFormat extends React.Component { reformat, } = this.props; - worker - .format(code, options, { ast, doc, comments, reformat }) - .then((result) => this.setState(result)); + const result = await worker.format(code, options, { + ast, + doc, + comments, + reformat, + }); + this.setState(result); } render() { diff --git a/website/playground/index.js b/website/playground/index.js index 67d42705a..5be5d1ea3 100644 --- a/website/playground/index.js +++ b/website/playground/index.js @@ -15,13 +15,13 @@ class App extends React.Component { this.worker = new WorkerApi("/worker.js"); } - componentDidMount() { - this.worker.getMetadata().then(({ supportInfo, version }) => { - this.setState({ - loaded: true, - availableOptions: supportInfo.options.map(augmentOption), - version: fixPrettierVersion(version), - }); + async componentDidMount() { + const { supportInfo, version } = await this.worker.getMetadata(); + + this.setState({ + loaded: true, + availableOptions: supportInfo.options.map(augmentOption), + version: fixPrettierVersion(version), }); } diff --git a/website/static/worker.js b/website/static/worker.js index 18e423b56..0988563c7 100644 --- a/website/static/worker.js +++ b/website/static/worker.js @@ -30,10 +30,10 @@ for (const file in parsersLocation) { } } -self.onmessage = function (event) { +self.onmessage = async function (event) { self.postMessage({ uid: event.data.uid, - message: handleMessage(event.data.message), + message: await handleMessage(event.data.message), }); }; @@ -50,7 +50,7 @@ function serializeAst(ast) { ); } -function handleMessage(message) { +async function handleMessage(message) { if (message.type === "meta") { return { type: "meta", @@ -75,7 +75,7 @@ function handleMessage(message) { const plugins = [{ parsers }]; options.plugins = plugins; - const formatResult = formatCode(message.code, options); + const formatResult = await formatCode(message.code, options); const response = { formatted: formatResult.formatted, @@ -99,7 +99,7 @@ function handleMessage(message) { if (!errored) { try { - ast = formatCode(ast, { parser: "json", plugins }).formatted; + ast = (await formatCode(ast, { parser: "json", plugins })).formatted; } catch { ast = serializeAst(ast); } @@ -109,7 +109,7 @@ function handleMessage(message) { if (message.debug.doc) { try { - response.debug.doc = prettier.__debug.formatDoc( + response.debug.doc = await prettier.__debug.formatDoc( prettier.__debug.printToDoc(message.code, options), { parser: "babel", plugins } ); @@ -119,16 +119,17 @@ function handleMessage(message) { } if (message.debug.comments) { - response.debug.comments = formatCode( - JSON.stringify(formatResult.comments || []), - { parser: "json", plugins } + response.debug.comments = ( + await formatCode(JSON.stringify(formatResult.comments || []), { + parser: "json", + plugins, + }) ).formatted; } if (message.debug.reformat) { - response.debug.reformatted = formatCode( - response.formatted, - options + response.debug.reformatted = ( + await formatCode(response.formatted, options) ).formatted; } @@ -136,9 +137,9 @@ function handleMessage(message) { } } -function formatCode(text, options) { +async function formatCode(text, options) { try { - return prettier.formatWithCursor(text, options); + return await prettier.formatWithCursor(text, options); } catch (e) { if (e.constructor && e.constructor.name === "SyntaxError") { // Likely something wrong with the user's code