diff --git a/.eslintrc.cjs b/.eslintrc.cjs index 24af63a4d..d7f520562 100644 --- a/.eslintrc.cjs +++ b/.eslintrc.cjs @@ -325,7 +325,6 @@ module.exports = { path.resolve(__dirname, "src/**"), `!${path.resolve(__dirname, "src/cli/**")}`, `!${path.resolve(__dirname, "src/index.js")}`, - `!${path.resolve(__dirname, "src/common/mockable.js")}`, ], message: "Don't use code from other directory.", }, diff --git a/changelog_unreleased/api/15663.md b/changelog_unreleased/api/15663.md new file mode 100644 index 000000000..29aac10bf --- /dev/null +++ b/changelog_unreleased/api/15663.md @@ -0,0 +1,3 @@ +#### Improve config file search (#15663 by @fisker) + +The Prettier config file search performance has been improved by more effective cache strategy. diff --git a/changelog_unreleased/cli/15533.md b/changelog_unreleased/cli/15533.md new file mode 100644 index 000000000..4af08f62b --- /dev/null +++ b/changelog_unreleased/cli/15533.md @@ -0,0 +1,5 @@ +#### Skip explicitly passed symbolic links with `--no-error-on-unmatched-pattern` (#15533 by @sanmai-NL) + +Since Prettier v3, we stopped following symbolic links, however in some use cases, the symbolic link patterns can't be filtered out, and there is no way to prevent Prettier from throwing errors. + +In Prettier main, you can use `--no-error-on-unmatched-pattern` to simply skip symbolic links. diff --git a/changelog_unreleased/javascript/15756.md b/changelog_unreleased/javascript/15756.md new file mode 100644 index 000000000..7c78449b7 --- /dev/null +++ b/changelog_unreleased/javascript/15756.md @@ -0,0 +1,16 @@ +#### Keep curly braces and `from` keyword in empty `import` statements (#15756 by @fisker) + + +```js +// Input +import { } from 'foo'; +import { /* comment */ } from 'bar'; + +// Prettier stable +import {} from "foo"; +import /* comment */ "bar"; + +// Prettier main +import {} from "foo"; +import {} from /* comment */ "bar"; +``` diff --git a/changelog_unreleased/javascript/15757.md b/changelog_unreleased/javascript/15757.md new file mode 100644 index 000000000..f7bab6bb1 --- /dev/null +++ b/changelog_unreleased/javascript/15757.md @@ -0,0 +1,16 @@ +#### Keep empty import attributes and assertions (#15757 by @fisker) + + +```js +// Input +import foo from "foo" with {}; +import bar from "bar" assert {}; + +// Prettier stable +import foo from "foo"; +import bar from "bar"; + +// Prettier main +import foo from "foo" with {}; +import bar from "bar" assert {}; +``` diff --git a/changelog_unreleased/misc/15750.md b/changelog_unreleased/misc/15750.md new file mode 100644 index 000000000..ebbf8223c --- /dev/null +++ b/changelog_unreleased/misc/15750.md @@ -0,0 +1,3 @@ +#### Fix false claim in docs that cursorOffset is incompatible with rangeStart/rangeEnd (#15750 by @ExplodingCabbage) + +The cursorOffset option has in fact been compatible with rangeStart/rangeEnd for over 5 years, thanks to work by @ds300. However, Prettier's documentation (including the CLI `--help` text) continued to claim otherwise, falsely. The documentation is now fixed. diff --git a/changelog_unreleased/typescript/15718.md b/changelog_unreleased/typescript/15718.md new file mode 100644 index 000000000..008780346 --- /dev/null +++ b/changelog_unreleased/typescript/15718.md @@ -0,0 +1,7 @@ +#### Support "Import Attributes" (#15718 by @fisker) + +[TypeScript 5.3](https://devblogs.microsoft.com/typescript/announcing-typescript-5-3/#import-attributes) supports the latest updates to the [import attributes](https://github.com/tc39/proposal-import-attributes) proposal. + +```tsx +import something from "./something.json" with { type: "json" }; +``` diff --git a/commands.md b/commands.md index f7ca26626..8543ee094 100644 --- a/commands.md +++ b/commands.md @@ -97,6 +97,10 @@ ifBreak(";", " "); `groupId` can be used to check another _already printed_ group instead of the current group. +If a [`hardline`](#hardline) or [`breakParent`](#breakParent) is present within the possible contents, the parent groups will be broken regardless of said content being printed, which might not be desireable. This behaviour is a design limitation. Usually the desired result can be achieved in a different way. + +In the rare case that `hardline` is definitely needed, consider using [`hardlineWithoutBreakParent`](#hardlinewithoutbreakparent-and-literallinewithoutbreakparent) instead to avoid an unwanted group break propagation. + ### `breakParent` ```ts diff --git a/docs/api.md b/docs/api.md index af40bde7e..5d49e8e32 100644 --- a/docs/api.md +++ b/docs/api.md @@ -26,7 +26,7 @@ await prettier.format("foo ( );", { semi: false, parser: "babel" }); `formatWithCursor` both formats the code, and translates a cursor position from unformatted code to formatted code. This is useful for editor integrations, to prevent the cursor from moving when code is formatted. -The `cursorOffset` option should be provided, to specify where the cursor is. This option cannot be used with `rangeStart` and `rangeEnd`. +The `cursorOffset` option should be provided, to specify where the cursor is. ```js await prettier.formatWithCursor(" 1", { cursorOffset: 2, parser: "babel" }); @@ -66,7 +66,7 @@ If `options.editorconfig` is `true` and an [`.editorconfig` file](https://editor The promise will be rejected if there was an error parsing the configuration file. -The search starts at `process.cwd()`, or at `fileUrlOrPath` if provided. Please see the [lilconfig docs](https://github.com/antonk52/lilconfig) for details on how the resolving works. +The search starts at `process.cwd()`, or at the directory of `fileUrlOrPath` if provided. ```js const configFile = await prettier.resolveConfigFile(filePath); diff --git a/docs/configuration.md b/docs/configuration.md index eee65eb8e..5929585c9 100644 --- a/docs/configuration.md +++ b/docs/configuration.md @@ -3,7 +3,7 @@ id: configuration title: Configuration File --- -Prettier uses [lilconfig](https://github.com/antonk52/lilconfig) for configuration file support. This means you can configure Prettier via (in order of precedence): +You can configure Prettier via (in order of precedence): - A `"prettier"` key in your `package.json` file. - A `.prettierrc` file written in JSON or YAML. diff --git a/docs/options.md b/docs/options.md index c2df48f24..c79643c81 100644 --- a/docs/options.md +++ b/docs/options.md @@ -254,8 +254,6 @@ These two options can be used to format code starting and ending at a given char - Backwards to the start of the first line containing the selected statement. - Forwards to the end of the selected statement. -These options cannot be used with `cursorOffset`. - | Default | CLI Override | API Override | | ---------- | --------------------- | ------------------- | | `0` | `--range-start ` | `rangeStart: ` | diff --git a/package.json b/package.json index 371ad4050..45bff8ea3 100644 --- a/package.json +++ b/package.json @@ -31,16 +31,16 @@ ], "dependencies": { "@angular/compiler": "17.0.2", - "@babel/code-frame": "7.22.13", - "@babel/parser": "7.23.4", - "@babel/types": "7.23.3", + "@babel/code-frame": "7.23.5", + "@babel/parser": "7.23.5", + "@babel/types": "7.23.5", "@glimmer/syntax": "0.85.13", "@iarna/toml": "2.2.5", "@prettier/cli": "0.1.5", "@prettier/is-es5-identifier-name": "0.2.0", "@prettier/parse-srcset": "3.1.0", - "@typescript-eslint/typescript-estree": "6.10.0", - "@typescript-eslint/visitor-keys": "6.10.0", + "@typescript-eslint/typescript-estree": "6.13.2", + "@typescript-eslint/visitor-keys": "6.13.2", "acorn": "8.11.2", "acorn-jsx": "5.3.2", "angular-estree-parser": "9.0.0", @@ -61,11 +61,11 @@ "fast-json-stable-stringify": "2.1.0", "file-entry-cache": "7.0.2", "find-cache-dir": "5.0.0", - "flow-parser": "0.222.0", + "flow-parser": "0.223.3", "get-east-asian-width": "1.2.0", "get-stdin": "9.0.0", "graphql": "16.8.1", - "hermes-parser": "0.17.1", + "hermes-parser": "0.18.0", "html-element-attributes": "3.3.0", "html-tag-names": "2.1.0", "html-ua-styles": "0.0.3", @@ -76,7 +76,6 @@ "js-yaml": "4.1.0", "json5": "2.2.3", "leven": "4.0.0", - "lilconfig": "2.1.0", "lines-and-columns": "2.0.4", "linguist-languages": "7.27.0", "mem": "9.0.2", @@ -87,7 +86,7 @@ "outdent": "0.8.0", "parse-json": "8.1.0", "please-upgrade-node": "3.2.0", - "postcss": "8.4.31", + "postcss": "8.4.32", "postcss-less": "6.0.0", "postcss-media-query-parser": "0.2.3", "postcss-scss": "4.0.9", @@ -100,7 +99,7 @@ "sdbm": "2.0.0", "strip-ansi": "7.1.0", "to-fast-properties": "4.0.0", - "typescript": "5.2.2", + "typescript": "5.3.2", "unicode-regex": "4.0.0", "unified": "9.2.2", "url-or-path": "2.3.0", @@ -109,13 +108,13 @@ "yaml-unist-parser": "2.0.1" }, "devDependencies": { - "@babel/generator": "7.23.3", + "@babel/generator": "7.23.5", "@glimmer/reference": "0.85.13", "@types/estree": "1.0.5", "@types/file-entry-cache": "5.0.4", "@types/find-cache-dir": "3.2.1", "@types/jest": "29.5.8", - "@typescript-eslint/eslint-plugin": "6.10.0", + "@typescript-eslint/eslint-plugin": "6.13.2", "benchmark": "2.1.4", "browserslist-to-esbuild": "1.2.0", "c8": "8.0.1", @@ -126,7 +125,7 @@ "esbuild-plugins-node-modules-polyfill": "1.6.1", "esbuild-visualizer": "0.4.1", "eslint": "8.53.0", - "eslint-config-prettier": "9.0.0", + "eslint-config-prettier": "9.1.0", "eslint-formatter-friendly": "7.0.0", "eslint-plugin-compat": "4.2.0", "eslint-plugin-import": "2.29.0", diff --git a/scripts/build/config.js b/scripts/build/config.js index acc6af59d..b351ede2e 100644 --- a/scripts/build/config.js +++ b/scripts/build/config.js @@ -635,17 +635,6 @@ const nodejsFiles = [ external: ["benchmark"], replaceModule: [replaceDiffPackageEntry("lib/patch/create.js")], }, - { - input: "src/common/mockable.js", - outputBaseName: "internal/internal", - replaceModule: [ - { - module: require.resolve("lilconfig"), - find: "exports.lilconfigSync = lilconfigSync;", - replacement: "", - }, - ], - }, ].flatMap((file) => { let { input, output, outputBaseName, ...buildOptions } = file; diff --git a/scripts/build/modify-typescript-module.js b/scripts/build/modify-typescript-module.js index 5fe145562..043a09a7d 100644 --- a/scripts/build/modify-typescript-module.js +++ b/scripts/build/modify-typescript-module.js @@ -198,6 +198,13 @@ function modifyTypescriptModule(text) { } } + // server + for (const module of source.modules) { + if (module.path.startsWith("src/server/")) { + source.removeModule(module); + } + } + // `transformers` source.removeModule("src/compiler/transformer.ts"); for (const module of source.modules) { @@ -268,6 +275,9 @@ function modifyTypescriptModule(text) { `, ); + // `pnp` + source.removeModule("src/compiler/pnp.ts"); + /* spell-checker: disable */ // `ts.createParenthesizerRules` source.replaceAlignedCode({ diff --git a/src/cli/expand-patterns.js b/src/cli/expand-patterns.js index 2b7085ddb..d0b786181 100644 --- a/src/cli/expand-patterns.js +++ b/src/cli/expand-patterns.js @@ -69,9 +69,15 @@ async function* expandPatternsInternal(context) { const stat = await lstatSafe(absolutePath); if (stat) { if (stat.isSymbolicLink()) { - yield { - error: `Explicitly specified pattern "${pattern}" is a symbolic link.`, - }; + if (context.argv.errorOnUnmatchedPattern !== false) { + yield { + error: `Explicitly specified pattern "${pattern}" is a symbolic link.`, + }; + } else { + context.logger.debug( + `Skipping pattern "${pattern}", as it is a symbolic link.`, + ); + } } else if (stat.isFile()) { entries.push({ type: "file", diff --git a/src/cli/format.js b/src/cli/format.js index 69eb0ef59..6f313f3b6 100644 --- a/src/cli/format.js +++ b/src/cli/format.js @@ -3,8 +3,11 @@ import path from "node:path"; import chalk from "chalk"; import { createTwoFilesPatch } from "diff"; import * as prettier from "../index.js"; -import mockable from "../common/mockable.js"; -import { createIsIgnoredFunction, errors } from "./prettier-internal.js"; +import { + createIsIgnoredFunction, + errors, + mockable, +} from "./prettier-internal.js"; import { expandPatterns } from "./expand-patterns.js"; import getOptionsForFile from "./options/get-options-for-file.js"; import isTTY from "./is-tty.js"; diff --git a/src/cli/is-tty.js b/src/cli/is-tty.js index 947543825..fc8e9bca0 100644 --- a/src/cli/is-tty.js +++ b/src/cli/is-tty.js @@ -1,4 +1,4 @@ -import mockable from "../common/mockable.js"; +import { mockable } from "./prettier-internal.js"; // Some CI pipelines incorrectly report process.stdout.isTTY status, // which causes unwanted lines in the output. An additional check for isCI() helps. diff --git a/src/cli/prettier-internal.js b/src/cli/prettier-internal.js index 3599a89d6..45493090b 100644 --- a/src/cli/prettier-internal.js +++ b/src/cli/prettier-internal.js @@ -11,4 +11,5 @@ export const { normalizeOptionSettings, vnopts, fastGlob, + mockable, } = sharedWithCli; diff --git a/src/common/mockable.js b/src/common/mockable.js index 57583c2f2..dc6d38692 100644 --- a/src/common/mockable.js +++ b/src/common/mockable.js @@ -1,5 +1,4 @@ import fs from "node:fs/promises"; -import { lilconfig } from "lilconfig"; import getStdin from "get-stdin"; import { isCI } from "ci-info"; @@ -8,7 +7,8 @@ function writeFormattedFile(file, data) { } const mockable = { - lilconfig, + // eslint-disable-next-line unicorn/no-useless-undefined + getPrettierConfigSearchStopDirectory: () => undefined, getStdin, isCI: () => isCI, writeFormattedFile, diff --git a/src/config/get-prettier-config-explorer.js b/src/config/get-prettier-config-explorer.js deleted file mode 100644 index a2ceeef5a..000000000 --- a/src/config/get-prettier-config-explorer.js +++ /dev/null @@ -1,112 +0,0 @@ -import { pathToFileURL } from "node:url"; -import parseToml from "@iarna/toml/parse-async.js"; -import parseJson5 from "json5/lib/parse.js"; -import yaml from "js-yaml"; -import parseJson from "parse-json"; -import mockable from "../common/mockable.js"; -import loadExternalConfig from "./load-external-config.js"; - -const { lilconfig } = mockable; - -const searchPlaces = [ - "package.json", - ".prettierrc", - ".prettierrc.json", - ".prettierrc.yaml", - ".prettierrc.yml", - ".prettierrc.json5", - ".prettierrc.js", - ".prettierrc.mjs", - ".prettierrc.cjs", - "prettier.config.js", - "prettier.config.mjs", - "prettier.config.cjs", - ".prettierrc.toml", -]; - -async function loadJs(filepath /*, content*/) { - const module = await import(pathToFileURL(filepath).href); - return module.default; -} - -function loadYaml(filepath, content) { - try { - return yaml.load(content); - } catch (/** @type {any} */ error) { - error.message = `YAML Error in ${filepath}:\n${error.message}`; - throw error; - } -} - -const loaders = { - async ".toml"(filePath, content) { - try { - return await parseToml(content); - } catch (/** @type {any} */ error) { - error.message = `TOML Error in ${filePath}:\n${error.message}`; - throw error; - } - }, - ".json5"(filePath, content) { - try { - return parseJson5(content); - } catch (/** @type {any} */ error) { - error.message = `JSON5 Error in ${filePath}:\n${error.message}`; - throw error; - } - }, - ".json"(filePath, content) { - try { - return parseJson(content); - } catch (/** @type {any} */ error) { - error.message = `JSON Error in ${filePath}:\n${error.message}`; - throw error; - } - }, - ".js": loadJs, - ".mjs": loadJs, - ".yaml": loadYaml, - ".yml": loadYaml, - noExt: loadYaml, -}; - -async function transform(result) { - if (!result?.config) { - return result; - } - - let { config, filepath } = result; - - /* - We support external config - - ```json - { - "prettier": "my-prettier-config-package-or-file" - } - ``` - */ - if (typeof config === "string") { - config = await loadExternalConfig(config, filepath); - result.config = config; - } - - if (typeof config !== "object") { - throw new TypeError( - "Config is only allowed to be an object, " + - `but received ${typeof config} in "${filepath}"`, - ); - } - - delete config.$schema; - return result; -} - -/** - * @return {ReturnType} - */ -function getExplorer() { - return lilconfig("prettier", { searchPlaces, loaders, transform }); -} - -export default getExplorer; diff --git a/src/config/prettier-config-explorer/config-searcher.js b/src/config/prettier-config-explorer/config-searcher.js new file mode 100644 index 000000000..a73a015b8 --- /dev/null +++ b/src/config/prettier-config-explorer/config-searcher.js @@ -0,0 +1,119 @@ +import path from "node:path"; +import iterateDirectoryUp from "iterate-directory-up"; +import isFile from "../../utils/is-file.js"; +import { loadConfigFromPackageJson } from "./loaders.js"; + +const CONFIG_FILE_NAMES = [ + "package.json", + ".prettierrc", + ".prettierrc.json", + ".prettierrc.yaml", + ".prettierrc.yml", + ".prettierrc.json5", + ".prettierrc.js", + ".prettierrc.mjs", + ".prettierrc.cjs", + "prettier.config.js", + "prettier.config.mjs", + "prettier.config.cjs", + ".prettierrc.toml", +]; + +async function isPackageJsonFileWithPrettierConfig(file) { + try { + return Boolean(await loadConfigFromPackageJson(file)); + } catch { + return false; + } +} + +async function searchConfigInDirectory(directory) { + for (const fileName of CONFIG_FILE_NAMES) { + const file = path.join(directory, fileName); + + if (!(await isFile(file))) { + continue; + } + + if ( + fileName !== "package.json" || + (await isPackageJsonFileWithPrettierConfig(file)) + ) { + return file; + } + } +} + +function createCachedSearchConfigInDirectory() { + const cache = new Map(); + + return async function (fileOrDirectory) { + if (cache.has(fileOrDirectory)) { + return cache.get(fileOrDirectory); + } + + const promise = searchConfigInDirectory(fileOrDirectory); + cache.set(fileOrDirectory, promise); + const result = await promise; + cache.set(fileOrDirectory, result); + return result; + }; +} + +/** @type {Map} */ // @ts-expect-error -- intentionally not add the `get` method +const noopMap = { has: () => false, set() {} }; +class ConfigSearcher { + #shouldCache; + #stopDirectory; + #searchedFilesStore; + #searchConfigInDirectory; + constructor({ stopDirectory, shouldCache }) { + this.#shouldCache = shouldCache; + this.#stopDirectory = stopDirectory; + this.#searchConfigInDirectory = shouldCache + ? createCachedSearchConfigInDirectory() + : searchConfigInDirectory; + this.#searchedFilesStore = shouldCache ? new Map() : noopMap; + } + + async #searchConfigInDirectories(startDirectory) { + const store = this.#searchedFilesStore; + for (const directory of iterateDirectoryUp( + startDirectory, + this.#stopDirectory, + )) { + // The parent directory may already searched + if (store.has(directory)) { + return store.get(directory); + } + + const file = await this.#searchConfigInDirectory(directory); + if (file) { + return file; + } + } + } + + async search(startDirectory) { + const store = this.#searchedFilesStore; + if (store.has(startDirectory)) { + return store.get(startDirectory); + } + + const configFile = await this.#searchConfigInDirectories(startDirectory); + + // Directories between startDirectory and configFile directory should has the same result + if (this.#shouldCache) { + for (const directory of iterateDirectoryUp( + startDirectory, + configFile ? path.dirname(configFile) : startDirectory, + )) { + store.set(directory, configFile); + } + } + + return configFile; + } +} + +export default ConfigSearcher; diff --git a/src/config/prettier-config-explorer/index.js b/src/config/prettier-config-explorer/index.js new file mode 100644 index 000000000..d8f1fa3f6 --- /dev/null +++ b/src/config/prettier-config-explorer/index.js @@ -0,0 +1,64 @@ +import path from "node:path"; +import mockable from "../../common/mockable.js"; +import loadConfigWithoutCache from "./load-config.js"; +import ConfigSearcher from "./config-searcher.js"; + +const loadCache = new Map(); +const searchCache = new Map(); +function clearCache() { + loadCache.clear(); + searchCache.clear(); +} + +/** + * @param {string} configFile + * @param {{shouldCache?: boolean}} param1 + * @returns {Promise>} + */ +function loadConfig(configFile, { shouldCache }) { + configFile = path.resolve(configFile); + if (!shouldCache || !loadCache.has(configFile)) { + const promise = loadConfigWithoutCache(configFile); + // Even if `shouldCache` is false, we still cache it, so we can use it later + loadCache.set(configFile, promise); + return promise; + } + + return loadCache.get(configFile); +} + +/** + * @param {{shouldCache?: boolean, stopDirectory?: string}} param0 + */ +function getSearchFunction({ shouldCache, stopDirectory }) { + stopDirectory = stopDirectory ? path.resolve(stopDirectory) : undefined; + const searchCacheKey = JSON.stringify({ shouldCache, stopDirectory }); + + if (!searchCache.has(searchCacheKey)) { + const searcher = new ConfigSearcher({ shouldCache, stopDirectory }); + const searchFunction = searcher.search.bind(searcher); + + searchCache.set(searchCacheKey, searchFunction); + } + + return searchCache.get(searchCacheKey); +} + +/** + * @param {string} startDirectory + * @param {{shouldCache?: boolean, stopDirectory?: string}} options + * @returns {Promise} + */ +function searchConfig(startDirectory, options = {}) { + startDirectory = startDirectory + ? path.resolve(startDirectory) + : process.cwd(); + + options.stopDirectory = mockable.getPrettierConfigSearchStopDirectory(); + + const search = getSearchFunction(options); + + return search(startDirectory); +} + +export { searchConfig, loadConfig, clearCache }; diff --git a/src/config/prettier-config-explorer/load-config.js b/src/config/prettier-config-explorer/load-config.js new file mode 100644 index 000000000..50658e62c --- /dev/null +++ b/src/config/prettier-config-explorer/load-config.js @@ -0,0 +1,48 @@ +import path from "node:path"; +import loadExternalConfig from "./load-external-config.js"; +import loaders, { loadConfigFromPackageJson } from "./loaders.js"; + +async function loadConfig(configFile) { + const { base: fileName, ext: extension } = path.parse(configFile); + const load = + fileName === "package.json" + ? loadConfigFromPackageJson + : loaders[extension]; + + if (!load) { + throw new Error( + `No loader specified for extension "${extension || "noExt"}"`, + ); + } + + let config = await load(configFile); + + if (!config) { + return; + } + + /* + We support external config + + ```json + { + "prettier": "my-prettier-config-package-or-file" + } + ``` + */ + if (typeof config === "string") { + config = await loadExternalConfig(config, configFile); + } + + if (typeof config !== "object") { + throw new TypeError( + "Config is only allowed to be an object, " + + `but received ${typeof config} in "${configFile}"`, + ); + } + + delete config.$schema; + return config; +} + +export default loadConfig; diff --git a/src/config/load-external-config.js b/src/config/prettier-config-explorer/load-external-config.js similarity index 65% rename from src/config/load-external-config.js rename to src/config/prettier-config-explorer/load-external-config.js index 96988a08c..2b40eddd4 100644 --- a/src/config/load-external-config.js +++ b/src/config/prettier-config-explorer/load-external-config.js @@ -1,12 +1,12 @@ -import requireFromFile from "../utils/require-from-file.js"; -import importFromFile from "../utils/import-from-file.js"; +import requireFromFile from "../../utils/require-from-file.js"; +import importFromFile from "../../utils/import-from-file.js"; const requireErrorCodesShouldBeIgnored = new Set([ "MODULE_NOT_FOUND", "ERR_REQUIRE_ESM", "ERR_PACKAGE_PATH_NOT_EXPORTED", ]); -async function loadExternalConfig(config, filepath) { +async function loadExternalConfig(externalConfig, configFile) { /* Try `require()` first, this is how it works in Prettier v2. Kept this because the external config path or package may can't load with `import()`: @@ -15,14 +15,14 @@ async function loadExternalConfig(config, filepath) { 3. is a dirname with index.js inside */ try { - return requireFromFile(config, filepath); + return requireFromFile(externalConfig, configFile); } catch (/** @type {any} */ error) { if (!requireErrorCodesShouldBeIgnored.has(error?.code)) { throw error; } } - const module = await importFromFile(config, filepath); + const module = await importFromFile(externalConfig, configFile); return module.default; } diff --git a/src/config/prettier-config-explorer/loaders.js b/src/config/prettier-config-explorer/loaders.js new file mode 100644 index 000000000..2f663e333 --- /dev/null +++ b/src/config/prettier-config-explorer/loaders.js @@ -0,0 +1,68 @@ +import { pathToFileURL } from "node:url"; +import parseToml from "@iarna/toml/parse-async.js"; +import parseJson5 from "json5/lib/parse.js"; +import jsYaml from "js-yaml"; +import parseJson from "parse-json"; +import readFile from "../../utils/read-file.js"; + +async function readJson(file) { + const content = await readFile(file); + try { + return parseJson(content); + } catch (/** @type {any} */ error) { + error.message = `JSON Error in ${file}:\n${error.message}`; + throw error; + } +} + +async function loadJs(file) { + const module = await import(pathToFileURL(file).href); + return module.default; +} + +async function loadConfigFromPackageJson(file) { + const { prettier } = await readJson(file); + return prettier; +} + +async function loadYaml(file) { + const content = await readFile(file); + try { + return jsYaml.load(content); + } catch (/** @type {any} */ error) { + error.message = `YAML Error in ${file}:\n${error.message}`; + throw error; + } +} + +const loaders = { + async ".toml"(file) { + const content = await readFile(file); + try { + return await parseToml(content); + } catch (/** @type {any} */ error) { + error.message = `TOML Error in ${file}:\n${error.message}`; + throw error; + } + }, + async ".json5"(file) { + const content = await readFile(file); + try { + return parseJson5(content); + } catch (/** @type {any} */ error) { + error.message = `JSON5 Error in ${file}:\n${error.message}`; + throw error; + } + }, + ".json": readJson, + ".js": loadJs, + ".mjs": loadJs, + ".cjs": loadJs, + ".yaml": loadYaml, + ".yml": loadYaml, + // No extension + "": loadYaml, +}; + +export default loaders; +export { readJson, loadConfigFromPackageJson }; diff --git a/src/config/resolve-config.js b/src/config/resolve-config.js index 4c15de5f9..707007d89 100644 --- a/src/config/resolve-config.js +++ b/src/config/resolve-config.js @@ -3,15 +3,16 @@ import micromatch from "micromatch"; import mem, { memClear } from "mem"; import { toPath } from "url-or-path"; import partition from "../utils/partition.js"; +import { + searchConfig as searchPrettierConfig, + loadConfig as loadPrettierConfigFile, + clearCache as clearPrettierConfigCache, +} from "./prettier-config-explorer/index.js"; import loadEditorConfigWithoutCache from "./resolve-editorconfig.js"; -import getPrettierConfigExplorerWithoutCache from "./get-prettier-config-explorer.js"; -const getPrettierConfigExplorer = mem(getPrettierConfigExplorerWithoutCache, { - cacheKey: ([options]) => options.cache, -}); const memoizedLoadEditorConfig = mem(loadEditorConfigWithoutCache); function clearCache() { - memClear(getPrettierConfigExplorer); + clearPrettierConfigCache(); memClear(memoizedLoadEditorConfig); } @@ -25,22 +26,24 @@ function loadEditorConfig(filePath, options) { )(filePath); } -function loadPrettierConfig(filePath, options) { - const { useCache, config: configPath } = options; - const { load, search } = getPrettierConfigExplorer({ - cache: Boolean(useCache), - }); +async function loadPrettierConfig(filePath, options) { + const shouldCache = options.useCache; + let configFile = options.config; - if (configPath) { - return load(configPath); + if (!configFile) { + const directory = filePath + ? path.dirname(path.resolve(filePath)) + : undefined; + configFile = await searchPrettierConfig(directory, { shouldCache }); } - if (!filePath) { - return search(); + if (!configFile) { + return; } - const dirname = path.dirname(path.resolve(filePath)); - return search(dirname); + const config = await loadPrettierConfigFile(configFile, { shouldCache }); + + return { config, configFile }; } async function resolveConfig(fileUrlOrPath, options) { @@ -64,7 +67,7 @@ async function resolveConfig(fileUrlOrPath, options) { if (Array.isArray(merged.plugins)) { merged.plugins = merged.plugins.map((value) => typeof value === "string" && value.startsWith(".") // relative path - ? path.resolve(path.dirname(result.filepath), value) + ? path.resolve(path.dirname(result.configFile), value) : value, ); } @@ -73,19 +76,18 @@ async function resolveConfig(fileUrlOrPath, options) { } async function resolveConfigFile(fileUrlOrPath) { - const { search } = getPrettierConfigExplorerWithoutCache(); - const dirname = fileUrlOrPath + const directory = fileUrlOrPath ? path.dirname(path.resolve(toPath(fileUrlOrPath))) : undefined; - const result = await search(dirname); - return result?.filepath ?? null; + const result = await searchPrettierConfig(directory, { shouldCache: false }); + return result ?? null; } function mergeOverrides(configResult, filePath) { - const { config, filepath: configPath } = configResult || {}; + const { config, configFile } = configResult || {}; const { overrides, ...options } = config || {}; if (filePath && overrides) { - const relativeFilePath = path.relative(path.dirname(configPath), filePath); + const relativeFilePath = path.relative(path.dirname(configFile), filePath); for (const override of overrides) { if ( pathMatchesGlobs( diff --git a/src/index.d.ts b/src/index.d.ts index 5a7d30776..e5100597e 100644 --- a/src/index.d.ts +++ b/src/index.d.ts @@ -548,8 +548,6 @@ export interface CursorOptions extends Options { * Specify where the cursor is. */ cursorOffset: number; - rangeStart?: never; - rangeEnd?: never; } export interface CursorResult { @@ -572,7 +570,7 @@ export function check(source: string, options?: Options): Promise; * `formatWithCursor` both formats the code, and translates a cursor position from unformatted code to formatted code. * This is useful for editor integrations, to prevent the cursor from moving when code is formatted. * - * The `cursorOffset` option should be provided, to specify where the cursor is. This option cannot be used with `rangeStart` and `rangeEnd`. + * The `cursorOffset` option should be provided, to specify where the cursor is. */ export function formatWithCursor( source: string, diff --git a/src/index.js b/src/index.js index 31f1eac17..e166b41f8 100644 --- a/src/index.js +++ b/src/index.js @@ -26,6 +26,7 @@ import normalizeOptions from "./main/normalize-options.js"; import partition from "./utils/partition.js"; import isNonEmptyArray from "./utils/is-non-empty-array.js"; import omit from "./utils/object-omit.js"; +import mockable from "./common/mockable.js"; /** * @param {*} fn @@ -106,6 +107,7 @@ const sharedWithCli = { partition, omit, }, + mockable, }; const debugApis = { @@ -114,6 +116,7 @@ const debugApis = { formatDoc: withPlugins(core.formatDoc), printToDoc: withPlugins(core.printToDoc), printDocToString: withPlugins(core.printDocToString), + mockable, }; export { diff --git a/src/language-js/parse/postprocess/index.js b/src/language-js/parse/postprocess/index.js index 80cb5bf95..fc52dc4b8 100644 --- a/src/language-js/parse/postprocess/index.js +++ b/src/language-js/parse/postprocess/index.js @@ -97,10 +97,10 @@ function postprocess(ast, options) { ast.extra = { ...ast.extra, __isUsingHackPipeline: true }; break; - // TODO: Remove this when https://github.com/meriyah/meriyah/issues/200 get fixed - case "ExportAllDeclaration": { - const { exported } = node; - if (parser === "meriyah" && exported?.type === "Identifier") { + case "ExportAllDeclaration": + // TODO: Remove this when https://github.com/meriyah/meriyah/issues/200 get fixed + if (parser === "meriyah" && node.exported?.type === "Identifier") { + const { exported } = node; const raw = text.slice(locStart(exported), locEnd(exported)); if (raw.startsWith('"') || raw.startsWith("'")) { node.exported = { @@ -112,7 +112,7 @@ function postprocess(ast, options) { } } break; - } + // In Flow parser, it doesn't generate union/intersection types for single type case "TSUnionType": case "TSIntersectionType": diff --git a/src/language-js/parse/typescript.js b/src/language-js/parse/typescript.js index c0773a3c8..d751bce6c 100644 --- a/src/language-js/parse/typescript.js +++ b/src/language-js/parse/typescript.js @@ -17,6 +17,7 @@ const baseParseOptions = { tokens: true, loggerFn: false, project: [], + jsDocParsingMode: "none", // TODO: Use new properties when update printer suppressDeprecatedPropertyWarnings: true, }; diff --git a/src/language-js/print/module.js b/src/language-js/print/module.js index 4b83d8be4..65d37cf4e 100644 --- a/src/language-js/print/module.js +++ b/src/language-js/print/module.js @@ -1,3 +1,4 @@ +import assert from "node:assert"; import isNonEmptyArray from "../../utils/is-non-empty-array.js"; import UnexpectedNodeError from "../../utils/unexpected-node-error.js"; import { @@ -20,7 +21,7 @@ import { rawText, createTypeCheckFunction, } from "../utils/index.js"; -import { locStart, hasSameLoc } from "../loc.js"; +import { locStart, hasSameLoc, locEnd } from "../loc.js"; import { printDecoratorsBeforeExport } from "./decorators.js"; import { printDeclareToken } from "./misc.js"; @@ -147,7 +148,7 @@ function printModuleSource(path, options, print) { /** @type{Doc[]} */ const parts = []; - if (!shouldNotPrintSpecifiers(node, options)) { + if (shouldPrintSpecifiers(node, options)) { parts.push(" from"); } parts.push(" ", print("source")); @@ -158,7 +159,7 @@ function printModuleSource(path, options, print) { function printModuleSpecifiers(path, options, print) { const { node } = path; - if (shouldNotPrintSpecifiers(node, options)) { + if (!shouldPrintSpecifiers(node, options)) { return ""; } @@ -230,21 +231,96 @@ function printModuleSpecifiers(path, options, print) { return parts; } -function shouldNotPrintSpecifiers(node, options) { - const { type, importKind, source, specifiers } = node; - +function shouldPrintSpecifiers(node, options) { if ( - type !== "ImportDeclaration" || - isNonEmptyArray(specifiers) || - importKind === "type" + node.type !== "ImportDeclaration" || + isNonEmptyArray(node.specifiers) || + node.importKind === "type" ) { + return true; + } + + const text = getTextWithoutComments( + options, + locStart(node), + locStart(node.source), + ); + + return text.trimEnd().endsWith("from"); +} + +function shouldPrintAttributes(node, options) { + if (!node.source) { return false; } - // TODO: check tokens - return !/{\s*}/.test( - options.originalText.slice(locStart(node), locStart(source)), + if (isNonEmptyArray(node.attributes) || isNonEmptyArray(node.assertions)) { + return true; + } + + const text = getTextWithoutComments( + options, + locEnd(node.source), + locEnd(node), + ).trimStart(); + + return text.startsWith("with") || text.startsWith("assert"); +} + +function getTextWithoutComments(options, start, end) { + let text = options.originalText.slice(start, end); + + for (const comment of options[Symbol.for("comments")]) { + const commentStart = locStart(comment); + // Comments are sorted, we can escape if the comment is after the range + if (commentStart > end) { + break; + } + + const commentEnd = locEnd(comment); + if (commentEnd < start) { + continue; + } + + const commentLength = commentEnd - commentStart; + text = + text.slice(0, commentStart - start) + + " ".repeat(commentLength) + + text.slice(commentEnd - start); + } + + if (process.env.NODE_ENV !== "production") { + assert(text.length === end - start); + } + + return text; +} + +function getImportAttributesOrAssertionsKeyword(node, options) { + if ( + // Babel parser add this property to indicate the keyword is `assert` + node.extra?.deprecatedAssertSyntax || + (isNonEmptyArray(node.assertions) && !isNonEmptyArray(node.attributes)) + ) { + return "assert"; + } + + if (!isNonEmptyArray(node.assertions) && isNonEmptyArray(node.attributes)) { + return "with"; + } + + const firstAttribute = node.attributes?.[0] ?? node.assertions?.[0]; + const textBetweenSourceAndAttributes = getTextWithoutComments( + options, + locEnd(node.source), + firstAttribute ? locStart(firstAttribute) : locEnd(node), ); + + if (textBetweenSourceAndAttributes.trimStart().startsWith("assert")) { + return "assert"; + } + + return "with"; } /** @@ -254,27 +330,33 @@ function shouldNotPrintSpecifiers(node, options) { function printImportAttributes(path, options, print) { const { node } = path; + if (!shouldPrintAttributes(node, options)) { + return ""; + } + + const keyword = getImportAttributesOrAssertionsKeyword(node, options); + /** @type{Doc[]} */ + const parts = [` ${keyword} {`]; + const property = isNonEmptyArray(node.attributes) ? "attributes" : isNonEmptyArray(node.assertions) ? "assertions" : undefined; + if (property) { + if (options.bracketSpacing) { + parts.push(" "); + } - if (!property) { - return ""; + parts.push(join(", ", path.map(print, property))); + + if (options.bracketSpacing) { + parts.push(" "); + } } + parts.push("}"); - const keyword = - property === "assertions" || node.extra?.deprecatedAssertSyntax - ? "assert" - : "with"; - return [ - ` ${keyword} {`, - options.bracketSpacing ? " " : "", - join(", ", path.map(print, property)), - options.bracketSpacing ? " " : "", - "}", - ]; + return parts; } function printModuleSpecifier(path, options, print) { diff --git a/src/language-js/traverse/visitor-keys.evaluate.js b/src/language-js/traverse/visitor-keys.evaluate.js index d0e8121d1..7e28c32ae 100644 --- a/src/language-js/traverse/visitor-keys.evaluate.js +++ b/src/language-js/traverse/visitor-keys.evaluate.js @@ -61,10 +61,6 @@ const excludeKeys = { // Flow parser changed `.types` to `.elementTypes` https://github.com/facebook/flow/commit/5b60e6a81dc277dfab2e88fa3737a4dc9aafdcab // TupleTypeAnnotation: ["types"], PropertyDefinition: ["tsModifiers"], - - // From `babelVisitorKeys` - DeclareInterface: ["mixins", "implements"], - InterfaceDeclaration: ["mixins", "implements"], }; const visitorKeys = Object.fromEntries( diff --git a/src/main/core-options.evaluate.js b/src/main/core-options.evaluate.js index 36e2a6af7..5c68cc734 100644 --- a/src/main/core-options.evaluate.js +++ b/src/main/core-options.evaluate.js @@ -49,10 +49,8 @@ const options = { type: "int", default: -1, range: { start: -1, end: Number.POSITIVE_INFINITY, step: 1 }, - description: outdent` - Print (to stderr) where a cursor at the given position would move to after formatting. - This option cannot be used with --range-start and --range-end. - `, + description: + "Print (to stderr) where a cursor at the given position would move to after formatting.", cliCategory: CATEGORY_EDITOR, }, endOfLine: { @@ -160,7 +158,6 @@ const options = { description: outdent` Format code ending at a given character offset (exclusive). The range will extend forwards to the end of the selected statement. - This option cannot be used with --cursor-offset. `, cliCategory: CATEGORY_EDITOR, }, @@ -172,7 +169,6 @@ const options = { description: outdent` Format code starting at a given character offset. The range will extend backwards to the start of the first line containing the selected statement. - This option cannot be used with --cursor-offset. `, cliCategory: CATEGORY_EDITOR, }, diff --git a/src/standalone.d.ts b/src/standalone.d.ts index b77367bb7..953ccf49c 100644 --- a/src/standalone.d.ts +++ b/src/standalone.d.ts @@ -4,7 +4,7 @@ import { CursorOptions, CursorResult, Options, SupportInfo } from "./index.js"; * formatWithCursor both formats the code, and translates a cursor position from unformatted code to formatted code. * This is useful for editor integrations, to prevent the cursor from moving when code is formatted * - * The cursorOffset option should be provided, to specify where the cursor is. This option cannot be used with rangeStart and rangeEnd. + * The cursorOffset option should be provided, to specify where the cursor is. * * ```js * await prettier.formatWithCursor(" 1", { cursorOffset: 2, parser: "babel" }); diff --git a/src/utils/is-file.js b/src/utils/is-file.js new file mode 100644 index 000000000..d9526826a --- /dev/null +++ b/src/utils/is-file.js @@ -0,0 +1,22 @@ +import fs from "node:fs/promises"; +import { toPath } from "url-or-path"; + +/** + * @param {string | URL} file + * @param {{allowSymlinks: boolean}} [options] + * @returns {Promise} + */ +async function isFile(file, options) { + const allowSymlinks = options?.allowSymlinks ?? true; + + let stats; + try { + stats = await (allowSymlinks ? fs.stat : fs.lstat)(toPath(file)); + } catch { + return false; + } + + return stats.isFile(); +} + +export default isFile; diff --git a/tests/dts/unit/cases/standalone.ts b/tests/dts/unit/cases/standalone.ts index 2a23e24d0..863900241 100644 --- a/tests/dts/unit/cases/standalone.ts +++ b/tests/dts/unit/cases/standalone.ts @@ -4,13 +4,11 @@ prettierStandalone.formatWithCursor(" 1", { cursorOffset: 2, parser: "babel" }); prettierStandalone.formatWithCursor(" 1", { cursorOffset: 2, parser: "babel", - // @ts-expect-error rangeStart: 2, }); prettierStandalone.formatWithCursor(" 1", { cursorOffset: 2, parser: "babel", - // @ts-expect-error rangeEnd: 2, }); prettierStandalone.format(" 1", { parser: "babel" }); diff --git a/tests/dts/unit/run.js b/tests/dts/unit/run.js index 94431b3a6..5e8039335 100644 --- a/tests/dts/unit/run.js +++ b/tests/dts/unit/run.js @@ -29,6 +29,18 @@ describe("Unit tests for dts files", () => { /** @type {import("typescript").Diagnostic[]} */ const diagnostics = ts.getPreEmitDiagnostics(program); - expect(diagnostics).toEqual([]); + expect(diagnostics.map(formatDiagnostic)).toEqual([]); }); }); + +/** + * @param {import("typescript").Diagnostic} diagnostic + */ +function formatDiagnostic({ file, start, code, messageText }) { + let location = ""; + if (file) { + const { line, character } = ts.getLineAndCharacterOfPosition(file, start); + location = `${file.fileName}:${line + 1}:${character + 1} `; + } + return `${location}TS${code}: ${messageText}`; +} diff --git a/tests/format/js/explicit-resource-management/__snapshots__/jsfmt.spec.js.snap b/tests/format/js/explicit-resource-management/__snapshots__/jsfmt.spec.js.snap index b68238451..5af60a31d 100644 --- a/tests/format/js/explicit-resource-management/__snapshots__/jsfmt.spec.js.snap +++ b/tests/format/js/explicit-resource-management/__snapshots__/jsfmt.spec.js.snap @@ -742,17 +742,6 @@ exports[`valid-for-using-binding-of-of.js [meriyah] format 1`] = ` Cause: [2:21]: Invalid left-hand side in for-of" `; -exports[`valid-for-using-binding-of-of.js [typescript] format 1`] = ` -"')' expected. (2:26) - 1 | async function f() { -> 2 | for (await using of of of); - | ^ - 3 | for await (await using of of of); - 4 | } - 5 | -Cause: ')' expected." -`; - exports[`valid-for-using-binding-of-of.js format 1`] = ` ====================================options===================================== parsers: ["babel", "flow", "typescript"] diff --git a/tests/format/js/explicit-resource-management/jsfmt.spec.js b/tests/format/js/explicit-resource-management/jsfmt.spec.js index e97824449..1a962d686 100644 --- a/tests/format/js/explicit-resource-management/jsfmt.spec.js +++ b/tests/format/js/explicit-resource-management/jsfmt.spec.js @@ -32,9 +32,6 @@ run_spec(import.meta, ["babel", "flow", "typescript"], { "valid-await-using-comments.js", "using-declarations.js", - // https://github.com/microsoft/TypeScript/issues/55555 - "valid-for-using-binding-of-of.js", - // TypeScript does not support module expr "valid-module-block-top-level-using-binding.js", "valid-module-block-top-level-await-using-binding.js", diff --git a/tests/format/js/import-assertions/__snapshots__/jsfmt.spec.js.snap b/tests/format/js/import-assertions/__snapshots__/jsfmt.spec.js.snap index cd510baf0..d966610d2 100644 --- a/tests/format/js/import-assertions/__snapshots__/jsfmt.spec.js.snap +++ b/tests/format/js/import-assertions/__snapshots__/jsfmt.spec.js.snap @@ -86,12 +86,12 @@ import * as bar from "bar.json" assert { } import * as baz from "baz.json" assert { /* comment */ } =====================================output===================================== export * as foo from "foo.json"; -export * as bar from "bar.json"; -export * as baz from "baz.json" /* comment */; +export * as bar from "bar.json" assert {}; +export * as baz from "baz.json" /* comment */ assert {}; import * as foo from "foo.json"; -import * as bar from "bar.json"; -import * as baz from "baz.json" /* comment */; +import * as bar from "bar.json" assert {}; +import * as baz from "baz.json" /* comment */ assert {}; ================================================================================ `; diff --git a/tests/format/js/import-assertions/bracket-spacing/__snapshots__/jsfmt.spec.js.snap b/tests/format/js/import-assertions/bracket-spacing/__snapshots__/jsfmt.spec.js.snap index 884bb803b..1908fac6b 100644 --- a/tests/format/js/import-assertions/bracket-spacing/__snapshots__/jsfmt.spec.js.snap +++ b/tests/format/js/import-assertions/bracket-spacing/__snapshots__/jsfmt.spec.js.snap @@ -69,7 +69,7 @@ printWidth: 80 =====================================input====================================== export * as bar from "bar.json" assert { } =====================================output===================================== -export * as bar from "bar.json"; +export * as bar from "bar.json" assert {}; ================================================================================ `; diff --git a/tests/format/js/import-attributes/__snapshots__/jsfmt.spec.js.snap b/tests/format/js/import-attributes/__snapshots__/jsfmt.spec.js.snap index 9024e0269..db49f25ec 100644 --- a/tests/format/js/import-attributes/__snapshots__/jsfmt.spec.js.snap +++ b/tests/format/js/import-attributes/__snapshots__/jsfmt.spec.js.snap @@ -71,17 +71,6 @@ exports[`empty.js [meriyah] format 1`] = ` Cause: [2:36]: Unexpected token: 'with'" `; -exports[`empty.js [typescript] format 1`] = ` -"';' expected. (2:33) - 1 | export * as foo from "foo.json" -> 2 | export * as bar from "bar.json" with { } - | ^ - 3 | export * as baz from "baz.json" with { /* comment */ } - 4 | - 5 | import * as foo from "foo.json" -Cause: ';' expected." -`; - exports[`empty.js format 1`] = ` ====================================options===================================== parsers: ["babel", "typescript"] @@ -98,12 +87,74 @@ import * as baz from "baz.json" with { /* comment */ } =====================================output===================================== export * as foo from "foo.json"; -export * as bar from "bar.json"; -export * as baz from "baz.json" /* comment */; +export * as bar from "bar.json" with {}; +export * as baz from "baz.json" /* comment */ with {}; import * as foo from "foo.json"; -import * as bar from "bar.json"; -import * as baz from "baz.json" /* comment */; +import * as bar from "bar.json" with {}; +import * as baz from "baz.json" /* comment */ with {}; + +================================================================================ +`; + +exports[`keyword-detect.js [acorn] format 1`] = ` +"Unexpected token (1:35) +> 1 | import "./test.json" /* assert */ with /* assert */ { type: "json" } + | ^ + 2 | import {} from "./test.json" /* assert */ with /* assert */ { type: "json" } + 3 | import "./test.json" /* with */ assert /* with */ { type: "json" } + 4 | import {} from "./test.json" /* with */ assert /* with */ { type: "json" } +Cause: Unexpected token (1:34)" +`; + +exports[`keyword-detect.js [espree] format 1`] = ` +"Unexpected token with (1:35) +> 1 | import "./test.json" /* assert */ with /* assert */ { type: "json" } + | ^ + 2 | import {} from "./test.json" /* assert */ with /* assert */ { type: "json" } + 3 | import "./test.json" /* with */ assert /* with */ { type: "json" } + 4 | import {} from "./test.json" /* with */ assert /* with */ { type: "json" } +Cause: Unexpected token with" +`; + +exports[`keyword-detect.js [meriyah] format 1`] = ` +"Unexpected token: 'with' (1:38) +> 1 | import "./test.json" /* assert */ with /* assert */ { type: "json" } + | ^ + 2 | import {} from "./test.json" /* assert */ with /* assert */ { type: "json" } + 3 | import "./test.json" /* with */ assert /* with */ { type: "json" } + 4 | import {} from "./test.json" /* with */ assert /* with */ { type: "json" } +Cause: [1:38]: Unexpected token: 'with'" +`; + +exports[`keyword-detect.js format 1`] = ` +====================================options===================================== +parsers: ["babel", "typescript"] +printWidth: 80 + | printWidth +=====================================input====================================== +import "./test.json" /* assert */ with /* assert */ { type: "json" } +import {} from "./test.json" /* assert */ with /* assert */ { type: "json" } +import "./test.json" /* with */ assert /* with */ { type: "json" } +import {} from "./test.json" /* with */ assert /* with */ { type: "json" } + +export {} from "./test.json" /* assert */ with /* assert */ { type: "json" } +export {} from "./test.json" /* with */ assert /* with */ { type: "json" } + +export * from "./test.json" /* assert */ with /* assert */ { type: "json" } +export * from "./test.json" /* with */ assert /* with */ { type: "json" } + +=====================================output===================================== +import "./test.json" /* assert */ /* assert */ with { type: "json" }; +import {} from "./test.json" /* assert */ /* assert */ with { type: "json" }; +import "./test.json" /* with */ /* with */ assert { type: "json" }; +import {} from "./test.json" /* with */ /* with */ assert { type: "json" }; + +export {} from "./test.json" /* assert */ /* assert */ with { type: "json" }; +export {} from "./test.json" /* with */ /* with */ assert { type: "json" }; + +export * from "./test.json" /* assert */ /* assert */ with { type: "json" }; +export * from "./test.json" /* with */ /* with */ assert { type: "json" }; ================================================================================ `; @@ -132,14 +183,6 @@ exports[`multi-types.js [meriyah] format 1`] = ` Cause: [1:34]: Unexpected token: 'with'" `; -exports[`multi-types.js [typescript] format 1`] = ` -"';' expected. (1:31) -> 1 | import json from "./foo.json" with { type: "json", type: "bar" }; - | ^ - 2 | -Cause: ';' expected." -`; - exports[`multi-types.js format 1`] = ` ====================================options===================================== parsers: ["babel", "typescript"] @@ -178,14 +221,6 @@ exports[`non-type.js [meriyah] format 1`] = ` Cause: [1:31]: Unexpected token: 'with'" `; -exports[`non-type.js [typescript] format 1`] = ` -"';' expected. (1:28) -> 1 | import foo from "foo.json" with { lazy: "true" }; - | ^ - 2 | -Cause: ';' expected." -`; - exports[`non-type.js format 1`] = ` ====================================options===================================== parsers: ["babel", "typescript"] @@ -230,16 +265,6 @@ exports[`re-export.js [meriyah] format 1`] = ` Cause: [1:47]: Unexpected token: 'with'" `; -exports[`re-export.js [typescript] format 1`] = ` -"';' expected. (1:44) -> 1 | export { default as foo2 } from "foo.json" with { type: "json" }; - | ^ - 2 | export * from "foo.json" with { type: "json" }; - 3 | export * as foo3 from "foo.json" with { type: "json" }; - 4 | -Cause: ';' expected." -`; - exports[`re-export.js format 1`] = ` ====================================options===================================== parsers: ["babel", "typescript"] @@ -282,14 +307,6 @@ exports[`static-import.js [meriyah] format 1`] = ` Cause: [1:34]: Unexpected token: 'with'" `; -exports[`static-import.js [typescript] format 1`] = ` -"';' expected. (1:31) -> 1 | import json from "./foo.json" with { type: "json" }; - | ^ - 2 | -Cause: ';' expected." -`; - exports[`static-import.js format 1`] = ` ====================================options===================================== parsers: ["babel", "typescript"] @@ -328,14 +345,6 @@ exports[`without-from.js [meriyah] format 1`] = ` Cause: [1:17]: Unexpected token: 'with'" `; -exports[`without-from.js [typescript] format 1`] = ` -"';' expected. (1:14) -> 1 | import "foo" with { type: "json" } - | ^ - 2 | -Cause: ';' expected." -`; - exports[`without-from.js format 1`] = ` ====================================options===================================== parsers: ["babel", "typescript"] diff --git a/tests/format/js/import-attributes/bracket-spacing/__snapshots__/jsfmt.spec.js.snap b/tests/format/js/import-attributes/bracket-spacing/__snapshots__/jsfmt.spec.js.snap index 18d759c64..67936c32d 100644 --- a/tests/format/js/import-attributes/bracket-spacing/__snapshots__/jsfmt.spec.js.snap +++ b/tests/format/js/import-attributes/bracket-spacing/__snapshots__/jsfmt.spec.js.snap @@ -69,7 +69,7 @@ printWidth: 80 =====================================input====================================== export * as bar from "bar.json" with { } =====================================output===================================== -export * as bar from "bar.json"; +export * as bar from "bar.json" with {}; ================================================================================ `; diff --git a/tests/format/js/import-attributes/jsfmt.spec.js b/tests/format/js/import-attributes/jsfmt.spec.js index 168477a66..7e4f7ab95 100644 --- a/tests/format/js/import-attributes/jsfmt.spec.js +++ b/tests/format/js/import-attributes/jsfmt.spec.js @@ -8,6 +8,7 @@ run_spec(import.meta, ["babel", "typescript"], { "re-export.js", "without-from.js", "non-type.js", + "keyword-detect.js", ], espree: [ "dynamic-import.js", @@ -17,6 +18,7 @@ run_spec(import.meta, ["babel", "typescript"], { "re-export.js", "without-from.js", "non-type.js", + "keyword-detect.js", ], meriyah: [ "dynamic-import.js", @@ -26,14 +28,7 @@ run_spec(import.meta, ["babel", "typescript"], { "re-export.js", "without-from.js", "non-type.js", - ], - typescript: [ - "empty.js", - "multi-types.js", - "static-import.js", - "re-export.js", - "without-from.js", - "non-type.js", + "keyword-detect.js", ], }, }); diff --git a/tests/format/js/import-attributes/keyword-detect.js b/tests/format/js/import-attributes/keyword-detect.js new file mode 100644 index 000000000..4d0ed0657 --- /dev/null +++ b/tests/format/js/import-attributes/keyword-detect.js @@ -0,0 +1,10 @@ +import "./test.json" /* assert */ with /* assert */ { type: "json" } +import {} from "./test.json" /* assert */ with /* assert */ { type: "json" } +import "./test.json" /* with */ assert /* with */ { type: "json" } +import {} from "./test.json" /* with */ assert /* with */ { type: "json" } + +export {} from "./test.json" /* assert */ with /* assert */ { type: "json" } +export {} from "./test.json" /* with */ assert /* with */ { type: "json" } + +export * from "./test.json" /* assert */ with /* assert */ { type: "json" } +export * from "./test.json" /* with */ assert /* with */ { type: "json" } diff --git a/tests/format/js/import/__snapshots__/jsfmt.spec.js.snap b/tests/format/js/import/__snapshots__/jsfmt.spec.js.snap index c61aafb15..debf429eb 100644 --- a/tests/format/js/import/__snapshots__/jsfmt.spec.js.snap +++ b/tests/format/js/import/__snapshots__/jsfmt.spec.js.snap @@ -286,9 +286,92 @@ printWidth: 80 | printWidth =====================================input====================================== import { } from '@types/googlemaps'; +import 'a'; +import /* comment */ 'a'; +import // comment +'a'; +import { /* comment */ } from 'a'; +import /* comment */ {} from 'a'; +import {} /* comment */ from 'a'; +import {} from /* comment */ 'a'; +import /* comment */ {/* comment */} /* comment */ from /* comment */ 'a'; +import { + // comment +} from 'a'; +import // comment +{} from 'a'; +import {} +// comment +from 'a'; +import {} from +// comment +'a'; +import +// comment +{ +// comment +} +// comment +from +// comment +'a'; + +import // {} from +'a'; +import {} from // comment ends with from +'a'; +import {} from /* comment ends with from */ 'a'; +import {} from // comment not ends with from ___ +'a'; +import {} from /* comment not ends with from ___ */ 'a'; + +import // comment ends with from +'a'; +import /* comment ends with from */ 'a'; +import // comment not ends with from ___ +'a'; +import /* comment not ends with from ___ */ 'a'; =====================================output===================================== import {} from "@types/googlemaps"; +import "a"; +import /* comment */ "a"; +import // comment +"a"; +import {} from /* comment */ "a"; +import {} from /* comment */ "a"; +import {} from /* comment */ "a"; +import {} from /* comment */ "a"; +import {} from /* comment */ /* comment */ /* comment */ /* comment */ "a"; +import {} from // comment +"a"; +import {} from // comment +"a"; +import {} from // comment +"a"; +import {} from // comment +"a"; +import {} from // comment +// comment +// comment +// comment +"a"; + +import // {} from +"a"; +import {} from // comment ends with from +"a"; +import {} from /* comment ends with from */ "a"; +import {} from // comment not ends with from ___ +"a"; +import {} from /* comment not ends with from ___ */ "a"; + +import // comment ends with from +"a"; +import /* comment ends with from */ "a"; +import // comment not ends with from ___ +"a"; +import /* comment not ends with from ___ */ "a"; ================================================================================ `; @@ -300,9 +383,92 @@ printWidth: 80 | printWidth =====================================input====================================== import { } from '@types/googlemaps'; +import 'a'; +import /* comment */ 'a'; +import // comment +'a'; +import { /* comment */ } from 'a'; +import /* comment */ {} from 'a'; +import {} /* comment */ from 'a'; +import {} from /* comment */ 'a'; +import /* comment */ {/* comment */} /* comment */ from /* comment */ 'a'; +import { + // comment +} from 'a'; +import // comment +{} from 'a'; +import {} +// comment +from 'a'; +import {} from +// comment +'a'; +import +// comment +{ +// comment +} +// comment +from +// comment +'a'; + +import // {} from +'a'; +import {} from // comment ends with from +'a'; +import {} from /* comment ends with from */ 'a'; +import {} from // comment not ends with from ___ +'a'; +import {} from /* comment not ends with from ___ */ 'a'; + +import // comment ends with from +'a'; +import /* comment ends with from */ 'a'; +import // comment not ends with from ___ +'a'; +import /* comment not ends with from ___ */ 'a'; =====================================output===================================== import {} from "@types/googlemaps"; +import "a"; +import /* comment */ "a"; +import // comment +"a"; +import {} from /* comment */ "a"; +import {} from /* comment */ "a"; +import {} from /* comment */ "a"; +import {} from /* comment */ "a"; +import {} from /* comment */ /* comment */ /* comment */ /* comment */ "a"; +import {} from // comment +"a"; +import {} from // comment +"a"; +import {} from // comment +"a"; +import {} from // comment +"a"; +import {} from // comment +// comment +// comment +// comment +"a"; + +import // {} from +"a"; +import {} from // comment ends with from +"a"; +import {} from /* comment ends with from */ "a"; +import {} from // comment not ends with from ___ +"a"; +import {} from /* comment not ends with from ___ */ "a"; + +import // comment ends with from +"a"; +import /* comment ends with from */ "a"; +import // comment not ends with from ___ +"a"; +import /* comment not ends with from ___ */ "a"; ================================================================================ `; diff --git a/tests/format/js/import/empty-import.js b/tests/format/js/import/empty-import.js index f08bd7860..aa75b16d1 100644 --- a/tests/format/js/import/empty-import.js +++ b/tests/format/js/import/empty-import.js @@ -1 +1,46 @@ import { } from '@types/googlemaps'; +import 'a'; +import /* comment */ 'a'; +import // comment +'a'; +import { /* comment */ } from 'a'; +import /* comment */ {} from 'a'; +import {} /* comment */ from 'a'; +import {} from /* comment */ 'a'; +import /* comment */ {/* comment */} /* comment */ from /* comment */ 'a'; +import { + // comment +} from 'a'; +import // comment +{} from 'a'; +import {} +// comment +from 'a'; +import {} from +// comment +'a'; +import +// comment +{ +// comment +} +// comment +from +// comment +'a'; + +import // {} from +'a'; +import {} from // comment ends with from +'a'; +import {} from /* comment ends with from */ 'a'; +import {} from // comment not ends with from ___ +'a'; +import {} from /* comment not ends with from ___ */ 'a'; + +import // comment ends with from +'a'; +import /* comment ends with from */ 'a'; +import // comment not ends with from ___ +'a'; +import /* comment not ends with from ___ */ 'a'; diff --git a/tests/format/markdown/markdown/__snapshots__/jsfmt.spec.js.snap b/tests/format/markdown/markdown/__snapshots__/jsfmt.spec.js.snap index a273f370b..86e3747c1 100644 --- a/tests/format/markdown/markdown/__snapshots__/jsfmt.spec.js.snap +++ b/tests/format/markdown/markdown/__snapshots__/jsfmt.spec.js.snap @@ -465,7 +465,7 @@ This is similar to the \`--list-different\` parameter in the CLI and is useful f \`formatWithCursor\` both formats the code, and translates a cursor position from unformatted code to formatted code. This is useful for editor integrations, to prevent the cursor from moving when code is formatted. -The \`cursorOffset\` option should be provided, to specify where the cursor is. This option cannot be used with \`rangeStart\` and \`rangeEnd\`. +The \`cursorOffset\` option should be provided, to specify where the cursor is. \`\`\`js prettier.formatWithCursor(" 1", { cursorOffset: 2 }); @@ -646,8 +646,6 @@ These two options can be used to format code starting and ending at a given char * Backwards to the start of the first line containing the selected statement. * Forwards to the end of the selected statement. -These options cannot be used with \`cursorOffset\`. - Default | CLI Override | API Override --------|--------------|------------- \`0\` | \`--range-start \`| \`rangeStart: \` @@ -1454,7 +1452,6 @@ unformatted code to formatted code. This is useful for editor integrations, to prevent the cursor from moving when code is formatted. 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 }); @@ -1670,8 +1667,6 @@ character offset (inclusive and exclusive, respectively). The range will extend: - Backwards to the start of the first line containing the selected statement. - Forwards to the end of the selected statement. -These options cannot be used with \`cursorOffset\`. - | Default | CLI Override | API Override | | ---------- | --------------------- | ------------------- | | \`0\` | \`--range-start \` | \`rangeStart: \` | @@ -2442,7 +2437,7 @@ This is similar to the \`--list-different\` parameter in the CLI and is useful f \`formatWithCursor\` both formats the code, and translates a cursor position from unformatted code to formatted code. This is useful for editor integrations, to prevent the cursor from moving when code is formatted. -The \`cursorOffset\` option should be provided, to specify where the cursor is. This option cannot be used with \`rangeStart\` and \`rangeEnd\`. +The \`cursorOffset\` option should be provided, to specify where the cursor is. \`\`\`js prettier.formatWithCursor(" 1", { cursorOffset: 2 }); @@ -2623,8 +2618,6 @@ These two options can be used to format code starting and ending at a given char * Backwards to the start of the first line containing the selected statement. * Forwards to the end of the selected statement. -These options cannot be used with \`cursorOffset\`. - Default | CLI Override | API Override --------|--------------|------------- \`0\` | \`--range-start \`| \`rangeStart: \` @@ -3431,7 +3424,6 @@ unformatted code to formatted code. This is useful for editor integrations, to prevent the cursor from moving when code is formatted. 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 }); @@ -3647,8 +3639,6 @@ character offset (inclusive and exclusive, respectively). The range will extend: - Backwards to the start of the first line containing the selected statement. - Forwards to the end of the selected statement. -These options cannot be used with \`cursorOffset\`. - | Default | CLI Override | API Override | | ---------- | --------------------- | ------------------- | | \`0\` | \`--range-start \` | \`rangeStart: \` | diff --git a/tests/format/markdown/markdown/real-world-case.md b/tests/format/markdown/markdown/real-world-case.md index ff18ed16d..1f6ff7ab7 100644 --- a/tests/format/markdown/markdown/real-world-case.md +++ b/tests/format/markdown/markdown/real-world-case.md @@ -455,7 +455,7 @@ This is similar to the `--list-different` parameter in the CLI and is useful for `formatWithCursor` both formats the code, and translates a cursor position from unformatted code to formatted code. This is useful for editor integrations, to prevent the cursor from moving when code is formatted. -The `cursorOffset` option should be provided, to specify where the cursor is. This option cannot be used with `rangeStart` and `rangeEnd`. +The `cursorOffset` option should be provided, to specify where the cursor is. ```js prettier.formatWithCursor(" 1", { cursorOffset: 2 }); @@ -636,8 +636,6 @@ These two options can be used to format code starting and ending at a given char * Backwards to the start of the first line containing the selected statement. * Forwards to the end of the selected statement. -These options cannot be used with `cursorOffset`. - Default | CLI Override | API Override --------|--------------|------------- `0` | `--range-start `| `rangeStart: ` diff --git a/tests/format/misc/errors/typescript/__snapshots__/jsfmt.spec.js.snap b/tests/format/misc/errors/typescript/__snapshots__/jsfmt.spec.js.snap index fb4a8a9f7..8bbbfec42 100644 --- a/tests/format/misc/errors/typescript/__snapshots__/jsfmt.spec.js.snap +++ b/tests/format/misc/errors/typescript/__snapshots__/jsfmt.spec.js.snap @@ -47,11 +47,11 @@ Cause: Unexpected token. Did you mean \`{'>'}\` or \`>\`?" `; exports[`module-attributes-static.ts [typescript] format 1`] = ` -"';' expected. (1:28) +"'{' expected. (1:33) > 1 | import foo from "foo.json" with type: "json"; - | ^ + | ^ 2 | -Cause: ';' expected." +Cause: '{' expected." `; exports[`newline-before-arrow.ts [typescript] format 1`] = ` diff --git a/tests/format/typescript/import-export/__snapshots__/jsfmt.spec.js.snap b/tests/format/typescript/import-export/__snapshots__/jsfmt.spec.js.snap index ce63210d0..8fbcc19bd 100644 --- a/tests/format/typescript/import-export/__snapshots__/jsfmt.spec.js.snap +++ b/tests/format/typescript/import-export/__snapshots__/jsfmt.spec.js.snap @@ -1,5 +1,102 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP +exports[`empty-import.ts format 1`] = ` +====================================options===================================== +parsers: ["typescript"] +printWidth: 80 + | printWidth +=====================================input====================================== +import type { } from '@types/googlemaps'; +import 'a'; +import /* comment */ 'a'; +import // comment +'a'; +import type { /* comment */ } from 'a'; +import /* comment */ type {} from 'a'; +import type {} /* comment */ from 'a'; +import type {} from /* comment */ 'a'; +import /* comment */ type {/* comment */} /* comment */ from /* comment */ 'a'; +import type { + // comment +} from 'a'; +import // comment +type {} from 'a'; +import type {} +// comment +from 'a'; +import type {} from +// comment +'a'; +import type +// comment +{ +// comment +} +// comment +from +// comment +'a'; + +import // {} from +'a'; +import type {} from // comment ends with from +'a'; +import type {} from /* comment ends with from */ 'a'; +import type {} from // comment not ends with from ___ +'a'; +import type {} from /* comment not ends with from ___ */ 'a'; + +import // comment ends with from +'a'; +import /* comment ends with from */ 'a'; +import // comment not ends with from ___ +'a'; +import /* comment not ends with from ___ */ 'a'; + +=====================================output===================================== +import type {} from "@types/googlemaps"; +import "a"; +import /* comment */ "a"; +import // comment +"a"; +import type {} from /* comment */ "a"; +import type {} from /* comment */ "a"; +import type {} from /* comment */ "a"; +import type {} from /* comment */ "a"; +import type {} from /* comment */ /* comment */ /* comment */ /* comment */ "a"; +import type {} from // comment +"a"; +import type {} from // comment +"a"; +import type {} from // comment +"a"; +import type {} from // comment +"a"; +import type {} from // comment +// comment +// comment +// comment +"a"; + +import // {} from +"a"; +import type {} from // comment ends with from +"a"; +import type {} from /* comment ends with from */ "a"; +import type {} from // comment not ends with from ___ +"a"; +import type {} from /* comment not ends with from ___ */ "a"; + +import // comment ends with from +"a"; +import /* comment ends with from */ "a"; +import // comment not ends with from ___ +"a"; +import /* comment not ends with from ___ */ "a"; + +================================================================================ +`; + exports[`type-modifier.ts format 1`] = ` ====================================options===================================== parsers: ["typescript"] diff --git a/tests/format/typescript/import-export/empty-import.ts b/tests/format/typescript/import-export/empty-import.ts new file mode 100644 index 000000000..185385b71 --- /dev/null +++ b/tests/format/typescript/import-export/empty-import.ts @@ -0,0 +1,46 @@ +import type { } from '@types/googlemaps'; +import 'a'; +import /* comment */ 'a'; +import // comment +'a'; +import type { /* comment */ } from 'a'; +import /* comment */ type {} from 'a'; +import type {} /* comment */ from 'a'; +import type {} from /* comment */ 'a'; +import /* comment */ type {/* comment */} /* comment */ from /* comment */ 'a'; +import type { + // comment +} from 'a'; +import // comment +type {} from 'a'; +import type {} +// comment +from 'a'; +import type {} from +// comment +'a'; +import type +// comment +{ +// comment +} +// comment +from +// comment +'a'; + +import // {} from +'a'; +import type {} from // comment ends with from +'a'; +import type {} from /* comment ends with from */ 'a'; +import type {} from // comment not ends with from ___ +'a'; +import type {} from /* comment not ends with from ___ */ 'a'; + +import // comment ends with from +'a'; +import /* comment ends with from */ 'a'; +import // comment not ends with from ___ +'a'; +import /* comment not ends with from ___ */ 'a'; diff --git a/tests/integration/__tests__/__snapshots__/config-invalid.js.snap b/tests/integration/__tests__/__snapshots__/config-invalid.js.snap index 9b78f11b4..105c5d0cf 100644 --- a/tests/integration/__tests__/__snapshots__/config-invalid.js.snap +++ b/tests/integration/__tests__/__snapshots__/config-invalid.js.snap @@ -63,7 +63,7 @@ exports[`throw error with invalid config precedence option (configPrecedence) (w exports[`throw error with invalid config target (directory) (stderr) 1`] = ` "[error] Invalid configuration: -[error] EISDIR: illegal operation on a directory, read" +[error] Unable to read '/config/invalid/folder/.prettierrc': EISDIR: illegal operation on a directory, read" `; exports[`throw error with invalid config target (directory) (stdout) 1`] = `""`; diff --git a/tests/integration/__tests__/__snapshots__/early-exit.js.snap b/tests/integration/__tests__/__snapshots__/early-exit.js.snap index c75519ac4..25bc0e206 100644 --- a/tests/integration/__tests__/__snapshots__/early-exit.js.snap +++ b/tests/integration/__tests__/__snapshots__/early-exit.js.snap @@ -107,15 +107,12 @@ Config options: Editor options: --cursor-offset Print (to stderr) where a cursor at the given position would move to after formatting. - This option cannot be used with --range-start and --range-end. Defaults to -1. --range-end Format code ending at a given character offset (exclusive). The range will extend forwards to the end of the selected statement. - This option cannot be used with --cursor-offset. Defaults to Infinity. --range-start Format code starting at a given character offset. The range will extend backwards to the start of the first line containing the selected statement. - This option cannot be used with --cursor-offset. Defaults to 0. Other options: @@ -274,15 +271,12 @@ Config options: Editor options: --cursor-offset Print (to stderr) where a cursor at the given position would move to after formatting. - This option cannot be used with --range-start and --range-end. Defaults to -1. --range-end Format code ending at a given character offset (exclusive). The range will extend forwards to the end of the selected statement. - This option cannot be used with --cursor-offset. Defaults to Infinity. --range-start Format code starting at a given character offset. The range will extend backwards to the start of the first line containing the selected statement. - This option cannot be used with --cursor-offset. Defaults to 0. Other options: diff --git a/tests/integration/__tests__/__snapshots__/help-options.js.snap b/tests/integration/__tests__/__snapshots__/help-options.js.snap index 960199f40..554a07d2c 100644 --- a/tests/integration/__tests__/__snapshots__/help-options.js.snap +++ b/tests/integration/__tests__/__snapshots__/help-options.js.snap @@ -136,7 +136,6 @@ exports[`show detailed usage with --help cursor-offset (stdout) 1`] = ` "--cursor-offset Print (to stderr) where a cursor at the given position would move to after formatting. - This option cannot be used with --range-start and --range-end. Default: -1" `; @@ -505,7 +504,6 @@ exports[`show detailed usage with --help range-end (stdout) 1`] = ` Format code ending at a given character offset (exclusive). The range will extend forwards to the end of the selected statement. - This option cannot be used with --cursor-offset. Default: Infinity" `; @@ -519,7 +517,6 @@ exports[`show detailed usage with --help range-start (stdout) 1`] = ` Format code starting at a given character offset. The range will extend backwards to the start of the first line containing the selected statement. - This option cannot be used with --cursor-offset. Default: 0" `; diff --git a/tests/integration/__tests__/__snapshots__/schema.js.snap b/tests/integration/__tests__/__snapshots__/schema.js.snap index 971261fa8..a9a3e05a7 100644 --- a/tests/integration/__tests__/__snapshots__/schema.js.snap +++ b/tests/integration/__tests__/__snapshots__/schema.js.snap @@ -36,8 +36,7 @@ exports[`schema 1`] = ` }, "cursorOffset": { "default": -1, - "description": "Print (to stderr) where a cursor at the given position would move to after formatting. -This option cannot be used with --range-start and --range-end.", + "description": "Print (to stderr) where a cursor at the given position would move to after formatting.", "type": "integer", }, "embeddedLanguageFormatting": { @@ -345,15 +344,13 @@ This option cannot be used with --range-start and --range-end.", "rangeEnd": { "default": Infinity, "description": "Format code ending at a given character offset (exclusive). -The range will extend forwards to the end of the selected statement. -This option cannot be used with --cursor-offset.", +The range will extend forwards to the end of the selected statement.", "type": "integer", }, "rangeStart": { "default": 0, "description": "Format code starting at a given character offset. -The range will extend backwards to the start of the first line containing the selected statement. -This option cannot be used with --cursor-offset.", +The range will extend backwards to the start of the first line containing the selected statement.", "type": "integer", }, "requirePragma": { diff --git a/tests/integration/__tests__/__snapshots__/support-info.js.snap b/tests/integration/__tests__/__snapshots__/support-info.js.snap index ee5d880c8..a74818f21 100644 --- a/tests/integration/__tests__/__snapshots__/support-info.js.snap +++ b/tests/integration/__tests__/__snapshots__/support-info.js.snap @@ -806,7 +806,7 @@ exports[`CLI --support-info (stdout) 1`] = ` { "category": "Special", "default": -1, - "description": "Print (to stderr) where a cursor at the given position would move to after formatting.\\nThis option cannot be used with --range-start and --range-end.", + "description": "Print (to stderr) where a cursor at the given position would move to after formatting.", "name": "cursorOffset", "pluginDefaults": {}, "range": { "end": null, "start": -1, "step": 1 }, @@ -1001,7 +1001,7 @@ exports[`CLI --support-info (stdout) 1`] = ` { "category": "Special", "default": null, - "description": "Format code ending at a given character offset (exclusive).\\nThe range will extend forwards to the end of the selected statement.\\nThis option cannot be used with --cursor-offset.", + "description": "Format code ending at a given character offset (exclusive).\\nThe range will extend forwards to the end of the selected statement.", "name": "rangeEnd", "pluginDefaults": {}, "range": { "end": null, "start": 0, "step": 1 }, @@ -1010,7 +1010,7 @@ exports[`CLI --support-info (stdout) 1`] = ` { "category": "Special", "default": 0, - "description": "Format code starting at a given character offset.\\nThe range will extend backwards to the start of the first line containing the selected statement.\\nThis option cannot be used with --cursor-offset.", + "description": "Format code starting at a given character offset.\\nThe range will extend backwards to the start of the first line containing the selected statement.", "name": "rangeStart", "pluginDefaults": {}, "range": { "end": null, "start": 0, "step": 1 }, diff --git a/tests/integration/__tests__/bundle.js b/tests/integration/__tests__/bundle.js index b1f20632e..d74c2dcb6 100644 --- a/tests/integration/__tests__/bundle.js +++ b/tests/integration/__tests__/bundle.js @@ -118,7 +118,9 @@ test("Commonjs version", () => { expect(typeof prettierCommonjsVersion.util.getStringWidth).toBe("function"); expect(Object.keys(prettierCommonjsVersion.__debug).sort()).toEqual( - Object.keys(prettier.__debug).sort(), + Object.keys(prettier.__debug) + .filter((key) => key !== "mockable") + .sort(), ); expect(typeof prettierCommonjsVersion.__debug.parse).toBe("function"); diff --git a/tests/integration/__tests__/config-invalid.js b/tests/integration/__tests__/config-invalid.js index 7cf19705a..4becfe576 100644 --- a/tests/integration/__tests__/config-invalid.js +++ b/tests/integration/__tests__/config-invalid.js @@ -1,3 +1,4 @@ +import fs from "node:fs/promises"; import outdent from "outdent"; import jestPathSerializer from "../path-serializer.js"; @@ -178,3 +179,31 @@ describe("Invalid config value", () => { stderr: "", }); }); + +// Can't put a invalid `package.json` file in the test dir +test("Invalid package.json", async () => { + const packageJsonFile = new URL( + "../cli/config/invalid/broken-package-json/package.json", + import.meta.url, + ); + + try { + await fs.writeFile(packageJsonFile, '{"prettier":{}}'); + const { stdout: configFileForValidPackageJson } = await runCli( + "cli/config/invalid/broken-package-json", + ["--find-config-path", "foo.js"], + ); + + expect(configFileForValidPackageJson).toBe("package.json"); + + await fs.writeFile(packageJsonFile, '{"prettier":{'); + const { stdout: configFileForInvalidPackageJson } = await runCli( + "cli/config/invalid/broken-package-json", + ["--find-config-path", "foo.js"], + ); + + expect(configFileForInvalidPackageJson).toBe(".prettierrc"); + } finally { + await fs.rm(packageJsonFile, { force: true }); + } +}); diff --git a/tests/integration/__tests__/mockable.js b/tests/integration/__tests__/mockable.js index bde8dcb97..68b5f53ea 100644 --- a/tests/integration/__tests__/mockable.js +++ b/tests/integration/__tests__/mockable.js @@ -1,60 +1,7 @@ -import path from "node:path"; -import { pathToFileURL } from "node:url"; -import createEsmUtils from "esm-utils"; -import { mockable } from "../env.js"; +import prettier from "../../config/prettier-entry.js"; -const { __dirname } = createEsmUtils(import.meta); +const { mockable } = prettier.__debug; -// This don't has to be the same result as `prettier.resolveConfig`, -// Because we are testing with default `lilconfigOptions` -describe("lilconfig", () => { - let lilconfig; - beforeAll(async () => { - ({ - default: { lilconfig }, - } = await import(pathToFileURL(mockable))); - }); - - const configs = [ - { - title: "prettier.config.cjs", - dirname: path.join(__dirname, "../cli/config/js/"), - file: path.join(__dirname, "../cli/config/js/prettier.config.cjs"), - value: { - endOfLine: "auto", - tabWidth: 8, - }, - }, - { - title: "package.json", - dirname: path.join(__dirname, "../cli/config/package/"), - file: path.join(__dirname, "../cli/config/package/package.json"), - value: { - tabWidth: 3, - overrides: [ - { - files: "*.ts", - options: { - tabWidth: 5, - }, - }, - ], - }, - }, - ]; - - for (const { title, dirname, file, value } of configs) { - test(`async version ${title}`, async () => { - const { config, filepath } = await lilconfig("prettier").search(dirname); - expect(config).toEqual(value); - expect(filepath).toBe(file); - }); - } -}); - -test("isCI", async () => { - const { - default: { isCI }, - } = await import(pathToFileURL(mockable)); - expect(typeof isCI()).toBe("boolean"); +test("isCI", () => { + expect(typeof mockable.isCI()).toBe("boolean"); }); diff --git a/tests/integration/__tests__/patterns-dirs.js b/tests/integration/__tests__/patterns-dirs.js index 7963780f9..1ce748d19 100644 --- a/tests/integration/__tests__/patterns-dirs.js +++ b/tests/integration/__tests__/patterns-dirs.js @@ -321,6 +321,25 @@ function isSymlinkSupported() { { stdout: "test-a/symlink-to-directory-b/b.js" }, base, ); + + testPatterns( + "", + [ + "test-a/symlink-to-file-b", + "--no-error-on-unmatched-pattern", + "--log-level", + "debug", + ], + { + status: 0, + stdout: "", + stderr: + '[debug] normalized argv: {"":["test-a/symlink-to-file-b"],"cache":false,"color":true,"editorconfig":true,"errorOnUnmatchedPattern":false,"logLevel":"debug","ignorePath":[".prettierignore"],"configPrecedence":"cli-override","debugRepeat":0,"plugins":[],"listDifferent":true,"_":["test-a/symlink-to-file-b"],"__raw":{"_":["test-a/symlink-to-file-b"],"cache":false,"color":true,"editorconfig":true,"error-on-unmatched-pattern":false,"l":true,"log-level":"debug","ignore-path":".prettierignore","config-precedence":"cli-override","debug-repeat":0,"plugin":[]}}' + + "\n" + + '[debug] Skipping pattern "test-a/symlink-to-file-b", as it is a symbolic link.', + }, + base, + ); }); function testPatterns( diff --git a/tests/integration/cli-worker.js b/tests/integration/cli-worker.js index fd760126f..583569fab 100644 --- a/tests/integration/cli-worker.js +++ b/tests/integration/cli-worker.js @@ -3,8 +3,7 @@ import fs from "node:fs"; import path from "node:path"; import url from "node:url"; import readline from "node:readline"; -import { lilconfig } from "lilconfig"; -import { prettierCli, mockable as mockableModuleFile } from "./env.js"; +import { prettierCli, prettierMainEntry } from "./env.js"; const normalizeToPosix = path.sep === "\\" @@ -56,9 +55,8 @@ async function run() { process.stdin.isTTY = Boolean(options.isTTY); process.stdout.isTTY = Boolean(options.stdoutIsTTY); - const { default: mockable } = await import( - url.pathToFileURL(mockableModuleFile) - ); + const prettier = await import(url.pathToFileURL(prettierMainEntry)); + const { mockable } = prettier.__debug; // We cannot use `jest.setMock("get-stream", impl)` here, because in the // production build everything is bundled into one file so there is no @@ -66,11 +64,8 @@ async function run() { // eslint-disable-next-line require-await mockable.getStdin = async () => options.input || ""; mockable.isCI = () => Boolean(options.ci); - mockable.lilconfig = (moduleName, options) => - lilconfig(moduleName, { - ...options, - stopDir: url.fileURLToPath(new URL("./cli", import.meta.url)), - }); + mockable.getPrettierConfigSearchStopDirectory = () => + url.fileURLToPath(new URL("./cli", import.meta.url)); // eslint-disable-next-line require-await mockable.writeFormattedFile = async (filename, content) => { filename = normalizeToPosix(path.relative(process.cwd(), filename)); diff --git a/tests/integration/cli/config/invalid/broken-package-json/.prettierignore b/tests/integration/cli/config/invalid/broken-package-json/.prettierignore new file mode 100644 index 000000000..396a8fc23 --- /dev/null +++ b/tests/integration/cli/config/invalid/broken-package-json/.prettierignore @@ -0,0 +1,2 @@ +# will be created by test +package.json diff --git a/tests/integration/cli/config/invalid/broken-package-json/.prettierrc b/tests/integration/cli/config/invalid/broken-package-json/.prettierrc new file mode 100644 index 000000000..0967ef424 --- /dev/null +++ b/tests/integration/cli/config/invalid/broken-package-json/.prettierrc @@ -0,0 +1 @@ +{} diff --git a/tests/integration/env.js b/tests/integration/env.js index 5effb781d..a5cac1b69 100644 --- a/tests/integration/env.js +++ b/tests/integration/env.js @@ -11,10 +11,10 @@ const prettierCli = path.join( typeof bin === "object" ? bin.prettier : bin, ); -const mockable = isProduction - ? path.join(PRETTIER_DIR, "./internal/internal.mjs") - : path.join(PRETTIER_DIR, "./src/common/mockable.js"); +const prettierMainEntry = isProduction + ? path.join(PRETTIER_DIR, "./index.mjs") + : path.join(PRETTIER_DIR, "./src/index.js"); const projectRoot = path.join(__dirname, "../.."); -export { isProduction, mockable, prettierCli, projectRoot }; +export { isProduction, prettierMainEntry, prettierCli, projectRoot }; diff --git a/website/blog/2023-11-13-curious-ternaries.md b/website/blog/2023-11-13-curious-ternaries.md index def3a01d6..25ff8e16d 100644 --- a/website/blog/2023-11-13-curious-ternaries.md +++ b/website/blog/2023-11-13-curious-ternaries.md @@ -80,8 +80,7 @@ const animalName = pet.isScary() ? 'wolf' : 'dog' - : pet.canMeow() ? - 'cat' + : pet.canMeow() ? 'cat' : 'probably a bunny'; ``` diff --git a/website/playground/Playground.js b/website/playground/Playground.js index c7fa74552..a24e04e81 100644 --- a/website/playground/Playground.js +++ b/website/playground/Playground.js @@ -104,7 +104,15 @@ class Playground extends React.Component { this.setContent = (content) => this.setState({ content }); this.clearContent = this.setContent.bind(this, ""); this.resetOptions = () => this.setState({ options: defaultOptions }); - this.setSelection = (selection) => this.setState({ selection }); + this.setSelection = (selection) => { + this.setState({ selection }); + if (this.state.trackCursorOffset) { + this.handleOptionValueChange( + this.cursorOffsetOption, + util.convertSelectionToRange(selection, this.state.content)[0], + ); + } + }; this.setSelectionAsRange = () => { const { selection, content, options } = this.state; const [rangeStart, rangeEnd] = util.convertSelectionToRange( @@ -126,6 +134,9 @@ class Playground extends React.Component { this.rangeEndOption = props.availableOptions.find( (opt) => opt.name === "rangeEnd", ); + this.cursorOffsetOption = props.availableOptions.find( + (opt) => opt.name === "cursorOffset", + ); this.formatInput = this.formatInput.bind(this); this.insertDummyId = this.insertDummyId.bind(this); @@ -172,6 +183,7 @@ class Playground extends React.Component { ...ENABLED_OPTIONS, "rangeStart", "rangeEnd", + "cursorOffset", ]); const cliOptions = util.buildCliArgs(orderedOptions, options); @@ -247,7 +259,7 @@ class Playground extends React.Component { reformat={editorState.showSecondFormat} rethrowEmbedErrors={editorState.rethrowEmbedErrors} > - {({ formatted, debug }) => { + {({ formatted, debug, cursorOffset }) => { const fullReport = this.getMarkdown({ formatted, reformatted: debug.reformatted, @@ -294,6 +306,49 @@ class Playground extends React.Component { Set selected text as range + + ) ) : null} diff --git a/website/playground/panels.js b/website/playground/panels.js index 02117e843..7b39e6b75 100644 --- a/website/playground/panels.js +++ b/website/playground/panels.js @@ -97,10 +97,10 @@ class CodeMirrorPanel extends React.Component { } updateOverlay() { - if (!this.props.readOnly) { - if (this._overlay) { - this._codeMirror.removeOverlay(this._overlay); - } + if (this._overlay) { + this._codeMirror.removeOverlay(this._overlay); + } + if (this.props.overlayStart !== undefined) { const [start, end] = getIndexPosition(this.props.value, [ this.props.overlayStart, this.props.overlayEnd, diff --git a/website/versioned_docs/version-stable/api.md b/website/versioned_docs/version-stable/api.md index 139a9fa4d..25193d66a 100644 --- a/website/versioned_docs/version-stable/api.md +++ b/website/versioned_docs/version-stable/api.md @@ -27,7 +27,7 @@ await prettier.format("foo ( );", { semi: false, parser: "babel" }); `formatWithCursor` both formats the code, and translates a cursor position from unformatted code to formatted code. This is useful for editor integrations, to prevent the cursor from moving when code is formatted. -The `cursorOffset` option should be provided, to specify where the cursor is. This option cannot be used with `rangeStart` and `rangeEnd`. +The `cursorOffset` option should be provided, to specify where the cursor is. ```js await prettier.formatWithCursor(" 1", { cursorOffset: 2, parser: "babel" }); diff --git a/website/versioned_docs/version-stable/options.md b/website/versioned_docs/version-stable/options.md index b2ee7712b..2a4fb1577 100644 --- a/website/versioned_docs/version-stable/options.md +++ b/website/versioned_docs/version-stable/options.md @@ -255,8 +255,6 @@ These two options can be used to format code starting and ending at a given char - Backwards to the start of the first line containing the selected statement. - Forwards to the end of the selected statement. -These options cannot be used with `cursorOffset`. - | Default | CLI Override | API Override | | ---------- | --------------------- | ------------------- | | `0` | `--range-start ` | `rangeStart: ` | diff --git a/yarn.lock b/yarn.lock index 9c100daab..b35ca504b 100644 --- a/yarn.lock +++ b/yarn.lock @@ -45,23 +45,13 @@ __metadata: languageName: node linkType: hard -"@babel/code-frame@npm:7.22.13": - version: 7.22.13 - resolution: "@babel/code-frame@npm:7.22.13" - dependencies: - "@babel/highlight": ^7.22.13 - chalk: ^2.4.2 - checksum: 22e342c8077c8b77eeb11f554ecca2ba14153f707b85294fcf6070b6f6150aae88a7b7436dd88d8c9289970585f3fe5b9b941c5aa3aa26a6d5a8ef3f292da058 - languageName: node - linkType: hard - -"@babel/code-frame@npm:^7.0.0, @babel/code-frame@npm:^7.12.13, @babel/code-frame@npm:^7.21.4, @babel/code-frame@npm:^7.22.13, @babel/code-frame@npm:^7.23.4": - version: 7.23.4 - resolution: "@babel/code-frame@npm:7.23.4" +"@babel/code-frame@npm:7.23.5, @babel/code-frame@npm:^7.0.0, @babel/code-frame@npm:^7.12.13, @babel/code-frame@npm:^7.21.4, @babel/code-frame@npm:^7.22.13, @babel/code-frame@npm:^7.23.4": + version: 7.23.5 + resolution: "@babel/code-frame@npm:7.23.5" dependencies: "@babel/highlight": ^7.23.4 chalk: ^2.4.2 - checksum: 29999d08c3dbd803f3c296dae7f4f40af1f9e381d6bbc76e5a75327c4b8b023bcb2e209843d292f5d71c3b5c845df1da959d415ed862d6a68e0ad6c5c9622d37 + checksum: d90981fdf56a2824a9b14d19a4c0e8db93633fd488c772624b4e83e0ceac6039a27cd298a247c3214faa952bf803ba23696172ae7e7235f3b97f43ba278c569a languageName: node linkType: hard @@ -95,27 +85,15 @@ __metadata: languageName: node linkType: hard -"@babel/generator@npm:7.23.3": - version: 7.23.3 - resolution: "@babel/generator@npm:7.23.3" +"@babel/generator@npm:7.23.5, @babel/generator@npm:^7.23.3, @babel/generator@npm:^7.23.4, @babel/generator@npm:^7.7.2": + version: 7.23.5 + resolution: "@babel/generator@npm:7.23.5" dependencies: - "@babel/types": ^7.23.3 + "@babel/types": ^7.23.5 "@jridgewell/gen-mapping": ^0.3.2 "@jridgewell/trace-mapping": ^0.3.17 jsesc: ^2.5.1 - checksum: b6e71cca852d4e1aa01a28a30b8c74ffc3b8d56ccb7ae3ee783028ee015f63ad861a2e386c3eb490a9a8634db485a503a33521680f4af510151e90346c46da17 - languageName: node - linkType: hard - -"@babel/generator@npm:^7.23.3, @babel/generator@npm:^7.23.4, @babel/generator@npm:^7.7.2": - version: 7.23.4 - resolution: "@babel/generator@npm:7.23.4" - dependencies: - "@babel/types": ^7.23.4 - "@jridgewell/gen-mapping": ^0.3.2 - "@jridgewell/trace-mapping": ^0.3.17 - jsesc: ^2.5.1 - checksum: 7403717002584eaeb58559f4d0de19b79e924ef2735711278f7cb5206d081428bf3960578566d6fa4102b7b30800d44f70acffea5ecef83f0cb62361c2a23062 + checksum: 845ddda7cf38a3edf4be221cc8a439dee9ea6031355146a1a74047aa8007bc030305b27d8c68ec9e311722c910610bde38c0e13a9ce55225251e7cb7e7f3edc8 languageName: node linkType: hard @@ -207,7 +185,7 @@ __metadata: languageName: node linkType: hard -"@babel/helper-string-parser@npm:^7.22.5, @babel/helper-string-parser@npm:^7.23.4": +"@babel/helper-string-parser@npm:^7.23.4": version: 7.23.4 resolution: "@babel/helper-string-parser@npm:7.23.4" checksum: c0641144cf1a7e7dc93f3d5f16d5327465b6cf5d036b48be61ecba41e1eece161b48f46b7f960951b67f8c3533ce506b16dece576baef4d8b3b49f8c65410f90 @@ -239,7 +217,7 @@ __metadata: languageName: node linkType: hard -"@babel/highlight@npm:^7.0.0, @babel/highlight@npm:^7.22.13, @babel/highlight@npm:^7.23.4": +"@babel/highlight@npm:^7.0.0, @babel/highlight@npm:^7.23.4": version: 7.23.4 resolution: "@babel/highlight@npm:7.23.4" dependencies: @@ -250,12 +228,12 @@ __metadata: languageName: node linkType: hard -"@babel/parser@npm:7.23.4, @babel/parser@npm:^7.1.0, @babel/parser@npm:^7.14.7, @babel/parser@npm:^7.20.7, @babel/parser@npm:^7.22.15, @babel/parser@npm:^7.23.3, @babel/parser@npm:^7.23.4": - version: 7.23.4 - resolution: "@babel/parser@npm:7.23.4" +"@babel/parser@npm:7.23.5, @babel/parser@npm:^7.1.0, @babel/parser@npm:^7.14.7, @babel/parser@npm:^7.20.7, @babel/parser@npm:^7.22.15, @babel/parser@npm:^7.23.3, @babel/parser@npm:^7.23.4": + version: 7.23.5 + resolution: "@babel/parser@npm:7.23.5" bin: parser: ./bin/babel-parser.js - checksum: 1d90e17d966085b8ea12f357ffcc76568969364481254f0ae3e7ed579e9421d31c7fd3876ccb3b215a5b2ada48251b0c2d0f21ba225ee194f0e18295b49085f2 + checksum: ea763629310f71580c4a3ea9d3705195b7ba994ada2cc98f9a584ebfdacf54e92b2735d351672824c2c2b03c7f19206899f4d95650d85ce514a822b19a8734c7 languageName: node linkType: hard @@ -442,25 +420,14 @@ __metadata: languageName: node linkType: hard -"@babel/types@npm:7.23.3": - version: 7.23.3 - resolution: "@babel/types@npm:7.23.3" - dependencies: - "@babel/helper-string-parser": ^7.22.5 - "@babel/helper-validator-identifier": ^7.22.20 - to-fast-properties: ^2.0.0 - checksum: b96f1ec495351aeb2a5f98dd494aafa17df02a351548ae96999460f35c933261c839002a34c1e83552ff0d9f5e94d0b5b8e105d38131c7c9b0f5a6588676f35d - languageName: node - linkType: hard - -"@babel/types@npm:^7.0.0, @babel/types@npm:^7.20.7, @babel/types@npm:^7.22.15, @babel/types@npm:^7.22.5, @babel/types@npm:^7.23.0, @babel/types@npm:^7.23.3, @babel/types@npm:^7.23.4, @babel/types@npm:^7.3.3, @babel/types@npm:^7.8.3": - version: 7.23.4 - resolution: "@babel/types@npm:7.23.4" +"@babel/types@npm:7.23.5, @babel/types@npm:^7.0.0, @babel/types@npm:^7.20.7, @babel/types@npm:^7.22.15, @babel/types@npm:^7.22.5, @babel/types@npm:^7.23.0, @babel/types@npm:^7.23.3, @babel/types@npm:^7.23.4, @babel/types@npm:^7.23.5, @babel/types@npm:^7.3.3, @babel/types@npm:^7.8.3": + version: 7.23.5 + resolution: "@babel/types@npm:7.23.5" dependencies: "@babel/helper-string-parser": ^7.23.4 "@babel/helper-validator-identifier": ^7.22.20 to-fast-properties: ^2.0.0 - checksum: 8a1ab20da663d202b1c090fdef4b157d3c7d8cb1cf60ea548f887d7b674935371409804d6cba52f870c22ced7685fcb41b0578d3edde720990de00cbb328da54 + checksum: 3d21774480a459ef13b41c2e32700d927af649e04b70c5d164814d8e04ab584af66a93330602c2925e1a6925c2b829cc153418a613a4e7d79d011be1f29ad4b2 languageName: node linkType: hard @@ -1967,15 +1934,15 @@ __metadata: languageName: node linkType: hard -"@typescript-eslint/eslint-plugin@npm:6.10.0": - version: 6.10.0 - resolution: "@typescript-eslint/eslint-plugin@npm:6.10.0" +"@typescript-eslint/eslint-plugin@npm:6.13.2": + version: 6.13.2 + resolution: "@typescript-eslint/eslint-plugin@npm:6.13.2" dependencies: "@eslint-community/regexpp": ^4.5.1 - "@typescript-eslint/scope-manager": 6.10.0 - "@typescript-eslint/type-utils": 6.10.0 - "@typescript-eslint/utils": 6.10.0 - "@typescript-eslint/visitor-keys": 6.10.0 + "@typescript-eslint/scope-manager": 6.13.2 + "@typescript-eslint/type-utils": 6.13.2 + "@typescript-eslint/utils": 6.13.2 + "@typescript-eslint/visitor-keys": 6.13.2 debug: ^4.3.4 graphemer: ^1.4.0 ignore: ^5.2.4 @@ -1988,7 +1955,7 @@ __metadata: peerDependenciesMeta: typescript: optional: true - checksum: eaf1f66ae1915426dad8d229c8cb80d2b320572a30c3fbc57d560d40edc2d17d004101a2fcbe331bc458df19a00f8b705f2442ee02e028bb595f4e9f9152e99d + checksum: e50cbbe7104eecef59faf3355ab981d9f353b19327f0b4607dfd829b4726f9e694b536fe43ab55f50bb00fbfdd2e4268a7e2a568b28d5fcd0d2a32a8d2466218 languageName: node linkType: hard @@ -2002,22 +1969,22 @@ __metadata: languageName: node linkType: hard -"@typescript-eslint/scope-manager@npm:6.10.0": - version: 6.10.0 - resolution: "@typescript-eslint/scope-manager@npm:6.10.0" +"@typescript-eslint/scope-manager@npm:6.13.2": + version: 6.13.2 + resolution: "@typescript-eslint/scope-manager@npm:6.13.2" dependencies: - "@typescript-eslint/types": 6.10.0 - "@typescript-eslint/visitor-keys": 6.10.0 - checksum: c9b9483082ae853f10b888cf04d4a14f666ac55e749bfdb7b7f726fc51127a6340b5e2f50d93f134a8854ddcc41f7b116b214753251a8b033d0d84c600439c54 + "@typescript-eslint/types": 6.13.2 + "@typescript-eslint/visitor-keys": 6.13.2 + checksum: ff8fd64ddf324e296e2e0e34a8f73149c9a5f14d1761ea8e8665fc5998faa2b0bbbd1a5d416aa10d725f13c804032d532f68e39a0ca6cc36d1c9b9c0aea94311 languageName: node linkType: hard -"@typescript-eslint/type-utils@npm:6.10.0": - version: 6.10.0 - resolution: "@typescript-eslint/type-utils@npm:6.10.0" +"@typescript-eslint/type-utils@npm:6.13.2": + version: 6.13.2 + resolution: "@typescript-eslint/type-utils@npm:6.13.2" dependencies: - "@typescript-eslint/typescript-estree": 6.10.0 - "@typescript-eslint/utils": 6.10.0 + "@typescript-eslint/typescript-estree": 6.13.2 + "@typescript-eslint/utils": 6.13.2 debug: ^4.3.4 ts-api-utils: ^1.0.1 peerDependencies: @@ -2025,7 +1992,7 @@ __metadata: peerDependenciesMeta: typescript: optional: true - checksum: cfe9520cf0c0f50b115d2591acb2abf99ffe5789b3536268ca65b624c8498812d91f187e80c41bea7cf2cebad9c38f69ef27440f872a20fb53c59856d8f5df38 + checksum: ba54e5746139f778c35e4058e523ec8c20b68cf6472b3a7784170328e48c228f0761d2fc7e43dab053ca7d85ac4378b6965567774e6afedf551e600638404215 languageName: node linkType: hard @@ -2036,10 +2003,10 @@ __metadata: languageName: node linkType: hard -"@typescript-eslint/types@npm:6.10.0": - version: 6.10.0 - resolution: "@typescript-eslint/types@npm:6.10.0" - checksum: e63a9e05eb3d736d02a09131627d5cb89394bf0d9d6b46fb4b620be902d89d73554720be65acbc194787bff9ffcd518c9a6cf88fd63e418232b4181e8d8438df +"@typescript-eslint/types@npm:6.13.2": + version: 6.13.2 + resolution: "@typescript-eslint/types@npm:6.13.2" + checksum: 4493ff06fa07c68c5adbcbd842f6dd6f5c88f14d160b53c3379b6b703e6f62808fab7fdebcc06ff06a56f20ab432b6ceeb0afb8931dc97d4061cb417e787f2c1 languageName: node linkType: hard @@ -2061,12 +2028,12 @@ __metadata: languageName: node linkType: hard -"@typescript-eslint/typescript-estree@npm:6.10.0": - version: 6.10.0 - resolution: "@typescript-eslint/typescript-estree@npm:6.10.0" +"@typescript-eslint/typescript-estree@npm:6.13.2": + version: 6.13.2 + resolution: "@typescript-eslint/typescript-estree@npm:6.13.2" dependencies: - "@typescript-eslint/types": 6.10.0 - "@typescript-eslint/visitor-keys": 6.10.0 + "@typescript-eslint/types": 6.13.2 + "@typescript-eslint/visitor-keys": 6.13.2 debug: ^4.3.4 globby: ^11.1.0 is-glob: ^4.0.3 @@ -2075,24 +2042,24 @@ __metadata: peerDependenciesMeta: typescript: optional: true - checksum: 15bd8d9239a557071d6b03e7aa854b769fcc2dbdff587ed94be7ee8060dabdb05bcae4251df22432f625f82087e7f6986e9aab04f7eea35af694d4edd76a21af + checksum: 0c18ee5ef594a2411a788fe9d7bc6d51a03bce38d9d764bcb24ab557e5bc1942c2ddf9bd6fb4877eb102b0ae488974fb7b7fe72daa70a2054bf04d3cc6803546 languageName: node linkType: hard -"@typescript-eslint/utils@npm:6.10.0": - version: 6.10.0 - resolution: "@typescript-eslint/utils@npm:6.10.0" +"@typescript-eslint/utils@npm:6.13.2": + version: 6.13.2 + resolution: "@typescript-eslint/utils@npm:6.13.2" dependencies: "@eslint-community/eslint-utils": ^4.4.0 "@types/json-schema": ^7.0.12 "@types/semver": ^7.5.0 - "@typescript-eslint/scope-manager": 6.10.0 - "@typescript-eslint/types": 6.10.0 - "@typescript-eslint/typescript-estree": 6.10.0 + "@typescript-eslint/scope-manager": 6.13.2 + "@typescript-eslint/types": 6.13.2 + "@typescript-eslint/typescript-estree": 6.13.2 semver: ^7.5.4 peerDependencies: eslint: ^7.0.0 || ^8.0.0 - checksum: b6bd4d68623fb8d616ae63a88f2954258411a0cc113029fba801d1e74b4c0319fdfbcac0070527afe5cc38c012c8718e4faecd1603000924d7b89e8fefc3f24d + checksum: b66bcf2a945e9c55f3dccb48af49565863d974837ee23b2f01ce7f3fb2462eb8a5871784d4a2fcc80dac7d5cd4ed90c8d01431cd177c0249de89a448f6663fc8 languageName: node linkType: hard @@ -2124,13 +2091,13 @@ __metadata: languageName: node linkType: hard -"@typescript-eslint/visitor-keys@npm:6.10.0": - version: 6.10.0 - resolution: "@typescript-eslint/visitor-keys@npm:6.10.0" +"@typescript-eslint/visitor-keys@npm:6.13.2": + version: 6.13.2 + resolution: "@typescript-eslint/visitor-keys@npm:6.13.2" dependencies: - "@typescript-eslint/types": 6.10.0 + "@typescript-eslint/types": 6.13.2 eslint-visitor-keys: ^3.4.1 - checksum: 9640bfae41e6109ffba31e68b1720382de0538d021261e2fc9e514c83c703084393c0818ca77ed26b950273e45e593371120281e8d4bbd09cb8c2d46c9fe4f03 + checksum: 4b4def7acd7451e6a18dab3ee13f06504b3d23e51f195fced7c544f2203ee8a83426c82fa57ab6b58725c70fdedaf7a3eccb69793180be35756eed0f2c69fe04 languageName: node linkType: hard @@ -3790,14 +3757,14 @@ __metadata: languageName: node linkType: hard -"eslint-config-prettier@npm:9.0.0": - version: 9.0.0 - resolution: "eslint-config-prettier@npm:9.0.0" +"eslint-config-prettier@npm:9.1.0": + version: 9.1.0 + resolution: "eslint-config-prettier@npm:9.1.0" peerDependencies: eslint: ">=7.0.0" bin: eslint-config-prettier: bin/cli.js - checksum: 362e991b6cb343f79362bada2d97c202e5303e6865888918a7445c555fb75e4c078b01278e90be98aa98ae22f8597d8e93d48314bec6824f540f7efcab3ce451 + checksum: 9229b768c879f500ee54ca05925f31b0c0bafff3d9f5521f98ff05127356de78c81deb9365c86a5ec4efa990cb72b74df8612ae15965b14136044c73e1f6a907 languageName: node linkType: hard @@ -4397,10 +4364,10 @@ __metadata: languageName: node linkType: hard -"flow-parser@npm:0.222.0": - version: 0.222.0 - resolution: "flow-parser@npm:0.222.0" - checksum: 286fbd397e86eca7c2aaf7d280e2385670d261f986b24122471b153d8c646d924b3679807103aacb6e60282ad7ed8fb0f4112ecff89f6d0995b59021f73c0c40 +"flow-parser@npm:0.223.3": + version: 0.223.3 + resolution: "flow-parser@npm:0.223.3" + checksum: 4c0df178ff2e9140f57b5e7321b11e1cb827e00fbad6f342742c5834bd313f1bb0fe84d919d36e0c593e916c4ae5c8a93fcdb42c4328d6c5d77d75c8eed12090 languageName: node linkType: hard @@ -4802,19 +4769,19 @@ __metadata: languageName: node linkType: hard -"hermes-estree@npm:0.17.1": - version: 0.17.1 - resolution: "hermes-estree@npm:0.17.1" - checksum: ffa6f997ad0b2a0dfe8ec782fc8cc5224a0d943b330944e62fe58c93c1f590afb67ba064d5a308c51a824b0db6e1bdc1654bfaf6bdfb4b0de4fb8f9cd8cf1050 +"hermes-estree@npm:0.18.0": + version: 0.18.0 + resolution: "hermes-estree@npm:0.18.0" + checksum: c99ef2daf0e838bd738aa53e037e66b04c6e2bdc5426c460743a63fa55113d16a91045f2706e3ea99977e2291dd1a23746aeb0c9fe1bfe8d2fbced1a513e2740 languageName: node linkType: hard -"hermes-parser@npm:0.17.1": - version: 0.17.1 - resolution: "hermes-parser@npm:0.17.1" +"hermes-parser@npm:0.18.0": + version: 0.18.0 + resolution: "hermes-parser@npm:0.18.0" dependencies: - hermes-estree: 0.17.1 - checksum: 0a8fd611c708ec076654e9b7aed4b8c5b4302bdef87402a66e9c09ec3f925aa3c12718c80ebc52154ec5712a348ad375a69838f243c9bc2189ec6459415d6760 + hermes-estree: 0.18.0 + checksum: 163202f1916f1df34a560148d626eb9a82eb2b9738882cff350853051f4ebf5c56472c64029f17408ce1b1ea88309108970687dd586630febb57fea9af7e1b56 languageName: node linkType: hard @@ -6363,13 +6330,6 @@ __metadata: languageName: node linkType: hard -"lilconfig@npm:2.1.0": - version: 2.1.0 - resolution: "lilconfig@npm:2.1.0" - checksum: 8549bb352b8192375fed4a74694cd61ad293904eee33f9d4866c2192865c44c4eb35d10782966242634e0cbc1e91fe62b1247f148dc5514918e3a966da7ea117 - languageName: node - linkType: hard - "lines-and-columns@npm:2.0.4, lines-and-columns@npm:^2.0.3": version: 2.0.4 resolution: "lines-and-columns@npm:2.0.4" @@ -6778,7 +6738,7 @@ __metadata: languageName: node linkType: hard -"nanoid@npm:^3.3.6": +"nanoid@npm:^3.3.7": version: 3.3.7 resolution: "nanoid@npm:3.3.7" bin: @@ -7420,14 +7380,14 @@ __metadata: languageName: node linkType: hard -"postcss@npm:8.4.31": - version: 8.4.31 - resolution: "postcss@npm:8.4.31" +"postcss@npm:8.4.32": + version: 8.4.32 + resolution: "postcss@npm:8.4.32" dependencies: - nanoid: ^3.3.6 + nanoid: ^3.3.7 picocolors: ^1.0.0 source-map-js: ^1.0.2 - checksum: 1d8611341b073143ad90486fcdfeab49edd243377b1f51834dc4f6d028e82ce5190e4f11bb2633276864503654fb7cab28e67abdc0fbf9d1f88cad4a0ff0beea + checksum: 220d9d0bf5d65be7ed31006c523bfb11619461d296245c1231831f90150aeb4a31eab9983ac9c5c89759a3ca8b60b3e0d098574964e1691673c3ce5c494305ae languageName: node linkType: hard @@ -7452,10 +7412,10 @@ __metadata: resolution: "prettier@workspace:." dependencies: "@angular/compiler": 17.0.2 - "@babel/code-frame": 7.22.13 - "@babel/generator": 7.23.3 - "@babel/parser": 7.23.4 - "@babel/types": 7.23.3 + "@babel/code-frame": 7.23.5 + "@babel/generator": 7.23.5 + "@babel/parser": 7.23.5 + "@babel/types": 7.23.5 "@glimmer/reference": 0.85.13 "@glimmer/syntax": 0.85.13 "@iarna/toml": 2.2.5 @@ -7466,9 +7426,9 @@ __metadata: "@types/file-entry-cache": 5.0.4 "@types/find-cache-dir": 3.2.1 "@types/jest": 29.5.8 - "@typescript-eslint/eslint-plugin": 6.10.0 - "@typescript-eslint/typescript-estree": 6.10.0 - "@typescript-eslint/visitor-keys": 6.10.0 + "@typescript-eslint/eslint-plugin": 6.13.2 + "@typescript-eslint/typescript-estree": 6.13.2 + "@typescript-eslint/visitor-keys": 6.13.2 acorn: 8.11.2 acorn-jsx: 5.3.2 angular-estree-parser: 9.0.0 @@ -7494,7 +7454,7 @@ __metadata: esbuild-visualizer: 0.4.1 escape-string-regexp: 5.0.0 eslint: 8.53.0 - eslint-config-prettier: 9.0.0 + eslint-config-prettier: 9.1.0 eslint-formatter-friendly: 7.0.0 eslint-plugin-compat: 4.2.0 eslint-plugin-import: 2.29.0 @@ -7511,11 +7471,11 @@ __metadata: fast-json-stable-stringify: 2.1.0 file-entry-cache: 7.0.2 find-cache-dir: 5.0.0 - flow-parser: 0.222.0 + flow-parser: 0.223.3 get-east-asian-width: 1.2.0 get-stdin: 9.0.0 graphql: 16.8.1 - hermes-parser: 0.17.1 + hermes-parser: 0.18.0 html-element-attributes: 3.3.0 html-tag-names: 2.1.0 html-ua-styles: 0.0.3 @@ -7531,7 +7491,6 @@ __metadata: js-yaml: 4.1.0 json5: 2.2.3 leven: 4.0.0 - lilconfig: 2.1.0 lines-and-columns: 2.0.4 linguist-languages: 7.27.0 magic-string: 0.30.5 @@ -7544,7 +7503,7 @@ __metadata: outdent: 0.8.0 parse-json: 8.1.0 please-upgrade-node: 3.2.0 - postcss: 8.4.31 + postcss: 8.4.32 postcss-less: 6.0.0 postcss-media-query-parser: 0.2.3 postcss-scss: 4.0.9 @@ -7565,7 +7524,7 @@ __metadata: tempy: 3.1.0 to-fast-properties: 4.0.0 ts-expect: 1.3.0 - typescript: 5.2.2 + typescript: 5.3.2 unicode-regex: 4.0.0 unified: 9.2.2 url-or-path: 2.3.0 @@ -9020,23 +8979,23 @@ __metadata: languageName: node linkType: hard -"typescript@npm:5.2.2": - version: 5.2.2 - resolution: "typescript@npm:5.2.2" +"typescript@npm:5.3.2": + version: 5.3.2 + resolution: "typescript@npm:5.3.2" bin: tsc: bin/tsc tsserver: bin/tsserver - checksum: 7912821dac4d962d315c36800fe387cdc0a6298dba7ec171b350b4a6e988b51d7b8f051317786db1094bd7431d526b648aba7da8236607febb26cf5b871d2d3c + checksum: d92534dda639eb825db013203404c1fabca8ac630564283c9e7dc9e64fd9c9346c2de95ecebdf3e6e8c1c32941bca1cfe0da37877611feb9daf8feeaea58d230 languageName: node linkType: hard -"typescript@patch:typescript@5.2.2#~builtin": - version: 5.2.2 - resolution: "typescript@patch:typescript@npm%3A5.2.2#~builtin::version=5.2.2&hash=f3b441" +"typescript@patch:typescript@5.3.2#~builtin": + version: 5.3.2 + resolution: "typescript@patch:typescript@npm%3A5.3.2#~builtin::version=5.3.2&hash=e012d7" bin: tsc: bin/tsc tsserver: bin/tsserver - checksum: 0f4da2f15e6f1245e49db15801dbee52f2bbfb267e1c39225afdab5afee1a72839cd86000e65ee9d7e4dfaff12239d28beaf5ee431357fcced15fb08583d72ca + checksum: 47b2e63418ea7ef7dd0bf359ee41c6fca852c680826089269c5d03673ead471e052b172561f377f9e51212054e5f0fe19dd58085ff7db7b168449a6af704c784 languageName: node linkType: hard