Merge branch 'main' into next
# Conflicts: # package.json # tests/css/atrule/each.css # tests/css/atrule/for.css # tests/css/atrule/if-else.css # tests/css/atrule/include.css # tests/css/atrule/while.css # tests/format/css/atrule/each.css # tests/format/css/atrule/for.css # tests/format/css/atrule/if-else.css # tests/format/css/atrule/include.css # tests/format/css/atrule/while.css # tests/scss/atrule/each.scss # tests/scss/atrule/for.scss # tests/scss/atrule/if-else.scss # tests/scss/atrule/include.scss # tests/scss/atrule/while.scss # yarn.lock
This commit is contained in:
commit
60619338f1
6814 files changed
+4413
-1515
No files matched your search
+3
-3
@@ -1,6 +1,7 @@
|
||||
!/*.js
|
||||
/tests/**/*.js
|
||||
!/tests/**/jsfmt.spec.js
|
||||
/tests/format/**/*.js
|
||||
/tests/integration/cli/
|
||||
!/tests/format/**/jsfmt.spec.js
|
||||
!/**/.eslintrc.js
|
||||
/test*.js
|
||||
/scripts/release/node_modules
|
||||
@@ -10,4 +11,3 @@
|
||||
/website/build/
|
||||
/website/static/playground.js
|
||||
/website/static/lib/
|
||||
/tests_integration/cli/
|
||||
+4
-1
@@ -91,7 +91,9 @@ overrides:
|
||||
parserOptions:
|
||||
sourceType: module
|
||||
- files:
|
||||
- "{tests,tests_config,tests_integration}/**/*.js"
|
||||
- "tests/format/**/jsfmt.spec.js"
|
||||
- "tests/config/**/*.js"
|
||||
- "tests/integration/**/*.js"
|
||||
env:
|
||||
jest: true
|
||||
plugins:
|
||||
@@ -120,6 +122,7 @@ overrides:
|
||||
rules:
|
||||
prettier-internal-rules/consistent-negative-index-access: error
|
||||
prettier-internal-rules/flat-ast-path-call: error
|
||||
prettier-internal-rules/no-conflicting-comment-check-flags: error
|
||||
prettier-internal-rules/no-doc-builder-concat: error
|
||||
prettier-internal-rules/no-empty-flat-contents-for-if-break: error
|
||||
prettier-internal-rules/no-unnecessary-ast-path-call: error
|
||||
|
||||
@@ -28,6 +28,9 @@ f56d620be529b60c13032681446c1eb76e0fb088
|
||||
# 2.0.0
|
||||
9dad95b35f935edce4c3d6cfa45c79a0b9c82b9f
|
||||
|
||||
# Restructure test files (#10415)
|
||||
ece93681f1010796e7d8eb4394196ccaef0cbc9c
|
||||
|
||||
# Categorize tests (#8239 #8248 #8249 #8251)
|
||||
b585bd6fa4d750a98e277303c428edfc48fea3f4
|
||||
f8c5b1fd1da4d67bc09d12bc3411b70d0fa4f4a1
|
||||
|
||||
@@ -15,6 +15,13 @@ updates:
|
||||
day: sunday
|
||||
time: "01:00"
|
||||
|
||||
- package-ecosystem: "npm"
|
||||
directory: "/scripts/release"
|
||||
schedule:
|
||||
interval: weekly
|
||||
day: sunday
|
||||
time: "01:00"
|
||||
|
||||
- package-ecosystem: "github-actions"
|
||||
directory: "/"
|
||||
schedule:
|
||||
|
||||
@@ -42,7 +42,7 @@ jobs:
|
||||
|
||||
- name: Install Client Package
|
||||
if: matrix.NPM_CLIENT == 'pnpm'
|
||||
run: npm install --global ${{ matrix.NPM_CLIENT }}
|
||||
run: npm install --global pnpm@5
|
||||
|
||||
- name: Run Tests
|
||||
run: yarn test:dev-package --maxWorkers=2
|
||||
@@ -19,21 +19,26 @@ jobs:
|
||||
- "macos-latest"
|
||||
- "windows-latest"
|
||||
node:
|
||||
- "16"
|
||||
- "14"
|
||||
- "12"
|
||||
- "10"
|
||||
include:
|
||||
# only enable coverage on the fastest job
|
||||
- os: "ubuntu-latest"
|
||||
node: "14"
|
||||
node: "16"
|
||||
ENABLE_CODE_COVERAGE: true
|
||||
FULL_TEST: true
|
||||
CHECK_TEST_PARSERS: true
|
||||
- os: "ubuntu-latest"
|
||||
node: "15"
|
||||
exclude:
|
||||
- os: "macos-latest"
|
||||
node: "14"
|
||||
- os: "macos-latest"
|
||||
node: "12"
|
||||
- os: "windows-latest"
|
||||
node: "14"
|
||||
- os: "windows-latest"
|
||||
node: "12"
|
||||
env:
|
||||
@@ -66,19 +71,19 @@ jobs:
|
||||
run: yarn test --maxWorkers=2
|
||||
|
||||
- name: Upload Coverage
|
||||
uses: codecov/codecov-action@v1.3.1
|
||||
uses: codecov/codecov-action@v1.4.1
|
||||
if: matrix.ENABLE_CODE_COVERAGE
|
||||
with:
|
||||
fail_ci_if_error: true
|
||||
|
||||
# #8073 test
|
||||
- name: Run Tests (PRETTIER_FALLBACK_RESOLVE)
|
||||
run: yarn test "tests_integration/__tests__/(config|plugin)"
|
||||
run: yarn test "tests/integration/__tests__/(config|plugin)"
|
||||
env:
|
||||
PRETTIER_FALLBACK_RESOLVE: true
|
||||
|
||||
- name: Upload Coverage (PRETTIER_FALLBACK_RESOLVE)
|
||||
uses: codecov/codecov-action@v1.3.1
|
||||
uses: codecov/codecov-action@v1.4.1
|
||||
if: matrix.ENABLE_CODE_COVERAGE
|
||||
with:
|
||||
fail_ci_if_error: true
|
||||
@@ -24,7 +24,7 @@ jobs:
|
||||
|
||||
- name: Cache Build Results
|
||||
id: build-cache
|
||||
uses: actions/cache@v2.1.4
|
||||
uses: actions/cache@v2.1.5
|
||||
with:
|
||||
path: .cache
|
||||
key: v2-build-cache-${{ hashFiles('yarn.lock') }}-${{ hashFiles('scripts/build/**/*') }}-${{ github.ref }}-
|
||||
@@ -85,18 +85,23 @@ jobs:
|
||||
- "macos-latest"
|
||||
- "windows-latest"
|
||||
node:
|
||||
- "16"
|
||||
- "14"
|
||||
- "12"
|
||||
- "10"
|
||||
include:
|
||||
- os: "ubuntu-latest"
|
||||
node: "14"
|
||||
node: "16"
|
||||
FULL_TEST: true
|
||||
- os: "ubuntu-latest"
|
||||
node: "15"
|
||||
exclude:
|
||||
- os: "macos-latest"
|
||||
node: "14"
|
||||
- os: "macos-latest"
|
||||
node: "12"
|
||||
- os: "windows-latest"
|
||||
node: "14"
|
||||
- os: "windows-latest"
|
||||
node: "12"
|
||||
env:
|
||||
@@ -140,7 +145,7 @@ jobs:
|
||||
|
||||
# #8073 test
|
||||
- name: Run Tests (PRETTIER_FALLBACK_RESOLVE)
|
||||
run: yarn test "tests_integration/__tests__/(config|plugin)"
|
||||
run: yarn test "tests/integration/__tests__/(config|plugin)"
|
||||
env:
|
||||
NODE_ENV: production
|
||||
PRETTIER_FALLBACK_RESOLVE: true
|
||||
+5
-5
@@ -1,11 +1,11 @@
|
||||
dist/
|
||||
.cache/
|
||||
coverage/
|
||||
/tests/**/*.*
|
||||
!/tests/**/jsfmt.spec.js
|
||||
/tests_integration/cli/
|
||||
/tests_integration/plugins/
|
||||
/tests_integration/custom-parsers/
|
||||
/tests/format/**/*.*
|
||||
!/tests/format/**/jsfmt.spec.js
|
||||
/tests/integration/cli/
|
||||
/tests/integration/plugins/
|
||||
/tests/integration/custom-parsers/
|
||||
/website/build/
|
||||
/website/static/lib/
|
||||
/website/static/playground.js
|
||||
|
||||
+1
-1
@@ -51,7 +51,7 @@ Parameters:
|
||||
- **`parsers`**: A list of parser names. The tests verify that the parsers in this list produce the same output. If the list includes `typescript`, then `babel-ts` is included implicitly. If the list includes `babel`, and the current directory is inside `tests/js`, then `espree` and `meriyah` are included implicitly.
|
||||
- **`options`**: In addition to Prettier's formatting option, can contain the `errors` property to specify that it's expected that the formatting shouldn't be successful and an error should be thrown for all (`errors: true`) or some combinations of input entries and parsers.
|
||||
|
||||
The implementation of `run_spec` can be found in [`tests_config/run_spec.js`](tests_config/run_spec.js).
|
||||
The implementation of `run_spec` can be found in [`tests/config/format-test.js`](tests/config/format-test.js).
|
||||
|
||||
`tests/flow-repo/` contains the Flow test suite and is not supposed to be edited by hand. To update it, clone the Flow repo next to the Prettier repo and run: `node scripts/sync-flow-tests.js ../flow/tests/`.
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#### Fix `lineSuffixBoundary` (#10122 by @thorn0)
|
||||
#### Fix `lineSuffixBoundary` IR command (#10122 by @thorn0)
|
||||
|
||||
There was a bug in the implementation of the [`lineSuffixBoundary`][lsb] command that significantly limited its usefulness: the printer algorithm didn't correctly consider it a potential line break. Now that the bug has been fixed, we urge plugin authors to give this command another try and see if it can help them simplify printing of trailing comments.
|
||||
|
||||
|
||||
@@ -33,3 +33,5 @@ To print a sub-property of the current node, use `["property1", "property2"]`:
|
||||
+ return print(["child", "child"]);
|
||||
}
|
||||
```
|
||||
|
||||
See also an example in the [docs](https://prettier.io/docs/en/plugins.html#print).
|
||||
@@ -1,3 +1,3 @@
|
||||
#### Treat `.prettierrc` as `yaml` (#8105 by @fisker)
|
||||
#### Treat `.prettierrc` as YAML when formatting it (#8105 by @fisker)
|
||||
|
||||
`.prettierrc` file can written in both JSON and YAML, previously we infer the parser to be `json`, if it's write in YAML, there will be a `SyntaxError` thrown when formatting it, now it's treat as a YAML file, but if it's write in JSON, it won't format as a normal YAML file, it will be formatted as JSON.
|
||||
The `.prettierrc` file can be written in either JSON or YAML. Previously, when Prettier formatted it, the parser was inferred to be `json`, which lead to a `SyntaxError` thrown if the content was YAML. Now it’s treated as a YAML file. However, if it's JSON, it will be formatted as JSON (not as JSON-like YAML).
|
||||
@@ -1,15 +1,15 @@
|
||||
#### Add CLI option to prevent errors on unmatched pattern (#10058 by @daronmcintosh)
|
||||
|
||||
The following command will not throw an error when it doesn't find a YAML file.
|
||||
The Prettier CLI will no longer display an error when no files match the glob pattern passed as input.
|
||||
|
||||
```sh
|
||||
// Prettier stable
|
||||
# Prettier stable
|
||||
$ npx prettier --check "prettier/docs/*.yaml"
|
||||
Checking formatting...
|
||||
[error] No files matching the pattern were found: "prettier/docs/*.yaml".
|
||||
All matched files use Prettier code style!
|
||||
|
||||
// Prettier main
|
||||
# Prettier main
|
||||
$ npx prettier --check --no-error-on-unmatched-pattern "prettier/docs/*.yaml"
|
||||
Checking formatting...
|
||||
All matched files use Prettier code style!
|
||||
|
||||
@@ -10,7 +10,7 @@ tests\flow-repo\config_module_system_node_resolve_dirname\custom_resolve_dir\tes
|
||||
tests\flow-repo\config_module_system_node_resolve_dirname\subdir\custom_resolve_
|
||||
All matched files use Prettier code style!
|
||||
|
||||
// Prettier main
|
||||
# Prettier main
|
||||
$ prettier tests/flow-repo/config_module_system_node_resolve_dirname --check
|
||||
Checking formatting...
|
||||
All matched files use Prettier code style!
|
||||
|
||||
@@ -0,0 +1,34 @@
|
||||
#### Exclude `@keyframes` params from being parsed as a Less variable (#10773 by @tmazeika)
|
||||
|
||||
<!-- prettier-ignore -->
|
||||
```css
|
||||
/* Input */
|
||||
@keyframes :global(spin) {
|
||||
from {
|
||||
transform: rotate(0deg);
|
||||
}
|
||||
to {
|
||||
transform: rotate(360deg);
|
||||
}
|
||||
}
|
||||
|
||||
/* Prettier stable */
|
||||
@keyframes: global(spin){
|
||||
from {
|
||||
transform: rotate(0deg);
|
||||
}
|
||||
to {
|
||||
transform: rotate(360deg);
|
||||
}
|
||||
};
|
||||
|
||||
/* Prettier main */
|
||||
@keyframes :global(spin) {
|
||||
from {
|
||||
transform: rotate(0deg);
|
||||
}
|
||||
to {
|
||||
transform: rotate(360deg);
|
||||
}
|
||||
}
|
||||
```
|
||||
@@ -1,9 +1,10 @@
|
||||
#### Fix absolute path in custom CSS -custom-url() calls (#9966 by @vjeux)
|
||||
#### Fix absolute path in custom CSS `-custom-url()` calls (#9966 by @vjeux)
|
||||
|
||||
The CSS parser is parsing this as `["division", "absolute/path"]` instead of a single `"/absolute/path"` token unless you are in a `url()` call. Because we put space after division, it results in an incorrect path. The fix was to avoid printing a space if a division is the first token of a call, which hopefully should be safe.
|
||||
|
||||
<!-- prettier-ignore -->
|
||||
```css
|
||||
/* Input */
|
||||
-custom-url(/absolute/path)
|
||||
|
||||
/* Prettier stable */
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
#### Support for Flow's indexed access type (#10594 by @gkz)
|
||||
|
||||
Support for Flow's indexed access type.
|
||||
|
||||
<!-- prettier-ignore -->
|
||||
```js
|
||||
// Input
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#### Fix missing semi in `declare export * from …` (#9767 by @fisker)
|
||||
#### Fix missing semicolon in `declare export * from …` (#9767 by @fisker)
|
||||
|
||||
<!-- Optional description if it makes sense. -->
|
||||
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
#### Fix missing space after keyword in anonymous operations (#10689 by @patriscus)
|
||||
|
||||
<!-- prettier-ignore -->
|
||||
```graphql
|
||||
# Input
|
||||
query ($unnamed: String) {
|
||||
id
|
||||
}
|
||||
|
||||
# Prettier stable
|
||||
query($unnamed: String) {
|
||||
id
|
||||
}
|
||||
|
||||
# Prettier main
|
||||
query ($unnamed: String) {
|
||||
id
|
||||
}
|
||||
```
|
||||
@@ -6,19 +6,19 @@
|
||||
- implement simple formatting for the `class` attribute, like Prettier formatted it in HTML before v2.3.0
|
||||
|
||||
<!-- prettier-ignore -->
|
||||
```html
|
||||
// Input
|
||||
```hbs
|
||||
{{!-- Input --}}
|
||||
<div class="
|
||||
foo"></div>
|
||||
<div bar='"{{expr}}"'></div>
|
||||
<div baz="\{{ non-expression }}"></div>
|
||||
|
||||
// Prettier stable
|
||||
{{!-- Prettier stable --}}
|
||||
<div class="[object Object],foo"></div>
|
||||
<div bar=""{{expr}}""></div>
|
||||
<div baz="{{ non-expression }}"></div>
|
||||
|
||||
// Prettier main
|
||||
{{!-- Prettier main --}}
|
||||
<div class="foo"></div>
|
||||
<div bar='"{{expr}}"'></div>
|
||||
<div baz="\{{ non-expression }}"></div>
|
||||
|
||||
@@ -1,16 +1,23 @@
|
||||
#### Move Handlebars support out of alpha to release (#10290 by @dcyriller & @thorn0)
|
||||
#### [HIGHLIGHT] Move Handlebars support out of alpha to release (#10290 by @dcyriller & @thorn0)
|
||||
|
||||
This started in 2017. Handlebars support has been in Prettier for a while, but it wasn’t released officially as it wasn’t really ready. Its status was “alpha”, “experimental”, “beta”. Then, if you checked older release notes, you could see that after “beta” somehow it was “alpha” again…
|
||||
This started in 2017. Handlebars support has been in Prettier for a while, but it wasn’t released officially as it wasn’t really ready. Its status went from “alpha” to “experimental” to “beta” and then, if you checked older release notes, you can see that after “beta” somehow it was “alpha” again…
|
||||
|
||||
Well, anyway, it finally is happening: Prettier can now officially format Handlebars files! 🎉
|
||||
Well, anyway, it finally is happening: Prettier can now officially format HTML templates with Handlebars! 🎉
|
||||
|
||||
It uses [Glimmer], [Ember]’s Handlebars parser, so it should be compliant with the HTML spec thanks to the Ember team.
|
||||
|
||||
The [`--html-whitespace-sensitivity`][hws-option] option is supported and defaults to `strict`, which means that Prettier will always respect the presence or absence of whitespace around tags and consider it unsafe to add whitespace where there were none and vice versa as this can affect how the document is rendered in the browser. The `css` value is not yet supported (treated as `strict` for now).
|
||||
|
||||
The feature is called “Ember / Handlebars” and not just “Handlebars” because Glimmer doesn’t support some syntax and use cases of Handlebars. This is mostly due to the fact that [Handlebars], being a template engine (a preprocessor), doesn’t care about the underlying syntax of the content it processes whereas Glimmer parses two syntaxes – HTML and Handlebars – at the same time and combines the result into a single tree, which Prettier can print. This means Prettier won’t format Handlebars files that can’t be parsed into such a tree, either because the underlying syntax isn’t HTML or because template directives and tags overlap in a way that can’t be represented in a tree (e.g., `{{#if foo}}<div>{{/if}`). Even with these restrictions, the formatter still seems to be useful enough to non-Ember Handlebars users.
|
||||
The feature is called “Ember / Handlebars” and not just “Handlebars” because Glimmer doesn’t support some syntax and use cases of Handlebars. This is mostly due to the fact that [Handlebars], being a template engine (a preprocessor), doesn’t care about the underlying syntax of the content it processes whereas Glimmer parses two syntaxes – HTML and Handlebars – at the same time and combines the result into a single tree, which Prettier can print. This means Prettier won’t format Handlebars files that can’t be parsed into such a tree, either because the underlying syntax isn’t HTML or because template directives and tags overlap in a way that can’t be represented in a tree (e.g., `{{#if foo}}<div>{{/if}`). Even with these restrictions, the formatter still seems to be useful enough to non-Ember Handlebars users. As for the syntax unsupported by Ember, there is a good chance to see support for it in future versions of Prettier as Glimmer uses a full-fledged Handlebars parser under the hood.
|
||||
|
||||
Files with the extensions `.hbs` and `.handlebars` are recognized as Handlebars by default. For other extensions, the [`--parser`](parser-option) option with the value `glimmer` has to be specified – for example, using command line or, better yet, [configuration overrides].
|
||||
|
||||
See the formatter in action on the [playground][playground-glimmer]!
|
||||
|
||||
[glimmer]: https://www.npmjs.com/package/@glimmer/syntax
|
||||
[ember]: https://emberjs.com
|
||||
[hws-option]: https://prettier.io/docs/en/options.html#html-whitespace-sensitivity
|
||||
[handlebars]: https://handlebarsjs.com/
|
||||
[parser-option]: https://prettier.io/docs/en/options.html#parser
|
||||
[configuration overrides]: https://prettier.io/docs/en/configuration.html#configuration-overrides
|
||||
[playground-glimmer]: https://prettier.io/playground/#N4Igxg9gdgLgprEAuEACVAeAJgSwG7qFgA2AhgM7kC8AOiAjAE4CedhqAfDVOhgBYBGDsGDoYOGMTjsAvjIwB6QVx6ZcBdCQrU6AIwhZWIFe1OERhfYbOE53Reo6YFjkABoQEAA7jo5ZKCkjIwQAO4ACkEI-iikxKGkzP4euoykYADWcDAAyl7pOFAA5shMAK5wHnAAtrpwWFj1ADKkxWWkRXAAYhCM1aQw4sXIIKRlMBDuIHww1cQA6nwScOT5YHA50RL4Eswj5Ew4YDBTheRwjDDhaUX9yABmceceAFbkAB4AQmmZ2Tmk1TgTUKcAeT0qIDe7xyhSKUgAimUIPAwcRniB8oxzowRnCcNVATiPF5GIUYPMcFgYHxkAAOAAMxJC53maS8IxJKwueFBHgAjkj4NdvDFRuQALRQOD1epTRhwAU4eXXDp3JCPNEQ87VHClRgVDzkWEIwWg9XgjwwUi6ClUmlIABMlrSOGIsIAwhACaQRisAKxTMrnAAq1piGvReAqAEkoI1YDkwKSfABBOM5GDMKSo85yIA
|
||||
@@ -0,0 +1,40 @@
|
||||
#### Do not break opening mustache and path (#10586 by @dcyriller)
|
||||
|
||||
<!-- prettier-ignore -->
|
||||
```handlebars
|
||||
{{!-- Input --}}
|
||||
<GlimmerComponent
|
||||
@errors={{or this.aVeryLongProperty (and this.aProperty (v-get bike "number" "message"))}}
|
||||
data-test-beneficiary-account-number
|
||||
/>
|
||||
<GlimmerComponent
|
||||
@progress={{aPropertyEngdingAfterEightiethColumnToHighlightAWeirdClosingParenIssue}}
|
||||
/>
|
||||
|
||||
{{!-- Prettier stable --}}
|
||||
<GlimmerComponent
|
||||
@errors={{
|
||||
or
|
||||
this.aVeryLongProperty
|
||||
(and this.aProperty (v-get bike "number" "message"))
|
||||
}}
|
||||
data-test-beneficiary-account-number
|
||||
/>
|
||||
<GlimmerComponent
|
||||
@progress={{
|
||||
aPropertyEngdingAfterEightiethColumnToHighlightAWeirdClosingParenIssue
|
||||
}}
|
||||
/>
|
||||
|
||||
{{!-- Prettier main --}}
|
||||
<GlimmerComponent
|
||||
@errors={{or
|
||||
this.aLongProperty
|
||||
(and this.aProperty (v-get bike "number" "message"))
|
||||
}}
|
||||
data-test-beneficiary-account-number
|
||||
/>
|
||||
<GlimmerComponent
|
||||
@progress={{aPropertyEngdingAfterEightiethColumnToHighlightAWeirdClosingParenIssue}}
|
||||
/>
|
||||
```
|
||||
@@ -1,7 +1,8 @@
|
||||
#### Print final blockParam on its own line (#9978 by @dcyriller)
|
||||
#### Print final `blockParam` on its own line (#9978 by @dcyriller)
|
||||
|
||||
<!-- prettier-ignore -->
|
||||
```hbs
|
||||
{{!-- Input --}}
|
||||
<MyComponent @prop={{true}} @prop2={{true}} @prop3={{true}} @prop4={{true}} as |thing|></MyComponent>
|
||||
{{#block param hashKey=hashValue hashKey=hashValue hashKey=hashValue as |blockParam|}}
|
||||
Hello
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#### Prefix-based multiline formatting for the `class` attribute (#7865 by @thorn0)
|
||||
#### [IMPROVEMENT] Prefix-based multiline formatting for the `class` attribute (#7865 by @thorn0)
|
||||
|
||||
Formatting of HTML class names will now keep classes on one line until the line length limit is reached; at that point, consecutive classes with the same prefix will be grouped together on each line. For layout frameworks such as Bootstrap and Tailwind CSS, which add many classes to an element, this is important for readability and maintainability vs. the previous behavior (keeping all classes on one line) or e.g. putting each class on its own line.
|
||||
|
||||
|
||||
@@ -1,15 +1,7 @@
|
||||
#### Improve visual separation between header and body in classes with multiline headers (#10085 by @sosukesuzuki)
|
||||
#### [IMPROVEMENT:2] Improve visual separation between header and body in classes with multiline headers (#10085 by @sosukesuzuki)
|
||||
|
||||
<!-- prettier-ignore -->
|
||||
```ts
|
||||
// Input
|
||||
class loooooooooooooooooooong
|
||||
extends looooooooooooooooooong
|
||||
implements loooooooooooooooooooong
|
||||
{
|
||||
property: string;
|
||||
}
|
||||
|
||||
// Prettier stable
|
||||
class loooooooooooooooooooong
|
||||
extends looooooooooooooooooong
|
||||
@@ -24,5 +16,4 @@ class loooooooooooooooooooong
|
||||
{
|
||||
property: string;
|
||||
}
|
||||
|
||||
```
|
||||
@@ -1,4 +1,4 @@
|
||||
#### Concise formatting of number-only arrays (#10106, #10160 by @thorn0)
|
||||
#### [IMPROVEMENT:3] Concise formatting of number-only arrays (#10106, #10160 by @thorn0)
|
||||
|
||||
While in general, Prettier avoids this kind of formatting because it's not diff-friendly, in this special case we decided that the benefits outweigh the risks.
|
||||
|
||||
@@ -26,11 +26,10 @@ const lazyCatererNumbers = [
|
||||
22,
|
||||
29,
|
||||
37,
|
||||
// ... ✂ a lot of lines ✂ ...
|
||||
// ... ✂ 46 lines ✂ ...
|
||||
1379,
|
||||
];
|
||||
|
||||
|
||||
// Prettier main
|
||||
const lazyCatererNumbers = [
|
||||
1, 2, 4, 7, 11, 16, 22, 29, 37, 46,
|
||||
@@ -41,5 +40,4 @@ const lazyCatererNumbers = [
|
||||
// n > 40
|
||||
821, 862, 904, 947, 991, 1036, 1082, 1129, 1177, 1226, 1276, 1327, 1379,
|
||||
];
|
||||
|
||||
```
|
||||
@@ -1,15 +0,0 @@
|
||||
#### Break assignment whose rhs is wrapped by an unary expression (#10158 by @sosukesuzuki)
|
||||
|
||||
<!-- prettier-ignore -->
|
||||
```js
|
||||
// Input
|
||||
const loooooooooooooooooooooooooong = !looooooooooooooong.looooooooooooooong.loooooong;
|
||||
|
||||
// Prettier stable
|
||||
const loooooooooooooooooooooooooong = !looooooooooooooong.looooooooooooooong
|
||||
.loooooong;
|
||||
|
||||
// Prettier main
|
||||
const loooooooooooooooooooooooooong =
|
||||
!looooooooooooooong.looooooooooooooong.loooooong;
|
||||
```
|
||||
@@ -1,43 +1,24 @@
|
||||
#### Consistent indentations for conditional operators (#10187, #10266 by @sosukesuzuki)
|
||||
#### [IMPROVEMENT:6] Consistent indentation for conditional operators (#10187, #10266 by @sosukesuzuki)
|
||||
|
||||
<!-- prettier-ignore -->
|
||||
```ts
|
||||
// Input
|
||||
const dotNotationMemberExpression = (
|
||||
callNode.parent?.type === AST_NODE_TYPES.ChainExpression
|
||||
? callNode.parent.parent
|
||||
: callNode.parent
|
||||
).TSESTree.BinaryExpression;
|
||||
const computedMemberExpression = (
|
||||
callNode.parent?.type === AST_NODE_TYPES.ChainExpression
|
||||
? callNode.parent.parent
|
||||
: callNode.parent
|
||||
)[TSESTree.BinaryExpression];
|
||||
const callExpressionCallee = (
|
||||
callNode.parent?.type === AST_NODE_TYPES.ChainExpression
|
||||
? callNode.parent.parent
|
||||
: callNode.parent
|
||||
)(TSESTree.BinaryExpression);
|
||||
const typeScriptAsExpression = (
|
||||
callNode.parent?.type === AST_NODE_TYPES.ChainExpression
|
||||
? callNode.parent.parent
|
||||
: callNode.parent
|
||||
) as TSESTree.BinaryExpression;
|
||||
|
||||
// Prettier stable
|
||||
const dotNotationMemberExpression = (callNode.parent?.type ===
|
||||
AST_NODE_TYPES.ChainExpression
|
||||
? callNode.parent.parent
|
||||
: callNode.parent
|
||||
).TSESTree.BinaryExpression;
|
||||
|
||||
const computedMemberExpression = (callNode.parent?.type ===
|
||||
AST_NODE_TYPES.ChainExpression
|
||||
? callNode.parent.parent
|
||||
: callNode.parent)[TSESTree.BinaryExpression];
|
||||
|
||||
const callExpressionCallee = (callNode.parent?.type ===
|
||||
AST_NODE_TYPES.ChainExpression
|
||||
? callNode.parent.parent
|
||||
: callNode.parent)(TSESTree.BinaryExpression);
|
||||
|
||||
const typeScriptAsExpression = (callNode.parent?.type ===
|
||||
AST_NODE_TYPES.ChainExpression
|
||||
? callNode.parent.parent
|
||||
@@ -49,16 +30,19 @@ const dotNotationMemberExpression = (
|
||||
? callNode.parent.parent
|
||||
: callNode.parent
|
||||
).TSESTree.BinaryExpression;
|
||||
|
||||
const computedMemberExpression = (
|
||||
callNode.parent?.type === AST_NODE_TYPES.ChainExpression
|
||||
? callNode.parent.parent
|
||||
: callNode.parent
|
||||
)[TSESTree.BinaryExpression];
|
||||
|
||||
const callExpressionCallee = (
|
||||
callNode.parent?.type === AST_NODE_TYPES.ChainExpression
|
||||
? callNode.parent.parent
|
||||
: callNode.parent
|
||||
)(TSESTree.BinaryExpression);
|
||||
|
||||
const typeScriptAsExpression = (
|
||||
callNode.parent?.type === AST_NODE_TYPES.ChainExpression
|
||||
? callNode.parent.parent
|
||||
|
||||
@@ -1,25 +1,9 @@
|
||||
#### Format assignments more consistently (#10222 by @thorn0)
|
||||
#### [HIGHLIGHT] Format assignments more consistently (#10222, #10643, #10672 by @thorn0; #10158 by @sosukesuzuki)
|
||||
|
||||
Previously, Prettier had a lot of trouble with figuring out how to break lines in assignments. E.g., long right-hand sides often stayed unbroken. Not anymore.
|
||||
|
||||
<!-- prettier-ignore -->
|
||||
```ts
|
||||
// Input
|
||||
aParticularlyLongAndObnoxiousNameForIllustrativePurposes =
|
||||
anotherVeryLongNameForIllustrativePurposes;
|
||||
|
||||
aParticularlyLongAndObnoxiousNameForIllustrativePurposes =
|
||||
'a very long string for illustrative purposes'.length;
|
||||
|
||||
someReallyLongThingStoredInAMapWithAReallyBigName[pageletID] =
|
||||
_someVariableThatWeAreCheckingForFalsiness
|
||||
? Date.now() - _someVariableThatWeAreCheckingForFalsiness
|
||||
: 0;
|
||||
|
||||
class x {
|
||||
private readonly rawConfigFromFile$: BehaviorSubject<any> = new BehaviorSubject(notRead);
|
||||
}
|
||||
|
||||
// Prettier stable
|
||||
aParticularlyLongAndObnoxiousNameForIllustrativePurposes = anotherVeryLongNameForIllustrativePurposes;
|
||||
|
||||
|
||||
@@ -1,13 +1,7 @@
|
||||
#### Improve formatting for React Hooks call (#10238 by @sosukesuzuki)
|
||||
#### [IMPROVEMENT:1] Improve formatting for React Hooks calls (#10238 by @sosukesuzuki)
|
||||
|
||||
<!-- prettier-ignore -->
|
||||
```js
|
||||
// Input
|
||||
const { firstName, lastName } = useMemo(
|
||||
() => parseFullName(fullName),
|
||||
[fullName]
|
||||
);
|
||||
|
||||
// Prettier stable
|
||||
const { firstName, lastName } = useMemo(() => parseFullName(fullName), [
|
||||
fullName,
|
||||
@@ -18,5 +12,4 @@ const { firstName, lastName } = useMemo(
|
||||
() => parseFullName(fullName),
|
||||
[fullName]
|
||||
);
|
||||
|
||||
```
|
||||
@@ -1,15 +0,0 @@
|
||||
#### Disable Babel's error recovery for invalid escaped characters in identifiers (#10322 by @thorn0)
|
||||
|
||||
<!-- prettier-ignore -->
|
||||
```js
|
||||
// Input
|
||||
const \u{20} = 1
|
||||
|
||||
// Prettier stable
|
||||
const = 1;
|
||||
|
||||
// Prettier main
|
||||
[error] stdin: SyntaxError: Invalid Unicode escape (1:7)
|
||||
[error] > 1 | const \u{20} = 1
|
||||
[error] | ^ ^
|
||||
```
|
||||
@@ -1,22 +1,21 @@
|
||||
#### Prevent wrapping object properties with short keys (#10335 by @thorn0)
|
||||
#### [HIGHLIGHT] Prevent wrapping object properties with short keys (#10335 by @thorn0)
|
||||
|
||||
Line breaks after short property names in object literals often look unnatural. Even when such a line break yields a line length benefit of 1 or 2 characters, it rarely looks justified. Prettier main avoids line breaks after property names shorter than `tabWidth + 3`. The "+3" part has been chosen rather arbitrarily. It may be revised upward in future versions, provided there is a really good rationale.
|
||||
Line breaks after short property names in object literals often look unnatural. Even when such a line break yields a line length benefit of 1 or 2 characters, it rarely looks justified. Prettier main avoids line breaks after property names shorter than `tabWidth + 3` – for example, 5 characters in the default configuration, or 7 characters with `tabWidth: 4`. This heuristic may be revised in future versions.
|
||||
|
||||
<!-- prettier-ignore -->
|
||||
```js
|
||||
// Input
|
||||
const importantLink = {
|
||||
url: "https://prettier.io/docs/en/rationale.html#what-prettier-is-concerned-about"
|
||||
};
|
||||
|
||||
// Prettier stable
|
||||
const importantLink = {
|
||||
url:
|
||||
"https://prettier.io/docs/en/rationale.html#what-prettier-is-concerned-about"
|
||||
"https://prettier.io/docs/en/rationale.html#what-prettier-is-concerned-about",
|
||||
gitHubUrl:
|
||||
"https://github.com/prettier/prettier/blob/main/docs/rationale.md#what-prettier-is-concerned-about",
|
||||
};
|
||||
|
||||
// Prettier main
|
||||
const importantLink = {
|
||||
url: "https://prettier.io/docs/en/rationale.html#what-prettier-is-concerned-about"
|
||||
url: "https://prettier.io/docs/en/rationale.html#what-prettier-is-concerned-about",
|
||||
gitHubUrl:
|
||||
"https://github.com/prettier/prettier/blob/main/docs/rationale.md#what-prettier-is-concerned-about",
|
||||
};
|
||||
```
|
||||
@@ -1,4 +1,4 @@
|
||||
#### Improve formatting for nested await expressions in heads of member and call expressions (#10342 by @thorn0)
|
||||
#### [IMPROVEMENT:4] Improve formatting for nested await expressions in heads of member and call expressions (#10342 by @thorn0)
|
||||
|
||||
Even though Prettier tries to be helpful here, please don't write code like this. Have mercy upon your teammates and use intermediate variables.
|
||||
|
||||
|
||||
@@ -7,12 +7,11 @@ Support formatting for [Module Blocks Stage 2 proposal](https://github.com/tc39/
|
||||
// Input
|
||||
module { export let foo = "foo"; };
|
||||
|
||||
// Prettier main
|
||||
// Prettier stable
|
||||
SyntaxError: Unexpected token, expected ";"
|
||||
|
||||
// Prettier stable
|
||||
// Prettier main
|
||||
module {
|
||||
export let foo = "foo";
|
||||
};
|
||||
|
||||
```
|
||||
@@ -1,4 +1,4 @@
|
||||
#### Fix missing parentheses for `yield` in `pipeline` (#10446 by @fisker)
|
||||
#### Fix missing parentheses for `yield` in a pipeline (#10446 by @fisker)
|
||||
|
||||
<!-- prettier-ignore -->
|
||||
```jsx
|
||||
|
||||
@@ -0,0 +1,31 @@
|
||||
#### Make Babel’s error recovery more selective (#10495 by @fisker, #9787 by @sosukesuzuki, #10065, #10322 by @thorn0)
|
||||
|
||||
Previously, because of the [error recovery](https://babeljs.io/blog/2019/11/05/7.7.0#parser-error-recovery-10363httpsgithubcombabelbabelpull10363), the Babel parser was too permissive, which lead to all kinds of AST shapes that Prettier couldn’t print. Prettier main lets Babel recover only from a few harmless types of errors – for example, multiple `const` declarations with the same name. Anything else is reported as syntax errors.
|
||||
|
||||
<!-- prettier-ignore -->
|
||||
```js
|
||||
// Input
|
||||
foo("a", , "b");
|
||||
|
||||
// Prettier stable
|
||||
TypeError: Cannot read property 'type' of null
|
||||
|
||||
// Prettier main
|
||||
[error] stdin: SyntaxError: Argument expression expected. (1:10)
|
||||
[error] > 1 | foo("a", , "b");
|
||||
[error] | ^
|
||||
```
|
||||
|
||||
<!-- prettier-ignore -->
|
||||
```js
|
||||
// Input
|
||||
const \u{20} = 1
|
||||
|
||||
// Prettier stable
|
||||
const = 1;
|
||||
|
||||
// Prettier main
|
||||
[error] stdin: SyntaxError: Invalid Unicode escape (1:7)
|
||||
[error] > 1 | const \u{20} = 1
|
||||
[error] | ^ ^
|
||||
```
|
||||
@@ -1,16 +1,9 @@
|
||||
#### Improve detection of AMD `define` (#10528 by @thorn0)
|
||||
|
||||
Prettier special-cases AMD `define` calls to avoid unexpected line breaks in them. `define` calls that weren't expression statements and had nothing to do with AMD were formatted this way too. This happens no longer.
|
||||
Prettier special-cases AMD `define` calls to avoid unexpected line breaks in them. We now only format `define` calls if they are at the top level of a function or program and are passed arguments in the way AMD expects.
|
||||
|
||||
<!-- prettier-ignore -->
|
||||
```jsx
|
||||
// Input
|
||||
const someVariable = define(
|
||||
"some string literal",
|
||||
anotherVariable,
|
||||
yetAnotherVariable
|
||||
);
|
||||
|
||||
// Prettier stable
|
||||
const someVariable = define("some string literal", anotherVariable, yetAnotherVariable);
|
||||
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
#### Fix duplicated `prettier-ignore` comments (#10666 by @fisker)
|
||||
|
||||
<!-- prettier-ignore -->
|
||||
```jsx
|
||||
// Input
|
||||
foo = a.
|
||||
// prettier-ignore
|
||||
b;
|
||||
|
||||
// Prettier stable
|
||||
foo =
|
||||
// prettier-ignore
|
||||
a.
|
||||
// prettier-ignore
|
||||
b;
|
||||
|
||||
// Prettier main
|
||||
foo = a.
|
||||
// prettier-ignore
|
||||
b;
|
||||
```
|
||||
@@ -0,0 +1,20 @@
|
||||
#### [IMPROVEMENT:5] Improve formatting for `do` expressions in function calls (#10693 by @sosukesuzuki)
|
||||
|
||||
“`do` expressions” are a [stage 1 ECMAScript proposal](https://github.com/tc39/proposal-do-expressions).
|
||||
|
||||
<!-- prettier-ignore -->
|
||||
```js
|
||||
// Prettier stable
|
||||
expect(
|
||||
do {
|
||||
var bar = "foo";
|
||||
bar;
|
||||
}
|
||||
).toBe("foo");
|
||||
|
||||
// Prettier main
|
||||
expect(do {
|
||||
var bar = "foo";
|
||||
bar;
|
||||
}).toBe("foo");
|
||||
```
|
||||
@@ -0,0 +1,40 @@
|
||||
#### Process conditional groups in `mapDoc` (#10695 by @thorn0)
|
||||
|
||||
In particular, this fixes broken substitutions in HTML-in-JS.
|
||||
|
||||
<!-- prettier-ignore -->
|
||||
```jsx
|
||||
// Input
|
||||
export default function include_photoswipe(
|
||||
gallery_selector = ".my-gallery"
|
||||
): string {
|
||||
return /* HTML */ `
|
||||
<script>
|
||||
window.addEventListener("load", () =>
|
||||
initPhotoSwipeFromDOM("${gallery_selector}")
|
||||
);
|
||||
</script>`;
|
||||
}
|
||||
|
||||
// Prettier stable
|
||||
export default function include_photoswipe(
|
||||
gallery_selector = ".my-gallery"
|
||||
): string {
|
||||
return /* HTML */ ` <script>
|
||||
window.addEventListener("load", () =>
|
||||
initPhotoSwipeFromDOM("PRETTIER_HTML_PLACEHOLDER_0_13_IN_JS")
|
||||
);
|
||||
</script>`;
|
||||
}
|
||||
|
||||
// Prettier main
|
||||
export default function include_photoswipe(
|
||||
gallery_selector = ".my-gallery"
|
||||
): string {
|
||||
return /* HTML */ ` <script>
|
||||
window.addEventListener("load", () =>
|
||||
initPhotoSwipeFromDOM("${gallery_selector}")
|
||||
);
|
||||
</script>`;
|
||||
}
|
||||
```
|
||||
@@ -0,0 +1,24 @@
|
||||
#### Avoid arg expansion that leads to broken code (#10712 by @thorn0)
|
||||
|
||||
<!-- prettier-ignore -->
|
||||
```jsx
|
||||
// Input
|
||||
glimseGlyphsHazardNoopsTieTie(({ a, b = () => {
|
||||
console.log();
|
||||
}}) => averredBathersBoxroomBuggyNurl());
|
||||
|
||||
// Prettier stable
|
||||
glimseGlyphsHazardNoopsTieTie(({ a, b = () => {
|
||||
console.log();
|
||||
} }) => averredBathersBoxroomBuggyNurl());
|
||||
|
||||
// Prettier main
|
||||
glimseGlyphsHazardNoopsTieTie(
|
||||
({
|
||||
a,
|
||||
b = () => {
|
||||
console.log();
|
||||
},
|
||||
}) => averredBathersBoxroomBuggyNurl()
|
||||
);
|
||||
```
|
||||
@@ -1,9 +1,7 @@
|
||||
#### Improve comment format (#9672 by @fisker)
|
||||
|
||||
When multiple comments on same line, the result became unstable.
|
||||
#### Fix unstable multiple comments on the same line (#9672 by @fisker)
|
||||
|
||||
<!-- prettier-ignore -->
|
||||
```jsx
|
||||
```js
|
||||
// Input
|
||||
a;
|
||||
/*1*//*2*/
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
#### Fix node ends at `rangeStart` was formatted (#9704 by @fisker)
|
||||
#### Don’t format nodes that end just before `rangeStart` (#9704 by @fisker)
|
||||
|
||||
Previously a node ends at `rangeStart` in considered in range, now it's excluded.
|
||||
Previously, when [range formatting](https://prettier.io/docs/en/options.html#range) was performed, such nodes were considered part of the range, now they're excluded. This affects other languages that the range formatting feature supports, not only JavaScript.
|
||||
|
||||
<!-- prettier-ignore -->
|
||||
```js
|
||||
// Prettier stable
|
||||
// Input
|
||||
foo = 1.0000;bar = 1.0000;baz=1.0000;
|
||||
^^^^^^^^^^^^^ Range
|
||||
|
||||
@@ -15,5 +15,3 @@ bar = 1.0;baz=1.0000;
|
||||
// Prettier main
|
||||
foo = 1.0000;bar = 1.0;baz=1.0000;
|
||||
```
|
||||
|
||||
_This effect other languages support range format too._
|
||||
@@ -1,5 +1,7 @@
|
||||
#### Fix inconsistent language comment detection (#9743 by @fisker)
|
||||
|
||||
An `/* HTML */` comment should directly precede a template literal for the latter to be recognized as HTML-in-JS. Previously, the comment was erroneously recognized is some other locations.
|
||||
|
||||
<!-- prettier-ignore -->
|
||||
```jsx
|
||||
// Input
|
||||
|
||||
@@ -1,15 +0,0 @@
|
||||
#### Disable Babel's error recovery for omitted call arguments (#9787 by @sosukesuzuki, #10065 by @thorn0)
|
||||
|
||||
<!-- prettier-ignore -->
|
||||
```js
|
||||
// Input
|
||||
foo("a", , "b");
|
||||
|
||||
// Prettier stable
|
||||
TypeError: Cannot read property 'type' of null
|
||||
|
||||
// Prettier main
|
||||
[error] stdin: SyntaxError: Argument expression expected. (1:10)
|
||||
[error] > 1 | foo("a", , "b");
|
||||
[error] | ^
|
||||
```
|
||||
@@ -1,17 +1,7 @@
|
||||
#### Refine formatting of curried arrow functions (#9992, #10543 by @sosukesuzuki & @thorn0)
|
||||
#### [IMPROVEMENT:0] Refine formatting of curried arrow functions (#9992, #10543 by @sosukesuzuki & @thorn0)
|
||||
|
||||
<!-- prettier-ignore -->
|
||||
```js
|
||||
// Input
|
||||
const currying =
|
||||
(argument1) =>
|
||||
(argument2) =>
|
||||
(argument3) =>
|
||||
(argument4) =>
|
||||
(argument5) =>
|
||||
(argument6) =>
|
||||
foo;
|
||||
|
||||
// Prettier stable
|
||||
const currying = (argument1) => (argument2) => (argument3) => (argument4) => (
|
||||
argument5
|
||||
|
||||
@@ -2,11 +2,6 @@
|
||||
|
||||
<!-- prettier-ignore -->
|
||||
```ts
|
||||
// Input
|
||||
users.map((user: User): User => {
|
||||
return user;
|
||||
})
|
||||
|
||||
// Prettier stable
|
||||
users.map(
|
||||
(user: User): User => {
|
||||
|
||||
@@ -3,29 +3,20 @@
|
||||
<!-- prettier-ignore -->
|
||||
```ts
|
||||
// Input
|
||||
const getAccountCount = async () =>
|
||||
(await
|
||||
((await (
|
||||
await focusOnSection(BOOKMARKED_PROJECTS_SECTION_NAME)
|
||||
).findItem("My bookmarks")) as TreeItem
|
||||
).getChildren()
|
||||
).length
|
||||
const accountCount = (findItemInSection(BOOKMARKED_PROJECTS_SECTION_NAME,
|
||||
"My bookmarks") as TreeItem).getChildren().length;
|
||||
|
||||
// Prettier stable
|
||||
const getAccountCount = async () =>
|
||||
(
|
||||
await ((await (
|
||||
await focusOnSection(BOOKMARKED_PROJECTS_SECTION_NAME)
|
||||
).findItem("My bookmarks")) as TreeItem).getChildren()
|
||||
).length;
|
||||
const accountCount = (findItemInSection(
|
||||
BOOKMARKED_PROJECTS_SECTION_NAME,
|
||||
"My bookmarks"
|
||||
) as TreeItem).getChildren().length;
|
||||
|
||||
// Prettier main
|
||||
const getAccountCount = async () =>
|
||||
(
|
||||
await (
|
||||
(await (
|
||||
await focusOnSection(BOOKMARKED_PROJECTS_SECTION_NAME)
|
||||
).findItem("My bookmarks")) as TreeItem
|
||||
).getChildren()
|
||||
).length;
|
||||
const accountCount = (
|
||||
findItemInSection(
|
||||
BOOKMARKED_PROJECTS_SECTION_NAME,
|
||||
"My bookmarks"
|
||||
) as TreeItem
|
||||
).getChildren().length;
|
||||
```
|
||||
@@ -7,10 +7,10 @@
|
||||
// Input
|
||||
type T = abstract new () => void;
|
||||
|
||||
// Prettier main
|
||||
// Prettier stable
|
||||
SyntaxError: Unexpected token, expected ";" (1:19)
|
||||
|
||||
// Prettier stable
|
||||
// Prettier main
|
||||
type T = abstract new () => void;
|
||||
|
||||
```
|
||||
@@ -22,10 +22,10 @@ type T = abstract new () => void;
|
||||
// Input
|
||||
import type A = require("A");
|
||||
|
||||
// Prettier main
|
||||
// Prettier stable
|
||||
SyntaxError: Only ECMAScript imports may use 'import type'.
|
||||
|
||||
// Prettier stable
|
||||
// Prettier main
|
||||
import type A = require("A");
|
||||
|
||||
```
|
||||
@@ -0,0 +1,13 @@
|
||||
#### Don’t print parens around nested type assertions (#10702 by @thorn0)
|
||||
|
||||
<!-- prettier-ignore -->
|
||||
```ts
|
||||
// Input
|
||||
foo as unknown as Bar
|
||||
|
||||
// Prettier stable
|
||||
(foo as unknown) as Bar;
|
||||
|
||||
// Prettier main
|
||||
foo as unknown as Bar;
|
||||
```
|
||||
@@ -1,6 +1,6 @@
|
||||
#### Fix missing comments in `MethodDefinition` (#9872 by @fisker)
|
||||
|
||||
`typescript` parser only, `babel-ts` don't have this issue.
|
||||
`typescript` parser only, `babel-ts` doesn't have this issue.
|
||||
|
||||
<!-- prettier-ignore -->
|
||||
```typescript
|
||||
|
||||
@@ -199,6 +199,7 @@
|
||||
"kddeisz",
|
||||
"kddnewton",
|
||||
"Kearney",
|
||||
"keyframes",
|
||||
"keyof",
|
||||
"Khatri",
|
||||
"l’objectif",
|
||||
|
||||
+30
-8
@@ -20,7 +20,7 @@ yarn add --dev --exact prettier
|
||||
|
||||
<!--END_DOCUSAURUS_CODE_TABS-->
|
||||
|
||||
Then, create an empty config file to let editors and other tooling know you are using Prettier:
|
||||
Then, create an empty config file to let editors and other tools know you are using Prettier:
|
||||
|
||||
<!-- Note: `echo "{}" > .prettierrc.json` would result in `"{}"<SPACE>` on Windows. The below version works in cmd.exe, bash, zsh, fish. -->
|
||||
|
||||
@@ -68,7 +68,7 @@ yarn prettier --write .
|
||||
If you have a CI setup, run the following as part of it to make sure that everyone runs Prettier. This avoids merge conflicts and other collaboration issues!
|
||||
|
||||
```bash
|
||||
prettier --check .
|
||||
npx prettier --check .
|
||||
```
|
||||
|
||||
`--check` is like `--write`, but only checks that files are already formatted, rather than overwriting them. `prettier --write` and `prettier --check` are the most common ways to run Prettier.
|
||||
@@ -93,15 +93,37 @@ If you use ESLint, install [eslint-config-prettier](https://github.com/prettier/
|
||||
|
||||
In addition to running Prettier from the command line (`prettier --write`), checking formatting in CI, and running Prettier from your editor, many people like to run Prettier as a pre-commit hook as well. This makes sure all your commits are formatted, without having to wait for your CI build to finish.
|
||||
|
||||
For example, you can add the following to your `package.json` to have ESLint and Prettier run before each commit, via [lint-staged](https://github.com/okonet/lint-staged) and [husky](https://github.com/typicode/husky).
|
||||
For example, you can do the following to have Prettier run before each commit:
|
||||
|
||||
1. Install [husky](https://github.com/typicode/husky) and [lint-staged](https://github.com/okonet/lint-staged):
|
||||
|
||||
<!--DOCUSAURUS_CODE_TABS-->
|
||||
<!--npm-->
|
||||
|
||||
```bash
|
||||
npm install --save-dev husky lint-staged
|
||||
npx husky install
|
||||
npm set-script prepare "husky install"
|
||||
npx husky add .husky/pre-commit "npx lint-staged"
|
||||
```
|
||||
|
||||
<!--yarn-->
|
||||
|
||||
```bash
|
||||
yarn add --dev husky lint-staged
|
||||
npx husky install
|
||||
npm set-script prepare "husky install"
|
||||
npx husky add .husky/pre-commit "npx lint-staged"
|
||||
```
|
||||
|
||||
> If you use Yarn 2, see https://typicode.github.io/husky/#/?id=yarn-2
|
||||
|
||||
<!--END_DOCUSAURUS_CODE_TABS-->
|
||||
|
||||
2. Add the following to your `package.json`:
|
||||
|
||||
```json
|
||||
{
|
||||
"husky": {
|
||||
"hooks": {
|
||||
"pre-commit": "lint-staged"
|
||||
}
|
||||
},
|
||||
"lint-staged": {
|
||||
"**/*": "prettier --write --ignore-unknown"
|
||||
}
|
||||
|
||||
+13
-29
@@ -15,7 +15,7 @@ _Make sure Prettier is installed and is in your [`devDependencies`](https://docs
|
||||
npx mrm lint-staged
|
||||
```
|
||||
|
||||
This will install [simple-git-hooks](https://github.com/toplenboren/simple-git-hooks) and [lint-staged](https://github.com/okonet/lint-staged), then add a configuration to the project’s `package.json` that will automatically format supported files in a pre-commit hook.
|
||||
This will install [husky](https://github.com/typicode/husky) and [lint-staged](https://github.com/okonet/lint-staged), then add a configuration to the project’s `package.json` that will automatically format supported files in a pre-commit hook.
|
||||
|
||||
Read more at the [lint-staged](https://github.com/okonet/lint-staged#configuration) repo.
|
||||
|
||||
@@ -29,29 +29,21 @@ Install it along with [husky](https://github.com/typicode/husky):
|
||||
<!--npm-->
|
||||
|
||||
```bash
|
||||
npm install --save-dev pretty-quick husky
|
||||
npx husky-init
|
||||
npm install --save-dev pretty-quick
|
||||
npx husky set .husky/pre-commit "pretty-quick --staged"
|
||||
```
|
||||
|
||||
<!--yarn-->
|
||||
|
||||
```bash
|
||||
yarn add --dev pretty-quick husky
|
||||
npx husky-init # add --yarn2 for Yarn 2
|
||||
yarn add --dev pretty-quick
|
||||
yarn husky set .husky/pre-commit "pretty-quick --staged"
|
||||
```
|
||||
|
||||
<!--END_DOCUSAURUS_CODE_TABS-->
|
||||
|
||||
Add this to your `package.json`:
|
||||
|
||||
```json
|
||||
{
|
||||
"husky": {
|
||||
"hooks": {
|
||||
"pre-commit": "pretty-quick --staged"
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Read more at the [pretty-quick](https://github.com/azz/pretty-quick) repo.
|
||||
|
||||
## Option 3. [pre-commit](https://github.com/pre-commit/pre-commit)
|
||||
@@ -86,29 +78,21 @@ Git-format-staged requires Python v3 or v2.7. Python is usually pre-installed on
|
||||
<!--npm-->
|
||||
|
||||
```bash
|
||||
npm install --save-dev git-format-staged husky
|
||||
npx husky-init
|
||||
npm install --save-dev git-format-staged
|
||||
npx husky set .husky/pre-commit "git-format-staged -f 'prettier --ignore-unknown --stdin --stdin-filepath \"{}\"' ."
|
||||
```
|
||||
|
||||
<!--yarn-->
|
||||
|
||||
```bash
|
||||
yarn add --dev git-format-staged husky
|
||||
npx husky-init # add --yarn2 for Yarn 2
|
||||
yarn add --dev git-format-staged
|
||||
yarn husky set .husky/pre-commit "git-format-staged -f 'prettier --ignore-unknown --stdin --stdin-filepath \"{}\"' ."
|
||||
```
|
||||
|
||||
<!--END_DOCUSAURUS_CODE_TABS-->
|
||||
|
||||
and add this config to your `package.json`:
|
||||
|
||||
```json
|
||||
{
|
||||
"husky": {
|
||||
"hooks": {
|
||||
"pre-commit": "git-format-staged -f 'prettier --ignore-unknown --stdin --stdin-filepath \"{}\"' ."
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Add or remove file extensions to suit your project. Note that regardless of which extensions you list formatting will respect any `.prettierignore` files in your project.
|
||||
|
||||
To read about how git-format-staged works see [Automatic Code Formatting for Partially-Staged Files](https://www.olioapps.com/blog/automatic-code-formatting/).
|
||||
|
||||
+5
-5
@@ -20,7 +20,7 @@ process.env.PRETTIER_DIR = PRETTIER_DIR;
|
||||
const testPathIgnorePatterns = [];
|
||||
let transform = {};
|
||||
if (TEST_STANDALONE) {
|
||||
testPathIgnorePatterns.push("<rootDir>/tests_integration/");
|
||||
testPathIgnorePatterns.push("<rootDir>/tests/integration/");
|
||||
}
|
||||
if (isProduction) {
|
||||
// `esm` bundles need transform
|
||||
@@ -48,12 +48,12 @@ if (isProduction) {
|
||||
} else {
|
||||
// Only test bundles for production
|
||||
testPathIgnorePatterns.push(
|
||||
"<rootDir>/tests_integration/__tests__/bundle.js"
|
||||
"<rootDir>/tests/integration/__tests__/bundle.js"
|
||||
);
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
setupFiles: ["<rootDir>/tests_config/setup.js"],
|
||||
setupFiles: ["<rootDir>/tests/config/setup.js"],
|
||||
snapshotSerializers: [
|
||||
"jest-snapshot-serializer-raw",
|
||||
"jest-snapshot-serializer-ansi",
|
||||
@@ -68,8 +68,8 @@ module.exports = {
|
||||
],
|
||||
coverageReporters: ["text", "lcov"],
|
||||
moduleNameMapper: {
|
||||
"prettier-local": "<rootDir>/tests_config/require_prettier.js",
|
||||
"prettier-standalone": "<rootDir>/tests_config/require_standalone.js",
|
||||
"prettier-local": "<rootDir>/tests/config/require-prettier.js",
|
||||
"prettier-standalone": "<rootDir>/tests/config/require-standalone.js",
|
||||
},
|
||||
modulePathIgnorePatterns: ["<rootDir>/dist", "<rootDir>/website/static/lib"],
|
||||
testEnvironment: "node",
|
||||
|
||||
+1
-1
@@ -1,3 +1,3 @@
|
||||
[build.environment]
|
||||
NODE_VERSION = "12"
|
||||
NODE_VERSION = "14"
|
||||
YARN_VERSION = "1.22.10"
|
||||
+24
-24
@@ -20,16 +20,16 @@
|
||||
"bin"
|
||||
],
|
||||
"dependencies": {
|
||||
"@angular/compiler": "11.2.7",
|
||||
"@angular/compiler": "11.2.12",
|
||||
"@babel/code-frame": "7.12.13",
|
||||
"@babel/parser": "7.13.11",
|
||||
"@glimmer/syntax": "0.77.6",
|
||||
"@babel/parser": "7.13.16",
|
||||
"@glimmer/syntax": "0.79.0",
|
||||
"@iarna/toml": "2.2.5",
|
||||
"@typescript-eslint/typescript-estree": "4.19.0",
|
||||
"@typescript-eslint/typescript-estree": "4.22.0",
|
||||
"angular-estree-parser": "2.3.0",
|
||||
"angular-html-parser": "1.7.1",
|
||||
"angular-html-parser": "1.8.0",
|
||||
"camelcase": "6.2.0",
|
||||
"chalk": "4.1.0",
|
||||
"chalk": "4.1.1",
|
||||
"ci-info": "3.1.1",
|
||||
"cjk-regex": "2.0.1",
|
||||
"cosmiconfig": "7.0.0",
|
||||
@@ -43,7 +43,7 @@
|
||||
"fast-glob": "3.2.5",
|
||||
"fast-json-stable-stringify": "2.1.0",
|
||||
"find-parent-dir": "0.3.0",
|
||||
"flow-parser": "0.147.0",
|
||||
"flow-parser": "0.149.0",
|
||||
"get-stdin": "8.0.0",
|
||||
"globby": "11.0.3",
|
||||
"graphql": "15.5.0",
|
||||
@@ -56,9 +56,9 @@
|
||||
"json5": "2.2.0",
|
||||
"leven": "3.1.0",
|
||||
"lines-and-columns": "1.1.6",
|
||||
"linguist-languages": "7.13.0",
|
||||
"linguist-languages": "7.14.0",
|
||||
"lodash": "4.17.21",
|
||||
"mem": "8.1.0",
|
||||
"mem": "8.1.1",
|
||||
"meriyah": "4.1.5",
|
||||
"minimatch": "3.0.4",
|
||||
"minimist": "1.2.5",
|
||||
@@ -80,7 +80,7 @@
|
||||
"semver": "7.3.5",
|
||||
"string-width": "4.2.2",
|
||||
"strip-ansi": "6.0.0",
|
||||
"typescript": "4.2.3",
|
||||
"typescript": "4.2.4",
|
||||
"unicode-regex": "3.0.0",
|
||||
"unified": "9.2.1",
|
||||
"vnopts": "1.0.2",
|
||||
@@ -88,10 +88,10 @@
|
||||
"yaml-unist-parser": "1.3.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@babel/core": "7.13.13",
|
||||
"@babel/preset-env": "7.13.12",
|
||||
"@babel/types": "7.13.13",
|
||||
"@glimmer/reference": "0.77.6",
|
||||
"@babel/core": "7.14.0",
|
||||
"@babel/preset-env": "7.13.15",
|
||||
"@babel/types": "7.13.17",
|
||||
"@glimmer/reference": "0.78.2",
|
||||
"@rollup/plugin-alias": "3.1.2",
|
||||
"@rollup/plugin-babel": "5.3.0",
|
||||
"@rollup/plugin-commonjs": "18.0.0",
|
||||
@@ -99,32 +99,32 @@
|
||||
"@rollup/plugin-node-resolve": "11.2.1",
|
||||
"@rollup/plugin-replace": "2.4.2",
|
||||
"@types/estree": "0.0.47",
|
||||
"@types/node": "14.14.0",
|
||||
"@types/node": "15.0.1",
|
||||
"babel-jest": "26.6.3",
|
||||
"babel-loader": "8.2.2",
|
||||
"benchmark": "2.1.4",
|
||||
"builtin-modules": "3.2.0",
|
||||
"cross-env": "7.0.3",
|
||||
"cspell": "4.2.8",
|
||||
"eslint": "7.23.0",
|
||||
"eslint-config-prettier": "8.1.0",
|
||||
"eslint": "7.25.0",
|
||||
"eslint-config-prettier": "8.3.0",
|
||||
"eslint-formatter-friendly": "7.0.0",
|
||||
"eslint-plugin-import": "2.22.1",
|
||||
"eslint-plugin-jest": "24.3.2",
|
||||
"eslint-plugin-jest": "24.3.6",
|
||||
"eslint-plugin-prettier-internal-rules": "link:scripts/tools/eslint-plugin-prettier-internal-rules",
|
||||
"eslint-plugin-react": "7.23.1",
|
||||
"eslint-plugin-unicorn": "29.0.0",
|
||||
"eslint-plugin-react": "7.23.2",
|
||||
"eslint-plugin-unicorn": "31.0.0",
|
||||
"execa": "5.0.0",
|
||||
"jest": "26.6.3",
|
||||
"jest-snapshot-serializer-ansi": "1.0.0",
|
||||
"jest-snapshot-serializer-raw": "1.1.0",
|
||||
"jest-watch-typeahead": "0.6.1",
|
||||
"jest-snapshot-serializer-raw": "1.2.0",
|
||||
"jest-watch-typeahead": "0.6.3",
|
||||
"npm-run-all": "4.1.5",
|
||||
"path-browserify": "1.0.1",
|
||||
"prettier": "2.2.1",
|
||||
"pretty-bytes": "5.6.0",
|
||||
"rimraf": "3.0.2",
|
||||
"rollup": "2.43.1",
|
||||
"rollup": "2.46.0",
|
||||
"rollup-plugin-polyfill-node": "0.6.2",
|
||||
"rollup-plugin-terser": "7.0.2",
|
||||
"shelljs": "0.8.4",
|
||||
@@ -139,7 +139,7 @@
|
||||
"test:dev-package": "cross-env INSTALL_PACKAGE=1 jest",
|
||||
"test:dist": "cross-env NODE_ENV=production jest",
|
||||
"test:dist-standalone": "cross-env NODE_ENV=production TEST_STANDALONE=1 jest",
|
||||
"test:integration": "jest tests_integration",
|
||||
"test:integration": "jest tests/integration",
|
||||
"perf:repeat": "yarn && yarn build && cross-env NODE_ENV=production node ./dist/bin-prettier.js --debug-repeat ${PERF_REPEAT:-1000} --loglevel debug ${PERF_FILE:-./index.js} > /dev/null",
|
||||
"perf:repeat-inspect": "yarn && yarn build && cross-env NODE_ENV=production node --inspect-brk ./dist/bin-prettier.js --debug-repeat ${PERF_REPEAT:-1000} --loglevel debug ${PERF_FILE:-./index.js} > /dev/null",
|
||||
"perf:benchmark": "yarn && yarn build && cross-env NODE_ENV=production node ./dist/bin-prettier.js --debug-benchmark --loglevel debug ${PERF_FILE:-./index.js} > /dev/null",
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
{
|
||||
"private": true,
|
||||
"dependencies": {
|
||||
"chalk": "2.4.1",
|
||||
"execa": "0.10.0",
|
||||
"minimist": "1.2.3",
|
||||
"chalk": "4.1.1",
|
||||
"execa": "5.0.0",
|
||||
"minimist": "1.2.5",
|
||||
"node-fetch": "2.6.1",
|
||||
"outdent": "0.7.1",
|
||||
"semver": "5.5.0",
|
||||
"string-width": "2.1.1"
|
||||
"outdent": "0.8.0",
|
||||
"semver": "7.3.5",
|
||||
"string-width": "4.2.0"
|
||||
}
|
||||
}
|
||||
@@ -2,15 +2,14 @@
|
||||
|
||||
"use strict";
|
||||
|
||||
const { exec, execSync } = require("child_process");
|
||||
const { exec } = require("child_process");
|
||||
|
||||
async function run() {
|
||||
const chalk = require("chalk");
|
||||
const { string: outdentString } = require("outdent");
|
||||
const minimist = require("minimist");
|
||||
const semver = require("semver");
|
||||
|
||||
const { readJson } = require("./utils");
|
||||
const { string: outdentString } = require("outdent");
|
||||
const { runGit, readJson } = require("./utils");
|
||||
|
||||
const params = minimist(process.argv.slice(2), {
|
||||
string: ["version"],
|
||||
@@ -18,9 +17,11 @@ async function run() {
|
||||
alias: { v: "version" },
|
||||
});
|
||||
|
||||
const previousVersion = execSync("git describe --tags --abbrev=0")
|
||||
.toString()
|
||||
.trim();
|
||||
const { stdout: previousVersion } = await runGit([
|
||||
"describe",
|
||||
"--tags",
|
||||
"--abbrev=0",
|
||||
]);
|
||||
|
||||
if (semver.parse(previousVersion) === null) {
|
||||
throw new Error(`Unexpected previousVersion: ${previousVersion}`);
|
||||
|
||||
@@ -1,32 +1,33 @@
|
||||
"use strict";
|
||||
|
||||
const fs = require("fs");
|
||||
const execa = require("execa");
|
||||
const semver = require("semver");
|
||||
const { logPromise, readJson, writeJson } = require("../utils");
|
||||
const {
|
||||
runYarn,
|
||||
runGit,
|
||||
logPromise,
|
||||
readJson,
|
||||
writeJson,
|
||||
} = require("../utils");
|
||||
|
||||
async function format() {
|
||||
await execa("yarn", ["lint:eslint", "--fix"]);
|
||||
await execa("yarn", ["lint:prettier", "--write"]);
|
||||
await runYarn(["lint:eslint", "--fix"]);
|
||||
await runYarn(["lint:prettier", "--write"]);
|
||||
}
|
||||
|
||||
async function commit(version) {
|
||||
await execa("git", [
|
||||
"commit",
|
||||
"-am",
|
||||
`Bump Prettier dependency to ${version}`,
|
||||
]);
|
||||
await runGit(["commit", "-am", `Bump Prettier dependency to ${version}`]);
|
||||
|
||||
// Add rev to `.git-blame-ignore-revs` file
|
||||
const file = ".git-blame-ignore-revs";
|
||||
const mark = "# Prettier bump after release";
|
||||
const rev = await execa.stdout("git", ["rev-parse", "HEAD"]);
|
||||
const { stdout: rev } = await runGit("git", ["rev-parse", "HEAD"]);
|
||||
let text = fs.readFileSync(file, "utf8");
|
||||
text = text.replace(mark, `${mark}\n# ${version}\n${rev}`);
|
||||
fs.writeFileSync(file, text);
|
||||
await execa("git", ["commit", "-am", `Git blame ignore ${version}`]);
|
||||
await runGit(["commit", "-am", `Git blame ignore ${version}`]);
|
||||
|
||||
await execa("git", ["push"]);
|
||||
await runGit(["push"]);
|
||||
}
|
||||
|
||||
async function bump({
|
||||
@@ -52,7 +53,7 @@ module.exports = async function (params) {
|
||||
|
||||
await logPromise(
|
||||
"Installing Prettier",
|
||||
execa("yarn", ["add", "--dev", `prettier@${version}`])
|
||||
runYarn(["add", "--dev", `prettier@${version}`])
|
||||
);
|
||||
|
||||
await logPromise("Updating files", format());
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
"use strict";
|
||||
|
||||
const execa = require("execa");
|
||||
const { runGit } = require("../utils");
|
||||
|
||||
module.exports = async function () {
|
||||
const status = await execa.stdout("git", ["status", "--porcelain"]);
|
||||
const { stdout: status } = await runGit(["status", "--porcelain"]);
|
||||
|
||||
if (status) {
|
||||
throw new Error(
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
"use strict";
|
||||
|
||||
const execa = require("execa");
|
||||
const { logPromise } = require("../utils");
|
||||
const { runYarn, runGit, logPromise } = require("../utils");
|
||||
|
||||
async function install() {
|
||||
await execa("rm", ["-rf", "node_modules"]);
|
||||
await execa("yarn", ["install"]);
|
||||
await runYarn(["install"]);
|
||||
|
||||
const status = await execa.stdout("git", ["ls-files", "-m"]);
|
||||
const { stdout: status } = await runGit(["ls-files", "-m"]);
|
||||
if (status) {
|
||||
throw new Error(
|
||||
"The lockfile needs to be updated, commit it before making the release."
|
||||
|
||||
@@ -2,9 +2,8 @@
|
||||
|
||||
const chalk = require("chalk");
|
||||
const { string: outdentString } = require("outdent");
|
||||
const fetch = require("node-fetch");
|
||||
const execa = require("execa");
|
||||
const { logPromise } = require("../utils");
|
||||
const { fetchText, logPromise } = require("../utils");
|
||||
|
||||
const SCHEMA_REPO = "SchemaStore/schemastore";
|
||||
const SCHEMA_PATH = "src/schemas/json/prettierrc.json";
|
||||
@@ -14,15 +13,15 @@ const EDIT_URL = `https://github.com/${SCHEMA_REPO}/edit/master/${SCHEMA_PATH}`;
|
||||
// Any optional or manual step can be warned in this script.
|
||||
|
||||
async function checkSchema() {
|
||||
const schema = await execa.stdout("node", ["scripts/generate-schema.js"]);
|
||||
const { stdout: schema } = await execa("node", [
|
||||
"scripts/generate-schema.js",
|
||||
]);
|
||||
const remoteSchema = await logPromise(
|
||||
"Checking current schema in SchemaStore",
|
||||
fetch(RAW_URL)
|
||||
.then((r) => r.text())
|
||||
.then((t) => t.trim())
|
||||
fetchText(RAW_URL)
|
||||
);
|
||||
|
||||
if (schema === remoteSchema) {
|
||||
if (schema === remoteSchema.trim()) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,13 +1,12 @@
|
||||
"use strict";
|
||||
|
||||
const execa = require("execa");
|
||||
const { logPromise } = require("../utils");
|
||||
const { runGit, logPromise } = require("../utils");
|
||||
|
||||
async function pushGit({ version }) {
|
||||
await execa("git", ["commit", "-am", `Release ${version}`]);
|
||||
await execa("git", ["tag", "-a", version, "-m", `Release ${version}`]);
|
||||
await execa("git", ["push"]);
|
||||
await execa("git", ["push", "--tags"]);
|
||||
await runGit(["commit", "-am", `Release ${version}`]);
|
||||
await runGit(["tag", "-a", version, "-m", `Release ${version}`]);
|
||||
await runGit(["push"]);
|
||||
await runGit(["push", "--tags"]);
|
||||
}
|
||||
|
||||
module.exports = function (params) {
|
||||
|
||||
@@ -1,16 +1,12 @@
|
||||
"use strict";
|
||||
|
||||
const chalk = require("chalk");
|
||||
const fetch = require("node-fetch");
|
||||
const execa = require("execa");
|
||||
const { logPromise, processFile } = require("../utils");
|
||||
const { runGit, fetchText, logPromise, processFile } = require("../utils");
|
||||
|
||||
async function update() {
|
||||
const npmPage = await logPromise(
|
||||
"Fetching npm dependents count",
|
||||
fetch("https://www.npmjs.com/package/prettier").then((response) =>
|
||||
response.text()
|
||||
)
|
||||
fetchText("https://www.npmjs.com/package/prettier")
|
||||
);
|
||||
const dependentsCountNpm = Number(
|
||||
npmPage.match(/"dependentsCount":(\d+),/)[1]
|
||||
@@ -23,9 +19,7 @@ async function update() {
|
||||
|
||||
const githubPage = await logPromise(
|
||||
"Fetching github dependents count",
|
||||
fetch(
|
||||
"https://github.com/prettier/prettier/network/dependents"
|
||||
).then((response) => response.text())
|
||||
fetchText("https://github.com/prettier/prettier/network/dependents")
|
||||
);
|
||||
const dependentsCountGithub = Number(
|
||||
githubPage
|
||||
@@ -55,20 +49,17 @@ async function update() {
|
||||
|
||||
const isUpdated = await logPromise(
|
||||
"Checking if dependents count has been updated",
|
||||
execa("git", ["diff", "--name-only"]).then(
|
||||
({ stdout }) => stdout === "website/pages/en/index.js"
|
||||
)
|
||||
async () =>
|
||||
(await runGit(["diff", "--name-only"])).stdout ===
|
||||
"website/pages/en/index.js"
|
||||
);
|
||||
|
||||
if (isUpdated) {
|
||||
logPromise(
|
||||
"Committing and pushing to remote",
|
||||
(async () => {
|
||||
await execa("git", ["add", "."]);
|
||||
await execa("git", ["commit", "-m", "Update dependents count"]);
|
||||
await execa("git", ["push"]);
|
||||
})()
|
||||
);
|
||||
logPromise("Committing and pushing to remote", async () => {
|
||||
await runGit(["add", "."]);
|
||||
await runGit(["commit", "-m", "Update dependents count"]);
|
||||
await runGit(["push"]);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,7 +1,12 @@
|
||||
"use strict";
|
||||
|
||||
const execa = require("execa");
|
||||
const { logPromise, readJson, writeJson, processFile } = require("../utils");
|
||||
const {
|
||||
runYarn,
|
||||
logPromise,
|
||||
readJson,
|
||||
writeJson,
|
||||
processFile,
|
||||
} = require("../utils");
|
||||
|
||||
async function bump({ version }) {
|
||||
const pkg = await readJson("package.json");
|
||||
@@ -24,7 +29,7 @@ async function bump({ version }) {
|
||||
content.replace(/(\/\/unpkg\.com\/prettier@).*?\//g, `$1${version}/`)
|
||||
);
|
||||
|
||||
await execa("yarn", ["update-stable-docs"], {
|
||||
await runYarn(["update-stable-docs"], {
|
||||
cwd: "./website",
|
||||
});
|
||||
}
|
||||
|
||||
+35
-17
@@ -6,6 +6,7 @@ const fs = require("fs");
|
||||
const chalk = require("chalk");
|
||||
const execa = require("execa");
|
||||
const stringWidth = require("string-width");
|
||||
const fetch = require("node-fetch");
|
||||
|
||||
const OK = chalk.bgGreen.black(" DONE ");
|
||||
const FAIL = chalk.bgRed.black(" FAIL ");
|
||||
@@ -19,27 +20,37 @@ function fitTerminal(input) {
|
||||
return input;
|
||||
}
|
||||
|
||||
function logPromise(name, promise) {
|
||||
async function logPromise(name, promiseOrAsyncFunction) {
|
||||
const promise =
|
||||
typeof promiseOrAsyncFunction === "function"
|
||||
? promiseOrAsyncFunction()
|
||||
: promiseOrAsyncFunction;
|
||||
|
||||
process.stdout.write(fitTerminal(name));
|
||||
|
||||
return promise
|
||||
.then((result) => {
|
||||
process.stdout.write(`${OK}\n`);
|
||||
return result;
|
||||
})
|
||||
.catch((err) => {
|
||||
process.stdout.write(`${FAIL}\n`);
|
||||
throw err;
|
||||
});
|
||||
try {
|
||||
const result = await promise;
|
||||
process.stdout.write(`${OK}\n`);
|
||||
return result;
|
||||
} catch (error) {
|
||||
process.stdout.write(`${FAIL}\n`);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
function runYarn(script) {
|
||||
return execa("yarn", [
|
||||
"--silent",
|
||||
...(Array.isArray(script) ? script : [script]),
|
||||
]).catch((error) => {
|
||||
throw new Error(`\`yarn ${script}\` failed\n${error.stdout}`);
|
||||
});
|
||||
async function runYarn(args, options) {
|
||||
args = Array.isArray(args) ? args : [args];
|
||||
|
||||
try {
|
||||
return await execa("yarn", ["--silent", ...args], options);
|
||||
} catch (error) {
|
||||
throw new Error(`\`yarn ${args.join(" ")}\` failed\n${error.stdout}`);
|
||||
}
|
||||
}
|
||||
|
||||
function runGit(args, options) {
|
||||
args = Array.isArray(args) ? args : [args];
|
||||
return execa("git", args, options);
|
||||
}
|
||||
|
||||
function waitForEnter() {
|
||||
@@ -75,8 +86,15 @@ function processFile(filename, fn) {
|
||||
fs.writeFileSync(filename, fn(content));
|
||||
}
|
||||
|
||||
async function fetchText(url) {
|
||||
const response = await fetch(url);
|
||||
return response.text();
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
runYarn,
|
||||
runGit,
|
||||
fetchText,
|
||||
logPromise,
|
||||
processFile,
|
||||
readJson,
|
||||
|
||||
+186
-134
@@ -2,155 +2,207 @@
|
||||
# yarn lockfile v1
|
||||
|
||||
|
||||
ansi-regex@^3.0.0:
|
||||
ansi-regex@^5.0.0:
|
||||
version "5.0.0"
|
||||
resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-5.0.0.tgz#388539f55179bf39339c81af30a654d69f87cb75"
|
||||
integrity sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg==
|
||||
|
||||
ansi-styles@^4.1.0:
|
||||
version "4.3.0"
|
||||
resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-4.3.0.tgz#edd803628ae71c04c85ae7a0906edad34b648937"
|
||||
integrity sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==
|
||||
dependencies:
|
||||
color-convert "^2.0.1"
|
||||
|
||||
chalk@4.1.1:
|
||||
version "4.1.1"
|
||||
resolved "https://registry.yarnpkg.com/chalk/-/chalk-4.1.1.tgz#c80b3fab28bf6371e6863325eee67e618b77e6ad"
|
||||
integrity sha512-diHzdDKxcU+bAsUboHLPEDQiw0qEe0qd7SYUn3HgcFlWgbDcfLGswOHYeGrHKzG9z6UYf01d9VFMfZxPM1xZSg==
|
||||
dependencies:
|
||||
ansi-styles "^4.1.0"
|
||||
supports-color "^7.1.0"
|
||||
|
||||
color-convert@^2.0.1:
|
||||
version "2.0.1"
|
||||
resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-2.0.1.tgz#72d3a68d598c9bdb3af2ad1e84f21d896abd4de3"
|
||||
integrity sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==
|
||||
dependencies:
|
||||
color-name "~1.1.4"
|
||||
|
||||
color-name@~1.1.4:
|
||||
version "1.1.4"
|
||||
resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2"
|
||||
integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==
|
||||
|
||||
cross-spawn@^7.0.3:
|
||||
version "7.0.3"
|
||||
resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-7.0.3.tgz#f73a85b9d5d41d045551c177e2882d4ac85728a6"
|
||||
integrity sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==
|
||||
dependencies:
|
||||
path-key "^3.1.0"
|
||||
shebang-command "^2.0.0"
|
||||
which "^2.0.1"
|
||||
|
||||
emoji-regex@^8.0.0:
|
||||
version "8.0.0"
|
||||
resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-8.0.0.tgz#e818fd69ce5ccfcb404594f842963bf53164cc37"
|
||||
integrity sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==
|
||||
|
||||
execa@5.0.0:
|
||||
version "5.0.0"
|
||||
resolved "https://registry.yarnpkg.com/execa/-/execa-5.0.0.tgz#4029b0007998a841fbd1032e5f4de86a3c1e3376"
|
||||
integrity sha512-ov6w/2LCiuyO4RLYGdpFGjkcs0wMTgGE8PrkTHikeUy5iJekXyPIKUjifk5CsE0pt7sMCrMZ3YNqoCj6idQOnQ==
|
||||
dependencies:
|
||||
cross-spawn "^7.0.3"
|
||||
get-stream "^6.0.0"
|
||||
human-signals "^2.1.0"
|
||||
is-stream "^2.0.0"
|
||||
merge-stream "^2.0.0"
|
||||
npm-run-path "^4.0.1"
|
||||
onetime "^5.1.2"
|
||||
signal-exit "^3.0.3"
|
||||
strip-final-newline "^2.0.0"
|
||||
|
||||
get-stream@^6.0.0:
|
||||
version "6.0.0"
|
||||
resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-6.0.0.tgz#3e0012cb6827319da2706e601a1583e8629a6718"
|
||||
integrity sha512-A1B3Bh1UmL0bidM/YX2NsCOTnGJePL9rO/M+Mw3m9f2gUpfokS0hi5Eah0WSUEWZdZhIZtMjkIYS7mDfOqNHbg==
|
||||
|
||||
has-flag@^4.0.0:
|
||||
version "4.0.0"
|
||||
resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-4.0.0.tgz#944771fd9c81c81265c4d6941860da06bb59479b"
|
||||
integrity sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==
|
||||
|
||||
human-signals@^2.1.0:
|
||||
version "2.1.0"
|
||||
resolved "https://registry.yarnpkg.com/human-signals/-/human-signals-2.1.0.tgz#dc91fcba42e4d06e4abaed33b3e7a3c02f514ea0"
|
||||
integrity sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==
|
||||
|
||||
is-fullwidth-code-point@^3.0.0:
|
||||
version "3.0.0"
|
||||
resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-3.0.0.tgz#ed0317c322064f79466c02966bddb605ab37d998"
|
||||
resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz#f116f8064fe90b3f7844a38997c0b75051269f1d"
|
||||
integrity sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==
|
||||
|
||||
ansi-styles@^3.2.1:
|
||||
version "3.2.1"
|
||||
resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-3.2.1.tgz#41fbb20243e50b12be0f04b8dedbf07520ce841d"
|
||||
dependencies:
|
||||
color-convert "^1.9.0"
|
||||
|
||||
chalk@2.4.1:
|
||||
version "2.4.1"
|
||||
resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.1.tgz#18c49ab16a037b6eb0152cc83e3471338215b66e"
|
||||
dependencies:
|
||||
ansi-styles "^3.2.1"
|
||||
escape-string-regexp "^1.0.5"
|
||||
supports-color "^5.3.0"
|
||||
|
||||
color-convert@^1.9.0:
|
||||
version "1.9.1"
|
||||
resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.1.tgz#c1261107aeb2f294ebffec9ed9ecad529a6097ed"
|
||||
dependencies:
|
||||
color-name "^1.1.1"
|
||||
|
||||
color-name@^1.1.1:
|
||||
version "1.1.3"
|
||||
resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.3.tgz#a7d0558bd89c42f795dd42328f740831ca53bc25"
|
||||
|
||||
cross-spawn@^6.0.0:
|
||||
version "6.0.5"
|
||||
resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-6.0.5.tgz#4a5ec7c64dfae22c3a14124dbacdee846d80cbc4"
|
||||
dependencies:
|
||||
nice-try "^1.0.4"
|
||||
path-key "^2.0.1"
|
||||
semver "^5.5.0"
|
||||
shebang-command "^1.2.0"
|
||||
which "^1.2.9"
|
||||
|
||||
escape-string-regexp@^1.0.5:
|
||||
version "1.0.5"
|
||||
resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4"
|
||||
|
||||
execa@0.10.0:
|
||||
version "0.10.0"
|
||||
resolved "https://registry.yarnpkg.com/execa/-/execa-0.10.0.tgz#ff456a8f53f90f8eccc71a96d11bdfc7f082cb50"
|
||||
dependencies:
|
||||
cross-spawn "^6.0.0"
|
||||
get-stream "^3.0.0"
|
||||
is-stream "^1.1.0"
|
||||
npm-run-path "^2.0.0"
|
||||
p-finally "^1.0.0"
|
||||
signal-exit "^3.0.0"
|
||||
strip-eof "^1.0.0"
|
||||
|
||||
get-stream@^3.0.0:
|
||||
version "3.0.0"
|
||||
resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-3.0.0.tgz#8e943d1358dc37555054ecbe2edb05aa174ede14"
|
||||
|
||||
has-flag@^3.0.0:
|
||||
version "3.0.0"
|
||||
resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-3.0.0.tgz#b5d454dc2199ae225699f3467e5a07f3b955bafd"
|
||||
|
||||
is-fullwidth-code-point@^2.0.0:
|
||||
is-stream@^2.0.0:
|
||||
version "2.0.0"
|
||||
resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz#a3b30a5c4f199183167aaab93beefae3ddfb654f"
|
||||
|
||||
is-stream@^1.1.0:
|
||||
version "1.1.0"
|
||||
resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-1.1.0.tgz#12d4a3dd4e68e0b79ceb8dbc84173ae80d91ca44"
|
||||
resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-2.0.0.tgz#bde9c32680d6fae04129d6ac9d921ce7815f78e3"
|
||||
integrity sha512-XCoy+WlUr7d1+Z8GgSuXmpuUFC9fOhRXglJMx+dwLKTkL44Cjd4W1Z5P+BQZpr+cR93aGP4S/s7Ftw6Nd/kiEw==
|
||||
|
||||
isexe@^2.0.0:
|
||||
version "2.0.0"
|
||||
resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10"
|
||||
|
||||
minimist@1.2.3:
|
||||
version "1.2.3"
|
||||
resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.3.tgz#3db5c0765545ab8637be71f333a104a965a9ca3f"
|
||||
lru-cache@^6.0.0:
|
||||
version "6.0.0"
|
||||
resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-6.0.0.tgz#6d6fe6570ebd96aaf90fcad1dafa3b2566db3a94"
|
||||
integrity sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==
|
||||
dependencies:
|
||||
yallist "^4.0.0"
|
||||
|
||||
nice-try@^1.0.4:
|
||||
version "1.0.4"
|
||||
resolved "https://registry.yarnpkg.com/nice-try/-/nice-try-1.0.4.tgz#d93962f6c52f2c1558c0fbda6d512819f1efe1c4"
|
||||
merge-stream@^2.0.0:
|
||||
version "2.0.0"
|
||||
resolved "https://registry.yarnpkg.com/merge-stream/-/merge-stream-2.0.0.tgz#52823629a14dd00c9770fb6ad47dc6310f2c1f60"
|
||||
integrity sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==
|
||||
|
||||
mimic-fn@^2.1.0:
|
||||
version "2.1.0"
|
||||
resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-2.1.0.tgz#7ed2c2ccccaf84d3ffcb7a69b57711fc2083401b"
|
||||
integrity sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==
|
||||
|
||||
minimist@1.2.5:
|
||||
version "1.2.5"
|
||||
resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.5.tgz#67d66014b66a6a8aaa0c083c5fd58df4e4e97602"
|
||||
integrity sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==
|
||||
|
||||
node-fetch@2.6.1:
|
||||
version "2.6.1"
|
||||
resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.6.1.tgz#045bd323631f76ed2e2b55573394416b639a0052"
|
||||
integrity sha512-V4aYg89jEoVRxRb2fJdAg8FHvI7cEyYdVAh94HH0UIK8oJxUfkjlDQN9RbMx+bEjP7+ggMiFRprSti032Oipxw==
|
||||
|
||||
npm-run-path@^2.0.0:
|
||||
npm-run-path@^4.0.1:
|
||||
version "4.0.1"
|
||||
resolved "https://registry.yarnpkg.com/npm-run-path/-/npm-run-path-4.0.1.tgz#b7ecd1e5ed53da8e37a55e1c2269e0b97ed748ea"
|
||||
integrity sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==
|
||||
dependencies:
|
||||
path-key "^3.0.0"
|
||||
|
||||
onetime@^5.1.2:
|
||||
version "5.1.2"
|
||||
resolved "https://registry.yarnpkg.com/onetime/-/onetime-5.1.2.tgz#d0e96ebb56b07476df1dd9c4806e5237985ca45e"
|
||||
integrity sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==
|
||||
dependencies:
|
||||
mimic-fn "^2.1.0"
|
||||
|
||||
outdent@0.8.0:
|
||||
version "0.8.0"
|
||||
resolved "https://registry.yarnpkg.com/outdent/-/outdent-0.8.0.tgz#2ebc3e77bf49912543f1008100ff8e7f44428eb0"
|
||||
integrity sha512-KiOAIsdpUTcAXuykya5fnVVT+/5uS0Q1mrkRHcF89tpieSmY33O/tmc54CqwA+bfhbtEfZUNLHaPUiB9X3jt1A==
|
||||
|
||||
path-key@^3.0.0, path-key@^3.1.0:
|
||||
version "3.1.1"
|
||||
resolved "https://registry.yarnpkg.com/path-key/-/path-key-3.1.1.tgz#581f6ade658cbba65a0d3380de7753295054f375"
|
||||
integrity sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==
|
||||
|
||||
semver@7.3.5:
|
||||
version "7.3.5"
|
||||
resolved "https://registry.yarnpkg.com/semver/-/semver-7.3.5.tgz#0b621c879348d8998e4b0e4be94b3f12e6018ef7"
|
||||
integrity sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==
|
||||
dependencies:
|
||||
lru-cache "^6.0.0"
|
||||
|
||||
shebang-command@^2.0.0:
|
||||
version "2.0.0"
|
||||
resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-2.0.0.tgz#ccd0af4f8835fbdc265b82461aaf0c36663f34ea"
|
||||
integrity sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==
|
||||
dependencies:
|
||||
shebang-regex "^3.0.0"
|
||||
|
||||
shebang-regex@^3.0.0:
|
||||
version "3.0.0"
|
||||
resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-3.0.0.tgz#ae16f1644d873ecad843b0307b143362d4c42172"
|
||||
integrity sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==
|
||||
|
||||
signal-exit@^3.0.3:
|
||||
version "3.0.3"
|
||||
resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.3.tgz#a1410c2edd8f077b08b4e253c8eacfcaf057461c"
|
||||
integrity sha512-VUJ49FC8U1OxwZLxIbTTrDvLnf/6TDgxZcK8wxR8zs13xpx7xbG60ndBlhNrFi2EMuFRoeDoJO7wthSLq42EjA==
|
||||
|
||||
string-width@4.2.0:
|
||||
version "4.2.0"
|
||||
resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.0.tgz#952182c46cc7b2c313d1596e623992bd163b72b5"
|
||||
integrity sha512-zUz5JD+tgqtuDjMhwIg5uFVV3dtqZ9yQJlZVfq4I01/K5Paj5UHj7VyrQOJvzawSVlKpObApbfD0Ed6yJc+1eg==
|
||||
dependencies:
|
||||
emoji-regex "^8.0.0"
|
||||
is-fullwidth-code-point "^3.0.0"
|
||||
strip-ansi "^6.0.0"
|
||||
|
||||
strip-ansi@^6.0.0:
|
||||
version "6.0.0"
|
||||
resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.0.tgz#0b1571dd7669ccd4f3e06e14ef1eed26225ae532"
|
||||
integrity sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==
|
||||
dependencies:
|
||||
ansi-regex "^5.0.0"
|
||||
|
||||
strip-final-newline@^2.0.0:
|
||||
version "2.0.0"
|
||||
resolved "https://registry.yarnpkg.com/strip-final-newline/-/strip-final-newline-2.0.0.tgz#89b852fb2fcbe936f6f4b3187afb0a12c1ab58ad"
|
||||
integrity sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==
|
||||
|
||||
supports-color@^7.1.0:
|
||||
version "7.2.0"
|
||||
resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-7.2.0.tgz#1b7dcdcb32b8138801b3e478ba6a51caa89648da"
|
||||
integrity sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==
|
||||
dependencies:
|
||||
has-flag "^4.0.0"
|
||||
|
||||
which@^2.0.1:
|
||||
version "2.0.2"
|
||||
resolved "https://registry.yarnpkg.com/npm-run-path/-/npm-run-path-2.0.2.tgz#35a9232dfa35d7067b4cb2ddf2357b1871536c5f"
|
||||
dependencies:
|
||||
path-key "^2.0.0"
|
||||
|
||||
outdent@0.7.1:
|
||||
version "0.7.1"
|
||||
resolved "https://registry.yarnpkg.com/outdent/-/outdent-0.7.1.tgz#e9b400443622a97760b0bc74fa3223252ccd02a2"
|
||||
integrity sha512-VjIzdUHunL74DdhcwMDt5FhNDQ8NYmTkuW0B+usIV2afS9aWT/1c9z1TsnFW349TP3nxmYeUl7Z++XpJRByvgg==
|
||||
|
||||
p-finally@^1.0.0:
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/p-finally/-/p-finally-1.0.0.tgz#3fbcfb15b899a44123b34b6dcc18b724336a2cae"
|
||||
|
||||
path-key@^2.0.0, path-key@^2.0.1:
|
||||
version "2.0.1"
|
||||
resolved "https://registry.yarnpkg.com/path-key/-/path-key-2.0.1.tgz#411cadb574c5a140d3a4b1910d40d80cc9f40b40"
|
||||
|
||||
semver@5.5.0, semver@^5.5.0:
|
||||
version "5.5.0"
|
||||
resolved "https://registry.yarnpkg.com/semver/-/semver-5.5.0.tgz#dc4bbc7a6ca9d916dee5d43516f0092b58f7b8ab"
|
||||
|
||||
shebang-command@^1.2.0:
|
||||
version "1.2.0"
|
||||
resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-1.2.0.tgz#44aac65b695b03398968c39f363fee5deafdf1ea"
|
||||
dependencies:
|
||||
shebang-regex "^1.0.0"
|
||||
|
||||
shebang-regex@^1.0.0:
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-1.0.0.tgz#da42f49740c0b42db2ca9728571cb190c98efea3"
|
||||
|
||||
signal-exit@^3.0.0:
|
||||
version "3.0.2"
|
||||
resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.2.tgz#b5fdc08f1287ea1178628e415e25132b73646c6d"
|
||||
|
||||
string-width@2.1.1:
|
||||
version "2.1.1"
|
||||
resolved "https://registry.yarnpkg.com/string-width/-/string-width-2.1.1.tgz#ab93f27a8dc13d28cac815c462143a6d9012ae9e"
|
||||
dependencies:
|
||||
is-fullwidth-code-point "^2.0.0"
|
||||
strip-ansi "^4.0.0"
|
||||
|
||||
strip-ansi@^4.0.0:
|
||||
version "4.0.0"
|
||||
resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-4.0.0.tgz#a8479022eb1ac368a871389b635262c505ee368f"
|
||||
dependencies:
|
||||
ansi-regex "^3.0.0"
|
||||
|
||||
strip-eof@^1.0.0:
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/strip-eof/-/strip-eof-1.0.0.tgz#bb43ff5598a6eb05d89b59fcd129c983313606bf"
|
||||
|
||||
supports-color@^5.3.0:
|
||||
version "5.4.0"
|
||||
resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.4.0.tgz#1c6b337402c2137605efe19f10fec390f6faab54"
|
||||
dependencies:
|
||||
has-flag "^3.0.0"
|
||||
|
||||
which@^1.2.9:
|
||||
version "1.3.1"
|
||||
resolved "https://registry.yarnpkg.com/which/-/which-1.3.1.tgz#a45043d54f5805316da8d62f9f50918d3da70b0a"
|
||||
resolved "https://registry.yarnpkg.com/which/-/which-2.0.2.tgz#7c6a8dd0a636a0327e10b59c9286eee93f3f51b1"
|
||||
integrity sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==
|
||||
dependencies:
|
||||
isexe "^2.0.0"
|
||||
|
||||
yallist@^4.0.0:
|
||||
version "4.0.0"
|
||||
resolved "https://registry.yarnpkg.com/yallist/-/yallist-4.0.0.tgz#9bb92790d9c0effec63be73519e11a35019a3a72"
|
||||
integrity sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==
|
||||
@@ -7,6 +7,7 @@ module.exports = {
|
||||
"directly-loc-start-end": require("./directly-loc-start-end"),
|
||||
"flat-ast-path-call": require("./flat-ast-path-call"),
|
||||
"jsx-identifier-case": require("./jsx-identifier-case"),
|
||||
"no-conflicting-comment-check-flags": require("./no-conflicting-comment-check-flags"),
|
||||
"no-doc-builder-concat": require("./no-doc-builder-concat"),
|
||||
"no-empty-flat-contents-for-if-break": require("./no-empty-flat-contents-for-if-break"),
|
||||
"no-identifier-n": require("./no-identifier-n"),
|
||||
|
||||
+87
@@ -0,0 +1,87 @@
|
||||
"use strict";
|
||||
const MESSAGE_ID_UNIQUE = "unique";
|
||||
const MESSAGE_ID_CONFLICTING = "conflicting";
|
||||
|
||||
const conflictingFlags = [
|
||||
["Leading", "Trailing", "Dangling"],
|
||||
["Block", "Line"],
|
||||
];
|
||||
|
||||
const isCommentCheckFlags = (node) =>
|
||||
node.type === "MemberExpression" &&
|
||||
!node.computed &&
|
||||
!node.optional &&
|
||||
node.object.type === "Identifier" &&
|
||||
node.object.name === "CommentCheckFlags" &&
|
||||
node.property.type === "Identifier";
|
||||
|
||||
const flatFlags = (node) => {
|
||||
const flags = [];
|
||||
const binaryExpressions = [node];
|
||||
while (binaryExpressions.length > 0) {
|
||||
const { left, right } = binaryExpressions.shift();
|
||||
for (const node of [left, right]) {
|
||||
if (node.type === "BinaryExpression" && node.operator === "|") {
|
||||
binaryExpressions.push(node);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!isCommentCheckFlags(node)) {
|
||||
return [];
|
||||
}
|
||||
|
||||
flags.push(node);
|
||||
}
|
||||
}
|
||||
|
||||
return flags.map((node) => node.property.name);
|
||||
};
|
||||
|
||||
module.exports = {
|
||||
meta: {
|
||||
type: "suggestion",
|
||||
docs: {
|
||||
url:
|
||||
"https://github.com/prettier/prettier/blob/main/scripts/eslint-plugin-prettier-internal-rules/no-conflicting-comment-check-flags.js",
|
||||
},
|
||||
messages: {
|
||||
[MESSAGE_ID_UNIQUE]: "Do not use same flag multiple times.",
|
||||
[MESSAGE_ID_CONFLICTING]: "Do not use {{flags}} together.",
|
||||
},
|
||||
},
|
||||
create(context) {
|
||||
return {
|
||||
':not(BinaryExpression) > BinaryExpression[operator="|"]'(node) {
|
||||
const flags = flatFlags(node);
|
||||
|
||||
if (flags.length < 2) {
|
||||
return;
|
||||
}
|
||||
|
||||
const uniqueFlags = new Set(flags);
|
||||
if (uniqueFlags.size !== flags.length) {
|
||||
context.report({
|
||||
node,
|
||||
messageId: MESSAGE_ID_UNIQUE,
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
for (const group of conflictingFlags) {
|
||||
const presentFlags = group.filter((flag) => uniqueFlags.has(flag));
|
||||
if (presentFlags.length > 1) {
|
||||
context.report({
|
||||
node,
|
||||
messageId: MESSAGE_ID_CONFLICTING,
|
||||
data: {
|
||||
flags: presentFlags
|
||||
.map((flag) => `'CommentCheckFlags.${flag}'`)
|
||||
.join(", "),
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
},
|
||||
};
|
||||
},
|
||||
};
|
||||
@@ -166,6 +166,69 @@ test("jsx-identifier-case", {
|
||||
],
|
||||
});
|
||||
|
||||
test("no-conflicting-comment-check-flags", {
|
||||
valid: [
|
||||
"CommentCheckFlags.Leading",
|
||||
"NotCommentCheckFlags.Leading | NotCommentCheckFlags.Trailing",
|
||||
"CommentCheckFlags.Leading | CommentCheckFlags.Trailing | SOMETHING_ELSE",
|
||||
"CommentCheckFlags.Leading & CommentCheckFlags.Trailing",
|
||||
],
|
||||
invalid: [
|
||||
{
|
||||
code: "CommentCheckFlags.Leading | CommentCheckFlags.Trailing",
|
||||
output: null,
|
||||
errors: [
|
||||
{
|
||||
message:
|
||||
"Do not use 'CommentCheckFlags.Leading', 'CommentCheckFlags.Trailing' together.",
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
code:
|
||||
"(CommentCheckFlags.Leading | CommentCheckFlags.Trailing) | CommentCheckFlags.Dangling",
|
||||
output: null,
|
||||
errors: [
|
||||
{
|
||||
message:
|
||||
"Do not use 'CommentCheckFlags.Leading', 'CommentCheckFlags.Trailing', 'CommentCheckFlags.Dangling' together.",
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
code:
|
||||
"CommentCheckFlags.Leading | CommentCheckFlags.Trailing | CommentCheckFlags.UNKNOWN",
|
||||
output: null,
|
||||
errors: [
|
||||
{
|
||||
message:
|
||||
"Do not use 'CommentCheckFlags.Leading', 'CommentCheckFlags.Trailing' together.",
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
code:
|
||||
"CommentCheckFlags.Block | CommentCheckFlags.Line | CommentCheckFlags.UNKNOWN",
|
||||
output: null,
|
||||
errors: [
|
||||
{
|
||||
message:
|
||||
"Do not use 'CommentCheckFlags.Block', 'CommentCheckFlags.Line' together.",
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
code: "CommentCheckFlags.Block | CommentCheckFlags.Block",
|
||||
output: null,
|
||||
errors: [
|
||||
{
|
||||
message: "Do not use same flag multiple times.",
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
test("no-doc-builder-concat", {
|
||||
valid: ["notConcat([])", "concat", "[].concat([])"],
|
||||
invalid: [
|
||||
|
||||
@@ -110,6 +110,21 @@ class AstPath {
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {() => void} callback
|
||||
* @internal Unstable API. Don't use in plugins for now.
|
||||
*/
|
||||
try(callback) {
|
||||
const { stack } = this;
|
||||
const stackBackup = [...stack];
|
||||
try {
|
||||
return callback();
|
||||
} finally {
|
||||
stack.length = 0;
|
||||
stack.push(...stackBackup);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {...(
|
||||
* | ((node: any, name: string | null, number: number | null) => boolean)
|
||||
|
||||
@@ -3,9 +3,11 @@
|
||||
class ConfigError extends Error {}
|
||||
class DebugError extends Error {}
|
||||
class UndefinedParserError extends Error {}
|
||||
class ArgExpansionBailout extends Error {}
|
||||
|
||||
module.exports = {
|
||||
ConfigError,
|
||||
DebugError,
|
||||
UndefinedParserError,
|
||||
ArgExpansionBailout,
|
||||
};
|
||||
+42
-15
@@ -71,26 +71,53 @@ function traverseDoc(doc, onEnter, onExit, shouldTraverseConditionalGroups) {
|
||||
}
|
||||
|
||||
function mapDoc(doc, cb) {
|
||||
if (Array.isArray(doc)) {
|
||||
return cb(doc.map((part) => mapDoc(part, cb)));
|
||||
// Within a doc tree, the same subtrees can be found multiple times.
|
||||
// E.g., often this happens in conditional groups.
|
||||
// As an optimization (those subtrees can be huge) and to maintain the
|
||||
// reference structure of the tree, the mapping results are cached in
|
||||
// a map and reused.
|
||||
const mapped = new Map();
|
||||
|
||||
return rec(doc);
|
||||
|
||||
function rec(doc) {
|
||||
if (mapped.has(doc)) {
|
||||
return mapped.get(doc);
|
||||
}
|
||||
const result = process(doc);
|
||||
mapped.set(doc, result);
|
||||
return result;
|
||||
}
|
||||
|
||||
if (doc.type === "concat" || doc.type === "fill") {
|
||||
const parts = doc.parts.map((part) => mapDoc(part, cb));
|
||||
return cb({ ...doc, parts });
|
||||
}
|
||||
function process(doc) {
|
||||
if (Array.isArray(doc)) {
|
||||
return cb(doc.map(rec));
|
||||
}
|
||||
|
||||
if (doc.type === "if-break") {
|
||||
const breakContents = doc.breakContents && mapDoc(doc.breakContents, cb);
|
||||
const flatContents = doc.flatContents && mapDoc(doc.flatContents, cb);
|
||||
return cb({ ...doc, breakContents, flatContents });
|
||||
}
|
||||
if (doc.type === "concat" || doc.type === "fill") {
|
||||
const parts = doc.parts.map(rec);
|
||||
return cb({ ...doc, parts });
|
||||
}
|
||||
|
||||
if (doc.contents) {
|
||||
const contents = mapDoc(doc.contents, cb);
|
||||
return cb({ ...doc, contents });
|
||||
if (doc.type === "if-break") {
|
||||
const breakContents = doc.breakContents && rec(doc.breakContents);
|
||||
const flatContents = doc.flatContents && rec(doc.flatContents);
|
||||
return cb({ ...doc, breakContents, flatContents });
|
||||
}
|
||||
|
||||
if (doc.type === "group" && doc.expandedStates) {
|
||||
const expandedStates = doc.expandedStates.map(rec);
|
||||
const contents = expandedStates[0];
|
||||
return cb({ ...doc, contents, expandedStates });
|
||||
}
|
||||
|
||||
if (doc.contents) {
|
||||
const contents = rec(doc.contents);
|
||||
return cb({ ...doc, contents });
|
||||
}
|
||||
|
||||
return cb(doc);
|
||||
}
|
||||
return cb(doc);
|
||||
}
|
||||
|
||||
function findInDoc(doc, fn, defaultValue) {
|
||||
|
||||
@@ -534,7 +534,7 @@ function parseNestedCSS(node, options) {
|
||||
|
||||
// `@color :blue;`
|
||||
if (
|
||||
!["page", "nest"].includes(node.name) &&
|
||||
!["page", "nest", "keyframes"].includes(node.name) &&
|
||||
node.params &&
|
||||
node.params[0] === ":"
|
||||
) {
|
||||
|
||||
@@ -39,6 +39,9 @@ function genericPrint(path, options, print) {
|
||||
return [
|
||||
hasOperation ? node.operation : "",
|
||||
hasOperation && hasName ? [" ", print("name")] : "",
|
||||
hasOperation && !hasName && isNonEmptyArray(node.variableDefinitions)
|
||||
? " "
|
||||
: "",
|
||||
isNonEmptyArray(node.variableDefinitions)
|
||||
? group([
|
||||
"(",
|
||||
|
||||
@@ -121,27 +121,13 @@ function print(path, options, print) {
|
||||
}
|
||||
|
||||
case "ElementModifierStatement": {
|
||||
return group(["{{", printPathAndParams(path, print), softline, "}}"]);
|
||||
return group(["{{", printPathAndParams(path, print), "}}"]);
|
||||
}
|
||||
|
||||
case "MustacheStatement": {
|
||||
const isParentOfSpecifiedTypes = isParentOfSomeType(path, [
|
||||
"AttrNode",
|
||||
"ConcatStatement",
|
||||
]);
|
||||
|
||||
const isChildOfElementNodeAndDoesNotHaveParams =
|
||||
isParentOfSomeType(path, ["ElementNode"]) &&
|
||||
doesNotHaveHashParams(node) &&
|
||||
doesNotHavePositionalParams(node);
|
||||
|
||||
const shouldBreakOpeningMustache =
|
||||
isParentOfSpecifiedTypes || isChildOfElementNodeAndDoesNotHaveParams;
|
||||
|
||||
return group([
|
||||
printOpeningMustache(node),
|
||||
shouldBreakOpeningMustache ? indent(softline) : "",
|
||||
printPathAndParams(path, print),
|
||||
softline,
|
||||
printClosingMustache(node),
|
||||
]);
|
||||
}
|
||||
@@ -550,7 +536,7 @@ function printOpenBlock(path, print) {
|
||||
|
||||
return group([
|
||||
openingMustache,
|
||||
indent(group(attributes)),
|
||||
indent(attributes),
|
||||
softline,
|
||||
closingMustache,
|
||||
]);
|
||||
@@ -570,8 +556,8 @@ function printElseIfBlock(path, print) {
|
||||
|
||||
return [
|
||||
printInverseBlockOpeningMustache(parentNode),
|
||||
"else ",
|
||||
printPathAndParams(path, print),
|
||||
"else if ",
|
||||
printParams(path, print),
|
||||
printInverseBlockClosingMustache(parentNode),
|
||||
];
|
||||
}
|
||||
@@ -764,7 +750,7 @@ function printPathAndParams(path, print) {
|
||||
return p;
|
||||
}
|
||||
|
||||
return indent(group([p, line, params]));
|
||||
return [indent([p, line, params]), softline];
|
||||
}
|
||||
|
||||
function printPath(path, print) {
|
||||
@@ -796,14 +782,6 @@ function printBlockParams(node) {
|
||||
return ["as |", node.blockParams.join(" "), "|"];
|
||||
}
|
||||
|
||||
function doesNotHaveHashParams(node) {
|
||||
return node.hash.pairs.length === 0;
|
||||
}
|
||||
|
||||
function doesNotHavePositionalParams(node) {
|
||||
return node.params.length === 0;
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
print,
|
||||
massageAstNode: clean,
|
||||
|
||||
Vendored
+39
@@ -0,0 +1,39 @@
|
||||
import "angular-html-parser/lib/compiler/src/ml_parser/ast";
|
||||
import { HtmlTagDefinition } from "angular-html-parser/lib/compiler/src/ml_parser/html_tags";
|
||||
|
||||
declare module "angular-html-parser/lib/compiler/src/ml_parser/ast" {
|
||||
interface Attribute {
|
||||
startSourceSpan: never;
|
||||
endSourceSpan: never;
|
||||
// see restoreName in parser-html.js
|
||||
namespace?: string | null;
|
||||
hasExplicitNamespace?: boolean;
|
||||
}
|
||||
|
||||
interface CDATA {
|
||||
startSourceSpan: never;
|
||||
endSourceSpan: never;
|
||||
}
|
||||
|
||||
interface Comment {
|
||||
startSourceSpan: never;
|
||||
endSourceSpan: never;
|
||||
}
|
||||
|
||||
interface DocType {
|
||||
startSourceSpan: never;
|
||||
endSourceSpan: never;
|
||||
}
|
||||
|
||||
interface Element {
|
||||
tagDefinition: HtmlTagDefinition;
|
||||
// see restoreName in parser-html.js
|
||||
namespace?: string | null;
|
||||
hasExplicitNamespace?: boolean;
|
||||
}
|
||||
|
||||
interface Text {
|
||||
startSourceSpan: never;
|
||||
endSourceSpan: never;
|
||||
}
|
||||
}
|
||||
@@ -3,11 +3,15 @@
|
||||
const fromPairs = require("lodash/fromPairs");
|
||||
const { isNonEmptyArray } = require("../common/util");
|
||||
const getLast = require("../utils/get-last");
|
||||
|
||||
const NODES_KEYS = {
|
||||
attrs: true,
|
||||
children: true,
|
||||
};
|
||||
|
||||
// TODO: typechecking is problematic for this class because of this issue:
|
||||
// https://github.com/microsoft/TypeScript/issues/26811
|
||||
|
||||
class Node {
|
||||
constructor(props = {}) {
|
||||
for (const [key, value] of Object.entries(props)) {
|
||||
@@ -33,6 +37,7 @@ class Node {
|
||||
}
|
||||
|
||||
map(fn) {
|
||||
/** @type{any} */
|
||||
let newNode = null;
|
||||
|
||||
for (const NODES_KEY in NODES_KEYS) {
|
||||
@@ -54,6 +59,7 @@ class Node {
|
||||
newNode[key] = this[key];
|
||||
}
|
||||
}
|
||||
// @ts-ignore
|
||||
const { index, siblings, prev, next, parent } = this;
|
||||
setNonEnumerableProperties(newNode, {
|
||||
index,
|
||||
@@ -67,23 +73,30 @@ class Node {
|
||||
return fn(newNode || this);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Object} [overrides]
|
||||
*/
|
||||
clone(overrides) {
|
||||
return new Node(overrides ? { ...this, ...overrides } : this);
|
||||
}
|
||||
|
||||
get firstChild() {
|
||||
// @ts-ignore
|
||||
return isNonEmptyArray(this.children) ? this.children[0] : null;
|
||||
}
|
||||
|
||||
get lastChild() {
|
||||
// @ts-ignore
|
||||
return isNonEmptyArray(this.children) ? getLast(this.children) : null;
|
||||
}
|
||||
|
||||
// for element and attribute
|
||||
get rawName() {
|
||||
// @ts-ignore
|
||||
return this.hasExplicitNamespace ? this.fullName : this.name;
|
||||
}
|
||||
get fullName() {
|
||||
// @ts-ignore
|
||||
return this.namespace ? this.namespace + ":" + this.name : this.name;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,24 +6,29 @@ const {
|
||||
|
||||
// https://css-tricks.com/how-to-create-an-ie-only-stylesheet
|
||||
|
||||
// <!--[if ... ]> ... <![endif]-->
|
||||
const IE_CONDITIONAL_START_END_COMMENT_REGEX = /^(\[if([^\]]*?)]>)([\S\s]*?)<!\s*\[endif]$/;
|
||||
// <!--[if ... ]><!-->
|
||||
const IE_CONDITIONAL_START_COMMENT_REGEX = /^\[if([^\]]*?)]><!$/;
|
||||
// <!--<![endif]-->
|
||||
const IE_CONDITIONAL_END_COMMENT_REGEX = /^<!\s*\[endif]$/;
|
||||
|
||||
const REGEX_PARSE_TUPLES = [
|
||||
[IE_CONDITIONAL_START_END_COMMENT_REGEX, parseIeConditionalStartEndComment],
|
||||
[IE_CONDITIONAL_START_COMMENT_REGEX, parseIeConditionalStartComment],
|
||||
[IE_CONDITIONAL_END_COMMENT_REGEX, parseIeConditionalEndComment],
|
||||
const parseFunctions = [
|
||||
{
|
||||
// <!--[if ... ]> ... <![endif]-->
|
||||
regex: /^(\[if([^\]]*?)]>)(.*?)<!\s*\[endif]$/s,
|
||||
parse: parseIeConditionalStartEndComment,
|
||||
},
|
||||
{
|
||||
// <!--[if ... ]><!-->
|
||||
regex: /^\[if([^\]]*?)]><!$/,
|
||||
parse: parseIeConditionalStartComment,
|
||||
},
|
||||
{
|
||||
// <!--<![endif]-->
|
||||
regex: /^<!\s*\[endif]$/,
|
||||
parse: parseIeConditionalEndComment,
|
||||
},
|
||||
];
|
||||
|
||||
function parseIeConditionalComment(node, parseHtml) {
|
||||
if (node.value) {
|
||||
let match;
|
||||
for (const [regex, parse] of REGEX_PARSE_TUPLES) {
|
||||
if ((match = node.value.match(regex))) {
|
||||
for (const { regex, parse } of parseFunctions) {
|
||||
const match = node.value.match(regex);
|
||||
if (match) {
|
||||
return parse(node, parseHtml, match);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,6 +19,27 @@ const { Node } = require("./ast");
|
||||
const { parseIeConditionalComment } = require("./conditional-comment");
|
||||
const { locStart, locEnd } = require("./loc");
|
||||
|
||||
/**
|
||||
* @typedef {import('angular-html-parser/lib/compiler/src/ml_parser/ast').Node} AstNode
|
||||
* @typedef {import('angular-html-parser/lib/compiler/src/ml_parser/ast').Attribute} Attribute
|
||||
* @typedef {import('angular-html-parser/lib/compiler/src/ml_parser/ast').Element} Element
|
||||
* @typedef {import('angular-html-parser/lib/compiler/src/ml_parser/parser').ParseTreeResult} ParserTreeResult
|
||||
* @typedef {Omit<import('angular-html-parser').ParseOptions, 'canSelfClose'> & {
|
||||
* recognizeSelfClosing?: boolean;
|
||||
* normalizeTagName?: boolean;
|
||||
* normalizeAttributeName?: boolean;
|
||||
* }} ParserOptions
|
||||
* @typedef {{
|
||||
* parser: 'html' | 'angular' | 'vue' | 'lwc',
|
||||
* filepath?: string
|
||||
* }} Options
|
||||
*/
|
||||
|
||||
/**
|
||||
* @param {string} input
|
||||
* @param {ParserOptions} parserOptions
|
||||
* @param {Options} options
|
||||
*/
|
||||
function ngHtmlParser(
|
||||
input,
|
||||
{
|
||||
@@ -35,12 +56,6 @@ function ngHtmlParser(
|
||||
const {
|
||||
RecursiveVisitor,
|
||||
visitAll,
|
||||
Attribute,
|
||||
CDATA,
|
||||
Comment,
|
||||
DocType,
|
||||
Element,
|
||||
Text,
|
||||
} = require("angular-html-parser/lib/compiler/src/ml_parser/ast");
|
||||
const {
|
||||
ParseSourceSpan,
|
||||
@@ -56,82 +71,85 @@ function ngHtmlParser(
|
||||
getTagContentType,
|
||||
});
|
||||
|
||||
const isVueHtml =
|
||||
options.parser === "vue" &&
|
||||
rootNodes.some(
|
||||
if (options.parser === "vue") {
|
||||
const isVueHtml = rootNodes.some(
|
||||
(node) =>
|
||||
(node instanceof DocType && node.value === "html") ||
|
||||
(node instanceof Element && node.name.toLowerCase() === "html")
|
||||
(node.type === "docType" && node.value === "html") ||
|
||||
(node.type === "element" && node.name.toLowerCase() === "html")
|
||||
);
|
||||
|
||||
if (options.parser === "vue" && !isVueHtml) {
|
||||
const shouldParseAsHTML = (node) => {
|
||||
/* istanbul ignore next */
|
||||
if (!node) {
|
||||
return false;
|
||||
}
|
||||
if (node.name !== "template") {
|
||||
return false;
|
||||
}
|
||||
const langAttr = node.attrs.find((attr) => attr.name === "lang");
|
||||
const langValue = langAttr && langAttr.value;
|
||||
return !langValue || inferParserByLanguage(langValue, options) === "html";
|
||||
};
|
||||
if (rootNodes.some(shouldParseAsHTML)) {
|
||||
let secondParseResult;
|
||||
const doSecondParse = () =>
|
||||
parser.parse(input, {
|
||||
canSelfClose: recognizeSelfClosing,
|
||||
allowHtmComponentClosingTags,
|
||||
isTagNameCaseSensitive,
|
||||
});
|
||||
const getSecondParse = () =>
|
||||
secondParseResult || (secondParseResult = doSecondParse());
|
||||
const getSameLocationNode = (node) =>
|
||||
getSecondParse().rootNodes.find(
|
||||
({ startSourceSpan }) =>
|
||||
startSourceSpan &&
|
||||
startSourceSpan.start.offset === node.startSourceSpan.start.offset
|
||||
if (!isVueHtml) {
|
||||
const shouldParseAsHTML = (/** @type {AstNode} */ node) => {
|
||||
/* istanbul ignore next */
|
||||
if (!node) {
|
||||
return false;
|
||||
}
|
||||
if (node.type !== "element" || node.name !== "template") {
|
||||
return false;
|
||||
}
|
||||
const langAttr = node.attrs.find((attr) => attr.name === "lang");
|
||||
const langValue = langAttr && langAttr.value;
|
||||
return (
|
||||
!langValue || inferParserByLanguage(langValue, options) === "html"
|
||||
);
|
||||
for (let i = 0; i < rootNodes.length; i++) {
|
||||
const node = rootNodes[i];
|
||||
const { endSourceSpan, startSourceSpan } = node;
|
||||
const isUnclosedNode = endSourceSpan === null;
|
||||
if (isUnclosedNode) {
|
||||
const result = getSecondParse();
|
||||
errors = result.errors;
|
||||
rootNodes[i] = getSameLocationNode(node) || node;
|
||||
} else if (shouldParseAsHTML(node)) {
|
||||
const result = getSecondParse();
|
||||
const startOffset = startSourceSpan.end.offset;
|
||||
const endOffset = endSourceSpan.start.offset;
|
||||
for (const error of result.errors) {
|
||||
const { offset } = error.span.start;
|
||||
/* istanbul ignore next */
|
||||
if (startOffset < offset && offset < endOffset) {
|
||||
errors = [error];
|
||||
break;
|
||||
};
|
||||
if (rootNodes.some(shouldParseAsHTML)) {
|
||||
/** @type {ParserTreeResult | undefined} */
|
||||
let secondParseResult;
|
||||
const doSecondParse = () =>
|
||||
parser.parse(input, {
|
||||
canSelfClose: recognizeSelfClosing,
|
||||
allowHtmComponentClosingTags,
|
||||
isTagNameCaseSensitive,
|
||||
});
|
||||
const getSecondParse = () =>
|
||||
secondParseResult || (secondParseResult = doSecondParse());
|
||||
const getSameLocationNode = (node) =>
|
||||
getSecondParse().rootNodes.find(
|
||||
({ startSourceSpan }) =>
|
||||
startSourceSpan &&
|
||||
startSourceSpan.start.offset === node.startSourceSpan.start.offset
|
||||
);
|
||||
for (let i = 0; i < rootNodes.length; i++) {
|
||||
const node = rootNodes[i];
|
||||
const { endSourceSpan, startSourceSpan } = node;
|
||||
const isUnclosedNode = endSourceSpan === null;
|
||||
if (isUnclosedNode) {
|
||||
const result = getSecondParse();
|
||||
errors = result.errors;
|
||||
rootNodes[i] = getSameLocationNode(node) || node;
|
||||
} else if (shouldParseAsHTML(node)) {
|
||||
const result = getSecondParse();
|
||||
const startOffset = startSourceSpan.end.offset;
|
||||
const endOffset = endSourceSpan.start.offset;
|
||||
for (const error of result.errors) {
|
||||
const { offset } = error.span.start;
|
||||
/* istanbul ignore next */
|
||||
if (startOffset < offset && offset < endOffset) {
|
||||
errors = [error];
|
||||
break;
|
||||
}
|
||||
}
|
||||
rootNodes[i] = getSameLocationNode(node) || node;
|
||||
}
|
||||
rootNodes[i] = getSameLocationNode(node) || node;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (isVueHtml) {
|
||||
// If not Vue SFC, treat as html
|
||||
recognizeSelfClosing = true;
|
||||
normalizeTagName = true;
|
||||
normalizeAttributeName = true;
|
||||
allowHtmComponentClosingTags = true;
|
||||
isTagNameCaseSensitive = false;
|
||||
const htmlParseResult = parser.parse(input, {
|
||||
canSelfClose: recognizeSelfClosing,
|
||||
allowHtmComponentClosingTags,
|
||||
isTagNameCaseSensitive,
|
||||
});
|
||||
} else {
|
||||
// If not Vue SFC, treat as html
|
||||
recognizeSelfClosing = true;
|
||||
normalizeTagName = true;
|
||||
normalizeAttributeName = true;
|
||||
allowHtmComponentClosingTags = true;
|
||||
isTagNameCaseSensitive = false;
|
||||
const htmlParseResult = parser.parse(input, {
|
||||
canSelfClose: recognizeSelfClosing,
|
||||
allowHtmComponentClosingTags,
|
||||
isTagNameCaseSensitive,
|
||||
});
|
||||
|
||||
rootNodes = htmlParseResult.rootNodes;
|
||||
errors = htmlParseResult.errors;
|
||||
rootNodes = htmlParseResult.rootNodes;
|
||||
errors = htmlParseResult.errors;
|
||||
}
|
||||
}
|
||||
|
||||
if (errors.length > 0) {
|
||||
@@ -145,31 +163,16 @@ function ngHtmlParser(
|
||||
});
|
||||
}
|
||||
|
||||
const addType = (node) => {
|
||||
if (node instanceof Attribute) {
|
||||
node.type = "attribute";
|
||||
} else if (node instanceof CDATA) {
|
||||
node.type = "cdata";
|
||||
} else if (node instanceof Comment) {
|
||||
node.type = "comment";
|
||||
} else if (node instanceof DocType) {
|
||||
node.type = "docType";
|
||||
} else if (node instanceof Element) {
|
||||
node.type = "element";
|
||||
} else if (node instanceof Text) {
|
||||
node.type = "text";
|
||||
} else {
|
||||
/* istanbul ignore next */
|
||||
throw new Error(`Unexpected node ${JSON.stringify(node)}`);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* @param {Attribute | Element} node
|
||||
*/
|
||||
const restoreName = (node) => {
|
||||
const namespace = node.name.startsWith(":")
|
||||
? node.name.slice(1).split(":")[0]
|
||||
: null;
|
||||
const rawName = node.nameSpan.toString();
|
||||
const hasExplicitNamespace = rawName.startsWith(`${namespace}:`);
|
||||
const hasExplicitNamespace =
|
||||
namespace !== null && rawName.startsWith(`${namespace}:`);
|
||||
const name = hasExplicitNamespace
|
||||
? rawName.slice(namespace.length + 1)
|
||||
: rawName;
|
||||
@@ -179,8 +182,11 @@ function ngHtmlParser(
|
||||
node.hasExplicitNamespace = hasExplicitNamespace;
|
||||
};
|
||||
|
||||
/**
|
||||
* @param {AstNode} node
|
||||
*/
|
||||
const restoreNameAndValue = (node) => {
|
||||
if (node instanceof Element) {
|
||||
if (node.type === "element") {
|
||||
restoreName(node);
|
||||
for (const attr of node.attrs) {
|
||||
restoreName(attr);
|
||||
@@ -193,11 +199,11 @@ function ngHtmlParser(
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (node instanceof Comment) {
|
||||
} else if (node.type === "comment") {
|
||||
node.value = node.sourceSpan
|
||||
.toString()
|
||||
.slice("<!--".length, -"-->".length);
|
||||
} else if (node instanceof Text) {
|
||||
} else if (node.type === "text") {
|
||||
node.value = node.sourceSpan.toString();
|
||||
}
|
||||
};
|
||||
@@ -207,7 +213,7 @@ function ngHtmlParser(
|
||||
return fn(lowerCasedText) ? lowerCasedText : text;
|
||||
};
|
||||
const normalizeName = (node) => {
|
||||
if (node instanceof Element) {
|
||||
if (node.type === "element") {
|
||||
if (
|
||||
normalizeTagName &&
|
||||
(!node.namespace ||
|
||||
@@ -247,8 +253,11 @@ function ngHtmlParser(
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* @param {AstNode} node
|
||||
*/
|
||||
const addTagDefinition = (node) => {
|
||||
if (node instanceof Element) {
|
||||
if (node.type === "element") {
|
||||
const tagDefinition = getHtmlTagDefinition(
|
||||
isTagNameCaseSensitive ? node.name : node.name.toLowerCase()
|
||||
);
|
||||
@@ -267,7 +276,6 @@ function ngHtmlParser(
|
||||
visitAll(
|
||||
new (class extends RecursiveVisitor {
|
||||
visit(node) {
|
||||
addType(node);
|
||||
restoreNameAndValue(node);
|
||||
addTagDefinition(node);
|
||||
normalizeName(node);
|
||||
@@ -280,6 +288,12 @@ function ngHtmlParser(
|
||||
return rootNodes;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} text
|
||||
* @param {Options} options
|
||||
* @param {ParserOptions} parserOptions
|
||||
* @param {boolean} shouldParseFrontMatter
|
||||
*/
|
||||
function _parse(text, options, parserOptions, shouldParseFrontMatter = true) {
|
||||
const { frontMatter, content } = shouldParseFrontMatter
|
||||
? parseFrontMatter(text)
|
||||
@@ -298,6 +312,7 @@ function _parse(text, options, parserOptions, shouldParseFrontMatter = true) {
|
||||
const start = new ParseLocation(file, 0, 0, 0);
|
||||
const end = start.moveBy(frontMatter.raw.length);
|
||||
frontMatter.sourceSpan = new ParseSourceSpan(start, end);
|
||||
// @ts-ignore
|
||||
rawAst.children.unshift(frontMatter);
|
||||
}
|
||||
|
||||
@@ -346,6 +361,9 @@ function _parse(text, options, parserOptions, shouldParseFrontMatter = true) {
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {ParserOptions} parserOptions
|
||||
*/
|
||||
function createParser({
|
||||
recognizeSelfClosing = false,
|
||||
normalizeTagName = false,
|
||||
|
||||
@@ -1,6 +1,11 @@
|
||||
"use strict";
|
||||
|
||||
/**
|
||||
* @typedef {import("../document").Doc} Doc
|
||||
*/
|
||||
|
||||
const assert = require("assert");
|
||||
|
||||
const {
|
||||
builders: {
|
||||
breakParent,
|
||||
@@ -676,6 +681,7 @@ function printAttributes(path, options, print) {
|
||||
node.attrs[0].fullName === "src" &&
|
||||
node.children.length === 0;
|
||||
|
||||
/** @type {Doc[]} */
|
||||
const parts = [
|
||||
indent([
|
||||
forceNotToBreakAttrContent ? " " : line,
|
||||
@@ -992,7 +998,7 @@ function printEmbeddedAttributeValue(node, originalTextToDoc, options) {
|
||||
group([indent([softline, doc]), canHaveTrailingWhitespace ? softline : ""]);
|
||||
const printMaybeHug = (doc) => (shouldHug ? printHug(doc) : printExpand(doc));
|
||||
|
||||
const textToDoc = (code, opts) =>
|
||||
const attributeTextToDoc = (code, opts) =>
|
||||
originalTextToDoc(
|
||||
code,
|
||||
{ __onHtmlBindingRoot, __embeddedInHtml: true, ...opts },
|
||||
@@ -1017,25 +1023,21 @@ function printEmbeddedAttributeValue(node, originalTextToDoc, options) {
|
||||
const value = getValue();
|
||||
if (!value.includes("{{")) {
|
||||
return printExpand(
|
||||
textToDoc(
|
||||
value,
|
||||
{
|
||||
parser: "css",
|
||||
__isHTMLStyleAttribute: true,
|
||||
},
|
||||
{ stripTrailingHardline: true }
|
||||
)
|
||||
attributeTextToDoc(value, {
|
||||
parser: "css",
|
||||
__isHTMLStyleAttribute: true,
|
||||
})
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
if (options.parser === "vue") {
|
||||
if (node.fullName === "v-for") {
|
||||
return printVueFor(getValue(), textToDoc);
|
||||
return printVueFor(getValue(), attributeTextToDoc);
|
||||
}
|
||||
|
||||
if (isVueSlotAttribute(node) || isVueSfcBindingsAttribute(node, options)) {
|
||||
return printVueBindings(getValue(), textToDoc);
|
||||
return printVueBindings(getValue(), attributeTextToDoc);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1058,35 +1060,23 @@ function printEmbeddedAttributeValue(node, originalTextToDoc, options) {
|
||||
if (isKeyMatched(vueEventBindingPatterns)) {
|
||||
const value = getValue();
|
||||
return printMaybeHug(
|
||||
textToDoc(
|
||||
value,
|
||||
{
|
||||
parser: isVueEventBindingExpression(value)
|
||||
? "__js_expression"
|
||||
: "__vue_event_binding",
|
||||
},
|
||||
{ stripTrailingHardline: true }
|
||||
)
|
||||
attributeTextToDoc(value, {
|
||||
parser: isVueEventBindingExpression(value)
|
||||
? "__js_expression"
|
||||
: "__vue_event_binding",
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
if (isKeyMatched(vueExpressionBindingPatterns)) {
|
||||
return printMaybeHug(
|
||||
textToDoc(
|
||||
getValue(),
|
||||
{ parser: "__vue_expression" },
|
||||
{ stripTrailingHardline: true }
|
||||
)
|
||||
attributeTextToDoc(getValue(), { parser: "__vue_expression" })
|
||||
);
|
||||
}
|
||||
|
||||
if (isKeyMatched(jsExpressionBindingPatterns)) {
|
||||
return printMaybeHug(
|
||||
textToDoc(
|
||||
getValue(),
|
||||
{ parser: "__js_expression" },
|
||||
{ stripTrailingHardline: true }
|
||||
)
|
||||
attributeTextToDoc(getValue(), { parser: "__js_expression" })
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -1094,11 +1084,7 @@ function printEmbeddedAttributeValue(node, originalTextToDoc, options) {
|
||||
if (options.parser === "angular") {
|
||||
const ngTextToDoc = (code, opts) =>
|
||||
// angular does not allow trailing comma
|
||||
textToDoc(
|
||||
code,
|
||||
{ ...opts, trailingComma: "none" },
|
||||
{ stripTrailingHardline: true }
|
||||
);
|
||||
attributeTextToDoc(code, { ...opts, trailingComma: "none" });
|
||||
|
||||
/**
|
||||
* *directive="angularDirective"
|
||||
|
||||
@@ -1,5 +1,9 @@
|
||||
"use strict";
|
||||
|
||||
/**
|
||||
* @typedef {import("../common/ast-path")} AstPath
|
||||
*/
|
||||
|
||||
const htmlTagNames = require("html-tag-names");
|
||||
const htmlElementAttributes = require("html-element-attributes");
|
||||
const { inferParserByLanguage, isFrontMatterNode } = require("../common/util");
|
||||
@@ -465,6 +469,10 @@ function isPreLikeNode(node) {
|
||||
return getNodeCssStyleWhiteSpace(node).startsWith("pre");
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {AstPath} path
|
||||
* @param {(any) => boolean} predicate
|
||||
*/
|
||||
function countParents(path, predicate) {
|
||||
let counter = 0;
|
||||
for (let i = path.stack.length - 1; i >= 0; i--) {
|
||||
|
||||
@@ -163,10 +163,6 @@ function needsParens(path, options) {
|
||||
}
|
||||
|
||||
switch (node.type) {
|
||||
case "SpreadElement":
|
||||
case "SpreadProperty":
|
||||
return name === "object" && parent.type === "MemberExpression";
|
||||
|
||||
case "UpdateExpression":
|
||||
if (parent.type === "UnaryExpression") {
|
||||
return (
|
||||
@@ -237,6 +233,10 @@ function needsParens(path, options) {
|
||||
case "TSAsExpression":
|
||||
case "LogicalExpression":
|
||||
switch (parent.type) {
|
||||
case "TSAsExpression":
|
||||
// example: foo as unknown as Bar
|
||||
return node.type !== "TSAsExpression";
|
||||
|
||||
case "ConditionalExpression":
|
||||
return node.type === "TSAsExpression";
|
||||
|
||||
@@ -257,7 +257,6 @@ function needsParens(path, options) {
|
||||
case "SpreadProperty":
|
||||
case "BindExpression":
|
||||
case "AwaitExpression":
|
||||
case "TSAsExpression":
|
||||
case "TSNonNullExpression":
|
||||
case "UpdateExpression":
|
||||
return true;
|
||||
@@ -267,6 +266,7 @@ function needsParens(path, options) {
|
||||
return name === "object";
|
||||
|
||||
case "AssignmentExpression":
|
||||
case "AssignmentPattern":
|
||||
return (
|
||||
name === "left" &&
|
||||
(node.type === "TSTypeAssertion" || node.type === "TSAsExpression")
|
||||
|
||||
@@ -150,11 +150,6 @@ const allowedMessages = new Set([
|
||||
"'with' in strict mode",
|
||||
"Legacy octal literals are not allowed in strict mode",
|
||||
|
||||
"Invalid left-hand side in parenthesized expression",
|
||||
"Invalid left-hand side in assignment expression",
|
||||
"Invalid left-hand side in postfix operation",
|
||||
"Invalid left-hand side in prefix operation",
|
||||
|
||||
"Type argument list cannot be empty.",
|
||||
"Type parameter list cannot be empty.",
|
||||
"Type parameters cannot appear on a constructor declaration.",
|
||||
@@ -185,7 +180,6 @@ const allowedMessages = new Set([
|
||||
"Unexpected trailing comma after rest element",
|
||||
"Decorators cannot be used to decorate parameters",
|
||||
"Unterminated JSX contents",
|
||||
"Invalid parenthesized assignment pattern",
|
||||
'Unexpected token, expected "}"',
|
||||
"Unexpected token :",
|
||||
"Unexpected reserved word 'package'",
|
||||
|
||||
@@ -9,13 +9,17 @@ const {
|
||||
hasLeadingOwnLineComment,
|
||||
isBinaryish,
|
||||
isStringLiteral,
|
||||
isLiteral,
|
||||
isNumericLiteral,
|
||||
isCallExpression,
|
||||
isMemberExpression,
|
||||
getCallArguments,
|
||||
isSimpleCallArgument,
|
||||
rawText,
|
||||
hasComment,
|
||||
isSignedNumericLiteral,
|
||||
} = require("../utils");
|
||||
const { shouldInlineLogicalExpression } = require("./binaryish");
|
||||
const { printCallExpression } = require("./call-expression");
|
||||
|
||||
function printAssignment(
|
||||
path,
|
||||
@@ -25,7 +29,7 @@ function printAssignment(
|
||||
operator,
|
||||
rightPropertyName
|
||||
) {
|
||||
const layout = chooseLayout(path, options, leftDoc, rightPropertyName);
|
||||
const layout = chooseLayout(path, options, print, leftDoc, rightPropertyName);
|
||||
|
||||
const rightDoc = print(rightPropertyName, { assignmentLayout: layout });
|
||||
|
||||
@@ -49,6 +53,9 @@ function printAssignment(
|
||||
]);
|
||||
}
|
||||
|
||||
case "break-lhs":
|
||||
return group([leftDoc, operator, " ", group(rightDoc)]);
|
||||
|
||||
// Parts of assignment chains aren't wrapped in groups.
|
||||
// Once one of them breaks, the chain breaks too.
|
||||
case "chain":
|
||||
@@ -81,7 +88,7 @@ function printVariableDeclarator(path, options, print) {
|
||||
return printAssignment(path, options, print, print("id"), " =", "init");
|
||||
}
|
||||
|
||||
function chooseLayout(path, options, leftDoc, rightPropertyName) {
|
||||
function chooseLayout(path, options, print, leftDoc, rightPropertyName) {
|
||||
const node = path.getValue();
|
||||
const rightNode = node[rightPropertyName];
|
||||
|
||||
@@ -96,7 +103,7 @@ function chooseLayout(path, options, leftDoc, rightPropertyName) {
|
||||
const isTail = !isAssignment(rightNode);
|
||||
const shouldUseChainFormatting = path.match(
|
||||
isAssignment,
|
||||
(node) => isAssignment(node) || node.type === "VariableDeclarator",
|
||||
isAssignmentOrVariableDeclarator,
|
||||
(node) =>
|
||||
!isTail ||
|
||||
(node.type !== "ExpressionStatement" &&
|
||||
@@ -119,26 +126,49 @@ function chooseLayout(path, options, leftDoc, rightPropertyName) {
|
||||
return "break-after-operator";
|
||||
}
|
||||
|
||||
// do not put values on a separate line from the key in json
|
||||
if (options.parser === "json5" || options.parser === "json") {
|
||||
if (
|
||||
(rightNode.type === "CallExpression" &&
|
||||
rightNode.callee.name === "require") ||
|
||||
// do not put values on a separate line from the key in json
|
||||
options.parser === "json5" ||
|
||||
options.parser === "json"
|
||||
) {
|
||||
return "never-break-after-operator";
|
||||
}
|
||||
|
||||
if (isComplexDestructuring(node)) {
|
||||
return "break-lhs";
|
||||
}
|
||||
|
||||
// wrapping object properties with very short keys usually doesn't add much value
|
||||
const hasShortKey = isObjectPropertyWithShortKey(node, leftDoc, options);
|
||||
|
||||
if (shouldBreakAfterOperator(rightNode, hasShortKey)) {
|
||||
if (
|
||||
path.call(
|
||||
() => shouldBreakAfterOperator(path, options, print, hasShortKey),
|
||||
rightPropertyName
|
||||
)
|
||||
) {
|
||||
return "break-after-operator";
|
||||
}
|
||||
|
||||
if (hasShortKey || shouldNeverBreakAfterOperator(rightNode)) {
|
||||
if (
|
||||
hasShortKey ||
|
||||
rightNode.type === "TemplateLiteral" ||
|
||||
rightNode.type === "TaggedTemplateExpression" ||
|
||||
rightNode.type === "BooleanLiteral" ||
|
||||
isNumericLiteral(rightNode) ||
|
||||
rightNode.type === "ClassExpression"
|
||||
) {
|
||||
return "never-break-after-operator";
|
||||
}
|
||||
|
||||
return "fluid";
|
||||
}
|
||||
|
||||
function shouldBreakAfterOperator(rightNode, hasShortKey) {
|
||||
function shouldBreakAfterOperator(path, options, print, hasShortKey) {
|
||||
const rightNode = path.getValue();
|
||||
|
||||
if (isBinaryish(rightNode) && !shouldInlineLogicalExpression(rightNode)) {
|
||||
return true;
|
||||
}
|
||||
@@ -160,22 +190,24 @@ function shouldBreakAfterOperator(rightNode, hasShortKey) {
|
||||
}
|
||||
|
||||
let node = rightNode;
|
||||
const propertiesForPath = [];
|
||||
for (;;) {
|
||||
if (node.type === "UnaryExpression") {
|
||||
node = node.argument;
|
||||
propertiesForPath.push("argument");
|
||||
} else if (node.type === "TSNonNullExpression") {
|
||||
node = node.expression;
|
||||
propertiesForPath.push("expression");
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (
|
||||
isStringLiteral(node) ||
|
||||
isMemberExpressionChainWithSimpleCalls(node) ||
|
||||
(isSimpleCall(node) &&
|
||||
isSimpleCall(node.callee) &&
|
||||
(isMemberExpressionChainHead(node.callee.callee) ||
|
||||
isMemberExpressionChainWithSimpleCalls(node.callee.callee)))
|
||||
path.call(
|
||||
() => isPoorlyBreakableMemberOrCallChain(path, options, print),
|
||||
...propertiesForPath
|
||||
)
|
||||
) {
|
||||
return true;
|
||||
}
|
||||
@@ -183,57 +215,115 @@ function shouldBreakAfterOperator(rightNode, hasShortKey) {
|
||||
return false;
|
||||
}
|
||||
|
||||
function shouldNeverBreakAfterOperator(rightNode) {
|
||||
return (
|
||||
rightNode.type === "TemplateLiteral" ||
|
||||
rightNode.type === "TaggedTemplateExpression" ||
|
||||
rightNode.type === "BooleanLiteral" ||
|
||||
isNumericLiteral(rightNode) ||
|
||||
(rightNode.type === "CallExpression" &&
|
||||
rightNode.callee.name === "require") ||
|
||||
rightNode.type === "ClassExpression"
|
||||
);
|
||||
// prefer to break destructuring assignment
|
||||
// if it includes default values or non-shorthand properties
|
||||
function isComplexDestructuring(node) {
|
||||
if (isAssignmentOrVariableDeclarator(node)) {
|
||||
const leftNode = node.left || node.id;
|
||||
return (
|
||||
leftNode.type === "ObjectPattern" &&
|
||||
leftNode.properties.length > 2 &&
|
||||
leftNode.properties.some(
|
||||
(property) =>
|
||||
(property.type === "ObjectProperty" ||
|
||||
property.type === "Property") &&
|
||||
(!property.shorthand ||
|
||||
(property.value && property.value.type === "AssignmentPattern"))
|
||||
)
|
||||
);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
function isAssignment(node) {
|
||||
return node.type === "AssignmentExpression";
|
||||
}
|
||||
|
||||
function isMemberExpressionChainHead(node) {
|
||||
return node.type === "Identifier" || node.type === "ThisExpression";
|
||||
function isAssignmentOrVariableDeclarator(node) {
|
||||
return isAssignment(node) || node.type === "VariableDeclarator";
|
||||
}
|
||||
|
||||
function isMemberExpressionChainWithSimpleCalls(node) {
|
||||
if (!isMemberExpression(node)) {
|
||||
return false;
|
||||
/**
|
||||
* A chain with no calls at all or whose calls are all without arguments or with lone short arguments,
|
||||
* excluding chains printed by `printMemberChain`
|
||||
*/
|
||||
function isPoorlyBreakableMemberOrCallChain(
|
||||
path,
|
||||
options,
|
||||
print,
|
||||
deep = false
|
||||
) {
|
||||
const node = path.getValue();
|
||||
const goDeeper = () =>
|
||||
isPoorlyBreakableMemberOrCallChain(path, options, print, true);
|
||||
|
||||
if (node.type === "TSNonNullExpression") {
|
||||
return path.call(goDeeper, "expression");
|
||||
}
|
||||
let { object } = node;
|
||||
for (;;) {
|
||||
if (object.type === "TSNonNullExpression") {
|
||||
object = object.expression;
|
||||
} else if (isCallExpression(object)) {
|
||||
if (!isSimpleCall(object)) {
|
||||
return false;
|
||||
}
|
||||
object = object.callee;
|
||||
} else {
|
||||
break;
|
||||
|
||||
if (isCallExpression(node)) {
|
||||
/** @type {any} TODO */
|
||||
const doc = printCallExpression(path, options, print);
|
||||
if (doc.label === "member-chain") {
|
||||
return false;
|
||||
}
|
||||
|
||||
const args = getCallArguments(node);
|
||||
const isPoorlyBreakableCall =
|
||||
args.length === 0 ||
|
||||
(args.length === 1 && isLoneShortArgument(args[0], options));
|
||||
if (!isPoorlyBreakableCall) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return path.call(goDeeper, "callee");
|
||||
}
|
||||
return (
|
||||
isMemberExpressionChainHead(object) ||
|
||||
isMemberExpressionChainWithSimpleCalls(object)
|
||||
);
|
||||
|
||||
if (isMemberExpression(node)) {
|
||||
return path.call(goDeeper, "object");
|
||||
}
|
||||
|
||||
return deep && (node.type === "Identifier" || node.type === "ThisExpression");
|
||||
}
|
||||
|
||||
function isSimpleCall(node) {
|
||||
if (!isCallExpression(node)) {
|
||||
const LONE_SHORT_ARGUMENT_THRESHOLD_RATE = 0.25;
|
||||
|
||||
function isLoneShortArgument(node, { printWidth }) {
|
||||
if (hasComment(node)) {
|
||||
return false;
|
||||
}
|
||||
const args = getCallArguments(node);
|
||||
return (
|
||||
args.length === 0 || (args.length === 1 && isSimpleCallArgument(args[0], 1))
|
||||
);
|
||||
|
||||
const threshold = printWidth * LONE_SHORT_ARGUMENT_THRESHOLD_RATE;
|
||||
|
||||
if (
|
||||
node.type === "ThisExpression" ||
|
||||
(node.type === "Identifier" && node.name.length <= threshold) ||
|
||||
(isSignedNumericLiteral(node) && !hasComment(node.argument))
|
||||
) {
|
||||
return true;
|
||||
}
|
||||
|
||||
const regexpPattern =
|
||||
(node.type === "Literal" && "regex" in node && node.regex.pattern) ||
|
||||
(node.type === "RegExpLiteral" && node.pattern);
|
||||
|
||||
if (regexpPattern) {
|
||||
return regexpPattern.length <= threshold;
|
||||
}
|
||||
|
||||
if (isStringLiteral(node)) {
|
||||
return rawText(node).length <= threshold;
|
||||
}
|
||||
|
||||
if (node.type === "TemplateLiteral") {
|
||||
return (
|
||||
node.expressions.length === 0 &&
|
||||
node.quasis[0].value.raw.length <= threshold &&
|
||||
!node.quasis[0].value.raw.includes("\n")
|
||||
);
|
||||
}
|
||||
|
||||
return isLiteral(node);
|
||||
}
|
||||
|
||||
function isObjectPropertyWithShortKey(node, keyDoc, options) {
|
||||
|
||||
@@ -4,7 +4,6 @@ const { printDanglingComments } = require("../../main/comments");
|
||||
const { getLast, getPenultimate } = require("../../common/util");
|
||||
const {
|
||||
getFunctionParameters,
|
||||
iterateFunctionParametersPath,
|
||||
hasComment,
|
||||
CommentCheckFlags,
|
||||
isFunctionCompositionArgs,
|
||||
@@ -31,6 +30,7 @@ const {
|
||||
utils: { willBreak },
|
||||
} = require("../../document");
|
||||
|
||||
const { ArgExpansionBailout } = require("../../common/errors");
|
||||
const { isConciselyPrintedArray } = require("./array");
|
||||
|
||||
function printCallArguments(path, options, print) {
|
||||
@@ -51,34 +51,7 @@ function printCallArguments(path, options, print) {
|
||||
return ["(", print(["arguments", 0]), ", ", print(["arguments", 1]), ")"];
|
||||
}
|
||||
|
||||
// func(
|
||||
// ({
|
||||
// a,
|
||||
//
|
||||
// b
|
||||
// }) => {}
|
||||
// );
|
||||
function shouldBreakForArrowFunctionInArguments(arg, argPath) {
|
||||
if (
|
||||
!arg ||
|
||||
arg.type !== "ArrowFunctionExpression" ||
|
||||
!arg.body ||
|
||||
arg.body.type !== "BlockStatement" ||
|
||||
getFunctionParameters(arg).length === 0
|
||||
) {
|
||||
return false;
|
||||
}
|
||||
|
||||
let shouldBreak = false;
|
||||
iterateFunctionParametersPath(argPath, () => {
|
||||
shouldBreak = shouldBreak || willBreak(print());
|
||||
});
|
||||
|
||||
return shouldBreak;
|
||||
}
|
||||
|
||||
let anyArgEmptyLine = false;
|
||||
let shouldBreakForArrowFunction = false;
|
||||
let hasEmptyLineFollowingFirstArg = false;
|
||||
const lastArgIndex = args.length - 1;
|
||||
const printedArguments = [];
|
||||
@@ -99,11 +72,6 @@ function printCallArguments(path, options, print) {
|
||||
parts.push(",", line);
|
||||
}
|
||||
|
||||
shouldBreakForArrowFunction = shouldBreakForArrowFunctionInArguments(
|
||||
arg,
|
||||
argPath
|
||||
);
|
||||
|
||||
printedArguments.push(parts);
|
||||
});
|
||||
|
||||
@@ -122,8 +90,9 @@ function printCallArguments(path, options, print) {
|
||||
}
|
||||
|
||||
if (
|
||||
path.getParentNode().type !== "Decorator" &&
|
||||
isFunctionCompositionArgs(args)
|
||||
anyArgEmptyLine ||
|
||||
(path.getParentNode().type !== "Decorator" &&
|
||||
isFunctionCompositionArgs(args))
|
||||
) {
|
||||
return allArgsBrokenOut();
|
||||
}
|
||||
@@ -131,67 +100,66 @@ function printCallArguments(path, options, print) {
|
||||
const shouldGroupFirst = shouldGroupFirstArg(args);
|
||||
const shouldGroupLast = shouldGroupLastArg(args, options);
|
||||
if (shouldGroupFirst || shouldGroupLast) {
|
||||
const shouldBreak =
|
||||
(shouldGroupFirst
|
||||
if (
|
||||
shouldGroupFirst
|
||||
? printedArguments.slice(1).some(willBreak)
|
||||
: printedArguments.slice(0, -1).some(willBreak)) ||
|
||||
anyArgEmptyLine ||
|
||||
shouldBreakForArrowFunction;
|
||||
: printedArguments.slice(0, -1).some(willBreak)
|
||||
) {
|
||||
return allArgsBrokenOut();
|
||||
}
|
||||
|
||||
// We want to print the last argument with a special flag
|
||||
let printedExpanded = [];
|
||||
iterateCallArgumentsPath(path, (argPath, i) => {
|
||||
if (shouldGroupFirst && i === 0) {
|
||||
printedExpanded = [
|
||||
[
|
||||
print([], { expandFirstArg: true }),
|
||||
printedArguments.length > 1 ? "," : "",
|
||||
hasEmptyLineFollowingFirstArg ? hardline : line,
|
||||
hasEmptyLineFollowingFirstArg ? hardline : "",
|
||||
],
|
||||
...printedArguments.slice(1),
|
||||
];
|
||||
}
|
||||
if (shouldGroupLast && i === args.length - 1) {
|
||||
printedExpanded = [
|
||||
...printedArguments.slice(0, -1),
|
||||
print([], { expandLastArg: true }),
|
||||
];
|
||||
}
|
||||
});
|
||||
|
||||
const somePrintedArgumentsWillBreak = printedArguments.some(willBreak);
|
||||
|
||||
const simpleConcat = ["(", ...printedExpanded, ")"];
|
||||
try {
|
||||
path.try(() => {
|
||||
iterateCallArgumentsPath(path, (argPath, i) => {
|
||||
if (shouldGroupFirst && i === 0) {
|
||||
printedExpanded = [
|
||||
[
|
||||
print([], { expandFirstArg: true }),
|
||||
printedArguments.length > 1 ? "," : "",
|
||||
hasEmptyLineFollowingFirstArg ? hardline : line,
|
||||
hasEmptyLineFollowingFirstArg ? hardline : "",
|
||||
],
|
||||
...printedArguments.slice(1),
|
||||
];
|
||||
}
|
||||
if (shouldGroupLast && i === lastArgIndex) {
|
||||
printedExpanded = [
|
||||
...printedArguments.slice(0, -1),
|
||||
print([], { expandLastArg: true }),
|
||||
];
|
||||
}
|
||||
});
|
||||
});
|
||||
} catch (caught) {
|
||||
if (caught instanceof ArgExpansionBailout) {
|
||||
return allArgsBrokenOut();
|
||||
}
|
||||
/* istanbul ignore next */
|
||||
throw caught;
|
||||
}
|
||||
|
||||
return [
|
||||
somePrintedArgumentsWillBreak ? breakParent : "",
|
||||
conditionalGroup(
|
||||
[
|
||||
!somePrintedArgumentsWillBreak &&
|
||||
!node.typeArguments &&
|
||||
!node.typeParameters
|
||||
? simpleConcat
|
||||
: ifBreak(allArgsBrokenOut(), simpleConcat),
|
||||
shouldGroupFirst
|
||||
? [
|
||||
"(",
|
||||
group(printedExpanded[0], { shouldBreak: true }),
|
||||
...printedExpanded.slice(1),
|
||||
")",
|
||||
]
|
||||
: [
|
||||
"(",
|
||||
...printedArguments.slice(0, -1),
|
||||
group(getLast(printedExpanded), {
|
||||
shouldBreak: true,
|
||||
}),
|
||||
")",
|
||||
],
|
||||
allArgsBrokenOut(),
|
||||
],
|
||||
{ shouldBreak }
|
||||
),
|
||||
printedArguments.some(willBreak) ? breakParent : "",
|
||||
conditionalGroup([
|
||||
["(", ...printedExpanded, ")"],
|
||||
shouldGroupFirst
|
||||
? [
|
||||
"(",
|
||||
group(printedExpanded[0], { shouldBreak: true }),
|
||||
...printedExpanded.slice(1),
|
||||
")",
|
||||
]
|
||||
: [
|
||||
"(",
|
||||
...printedArguments.slice(0, -1),
|
||||
group(getLast(printedExpanded), { shouldBreak: true }),
|
||||
")",
|
||||
],
|
||||
allArgsBrokenOut(),
|
||||
]),
|
||||
];
|
||||
}
|
||||
|
||||
@@ -247,7 +215,9 @@ function couldGroupArg(arg, arrowChainRecursion = false) {
|
||||
(!arrowChainRecursion &&
|
||||
(isCallExpression(arg.body) ||
|
||||
arg.body.type === "ConditionalExpression")) ||
|
||||
isJsxNode(arg.body)))
|
||||
isJsxNode(arg.body))) ||
|
||||
arg.type === "DoExpression" ||
|
||||
arg.type === "ModuleExpression"
|
||||
);
|
||||
}
|
||||
|
||||
@@ -279,6 +249,14 @@ function shouldGroupFirstArg(args) {
|
||||
}
|
||||
|
||||
const [firstArg, secondArg] = args;
|
||||
|
||||
if (
|
||||
firstArg.type === "ModuleExpression" &&
|
||||
isTypeModuleObjectExpression(secondArg)
|
||||
) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return (
|
||||
!hasComment(firstArg) &&
|
||||
(firstArg.type === "FunctionExpression" ||
|
||||
@@ -310,4 +288,17 @@ function isNonEmptyBlockStatement(node) {
|
||||
);
|
||||
}
|
||||
|
||||
// { type: "module" }
|
||||
function isTypeModuleObjectExpression(node) {
|
||||
return (
|
||||
node.type === "ObjectExpression" &&
|
||||
node.properties.length === 1 &&
|
||||
node.properties[0].type === "ObjectProperty" &&
|
||||
node.properties[0].key.type === "Identifier" &&
|
||||
node.properties[0].key.name === "type" &&
|
||||
node.properties[0].value.type === "StringLiteral" &&
|
||||
node.properties[0].value.value === "module"
|
||||
);
|
||||
}
|
||||
|
||||
module.exports = printCallArguments;
|
||||
@@ -20,6 +20,7 @@ const {
|
||||
isNextLineEmpty,
|
||||
} = require("../utils");
|
||||
const { locEnd } = require("../loc");
|
||||
const { ArgExpansionBailout } = require("../../common/errors");
|
||||
const { printFunctionTypeParameters } = require("./misc");
|
||||
|
||||
function printFunctionParameters(
|
||||
@@ -57,8 +58,6 @@ function printFunctionParameters(
|
||||
const parent = path.getParentNode();
|
||||
const isParametersInTestCall = isTestCall(parent);
|
||||
const shouldHugParameters = shouldHugFunctionParameters(functionNode);
|
||||
const shouldExpandParameters =
|
||||
expandArg && !parameters.some((node) => hasComment(node));
|
||||
const printed = [];
|
||||
iterateFunctionParametersPath(path, (parameterPath, index) => {
|
||||
const isLastParameter = index === parameters.length - 1;
|
||||
@@ -70,11 +69,7 @@ function printFunctionParameters(
|
||||
return;
|
||||
}
|
||||
printed.push(",");
|
||||
if (
|
||||
isParametersInTestCall ||
|
||||
shouldHugParameters ||
|
||||
shouldExpandParameters
|
||||
) {
|
||||
if (isParametersInTestCall || shouldHugParameters) {
|
||||
printed.push(" ");
|
||||
} else if (isNextLineEmpty(parameters[index], options)) {
|
||||
printed.push(hardline, hardline);
|
||||
@@ -91,15 +86,14 @@ function printFunctionParameters(
|
||||
// verylongcall( verylongcall((
|
||||
// (a, b) => { a,
|
||||
// } b,
|
||||
// }) ) => {
|
||||
// ) ) => {
|
||||
// })
|
||||
if (shouldExpandParameters) {
|
||||
return group([
|
||||
removeLines(typeParams),
|
||||
"(",
|
||||
...printed.map(removeLines),
|
||||
")",
|
||||
]);
|
||||
if (expandArg) {
|
||||
if (willBreak(typeParams) || willBreak(printed)) {
|
||||
// Removing lines in this case leads to broken or ugly output
|
||||
throw new ArgExpansionBailout();
|
||||
}
|
||||
return group([removeLines(typeParams), "(", removeLines(printed), ")"]);
|
||||
}
|
||||
|
||||
// Single object destructuring should hug
|
||||
|
||||
@@ -1,9 +1,13 @@
|
||||
"use strict";
|
||||
|
||||
const {
|
||||
builders: { softline, group, indent },
|
||||
builders: { softline, group, indent, label },
|
||||
} = require("../../document");
|
||||
const { isNumericLiteral, isMemberExpression } = require("../utils");
|
||||
const {
|
||||
isNumericLiteral,
|
||||
isMemberExpression,
|
||||
isCallExpression,
|
||||
} = require("../utils");
|
||||
const { printOptionalToken } = require("./misc");
|
||||
|
||||
function printMemberExpression(path, options, print) {
|
||||
@@ -21,6 +25,9 @@ function printMemberExpression(path, options, print) {
|
||||
firstNonMemberParent.type === "TSNonNullExpression")
|
||||
);
|
||||
|
||||
const objectDoc = print("object");
|
||||
const lookupDoc = printMemberLookup(path, options, print);
|
||||
|
||||
const shouldInline =
|
||||
(firstNonMemberParent &&
|
||||
(firstNonMemberParent.type === "NewExpression" ||
|
||||
@@ -30,14 +37,19 @@ function printMemberExpression(path, options, print) {
|
||||
node.computed ||
|
||||
(node.object.type === "Identifier" &&
|
||||
node.property.type === "Identifier" &&
|
||||
!isMemberExpression(parent));
|
||||
!isMemberExpression(parent)) ||
|
||||
((parent.type === "AssignmentExpression" ||
|
||||
parent.type === "VariableDeclarator") &&
|
||||
((isCallExpression(node.object) && node.object.arguments.length > 0) ||
|
||||
(node.object.type === "TSNonNullExpression" &&
|
||||
isCallExpression(node.object.expression) &&
|
||||
node.object.expression.arguments.length > 0) ||
|
||||
objectDoc.label === "member-chain"));
|
||||
|
||||
return [
|
||||
print("object"),
|
||||
shouldInline
|
||||
? printMemberLookup(path, options, print)
|
||||
: group(indent([softline, printMemberLookup(path, options, print)])),
|
||||
];
|
||||
return label(objectDoc.label === "member-chain" ? "member-chain" : "member", [
|
||||
objectDoc,
|
||||
shouldInline ? lookupDoc : group(indent([softline, lookupDoc])),
|
||||
]);
|
||||
}
|
||||
|
||||
function printMemberLookup(path, options, print) {
|
||||
|
||||
@@ -41,11 +41,10 @@ function printObject(path, options, print) {
|
||||
}
|
||||
|
||||
const isTypeAnnotation = node.type === "ObjectTypeAnnotation";
|
||||
const fields = [];
|
||||
const fields = [propertiesField];
|
||||
if (isTypeAnnotation) {
|
||||
fields.push("indexers", "callProperties", "internalSlots");
|
||||
}
|
||||
fields.push(propertiesField);
|
||||
|
||||
const firstProperty = fields
|
||||
.map((field) => node[field][0])
|
||||
@@ -109,26 +108,28 @@ function printObject(path, options, print) {
|
||||
}, field);
|
||||
}
|
||||
|
||||
if (fields.length > 1) {
|
||||
propsAndLoc.sort((a, b) => a.loc - b.loc);
|
||||
}
|
||||
|
||||
/** @type {Doc[]} */
|
||||
let separatorParts = [];
|
||||
const props = propsAndLoc
|
||||
.sort((a, b) => a.loc - b.loc)
|
||||
.map((prop) => {
|
||||
const result = [...separatorParts, group(prop.printed)];
|
||||
separatorParts = [separator, line];
|
||||
if (
|
||||
(prop.node.type === "TSPropertySignature" ||
|
||||
prop.node.type === "TSMethodSignature" ||
|
||||
prop.node.type === "TSConstructSignatureDeclaration") &&
|
||||
hasComment(prop.node, CommentCheckFlags.PrettierIgnore)
|
||||
) {
|
||||
separatorParts.shift();
|
||||
}
|
||||
if (isNextLineEmpty(prop.node, options)) {
|
||||
separatorParts.push(hardline);
|
||||
}
|
||||
return result;
|
||||
});
|
||||
const props = propsAndLoc.map((prop) => {
|
||||
const result = [...separatorParts, group(prop.printed)];
|
||||
separatorParts = [separator, line];
|
||||
if (
|
||||
(prop.node.type === "TSPropertySignature" ||
|
||||
prop.node.type === "TSMethodSignature" ||
|
||||
prop.node.type === "TSConstructSignatureDeclaration") &&
|
||||
hasComment(prop.node, CommentCheckFlags.PrettierIgnore)
|
||||
) {
|
||||
separatorParts.shift();
|
||||
}
|
||||
if (isNextLineEmpty(prop.node, options)) {
|
||||
separatorParts.push(hardline);
|
||||
}
|
||||
return result;
|
||||
});
|
||||
|
||||
if (node.inexact) {
|
||||
let printed;
|
||||
@@ -225,7 +226,16 @@ function printObject(path, options, print) {
|
||||
name === "this" ||
|
||||
name === "rest") &&
|
||||
number === 0
|
||||
)
|
||||
) ||
|
||||
// Assignment printing logic (printAssignment) is responsible
|
||||
// for adding a group if needed
|
||||
(!shouldBreak &&
|
||||
path.match(
|
||||
(node) => node.type === "ObjectPattern",
|
||||
(node) =>
|
||||
node.type === "AssignmentExpression" ||
|
||||
node.type === "VariableDeclarator"
|
||||
))
|
||||
) {
|
||||
return content;
|
||||
}
|
||||
|
||||
@@ -93,14 +93,16 @@ function printPrettierIgnoredNode(node, options) {
|
||||
|
||||
const start = locStart(node);
|
||||
const end = locEnd(node);
|
||||
const printedComments = new Set();
|
||||
|
||||
for (const comment of comments) {
|
||||
if (locStart(comment) >= start && locEnd(comment) <= end) {
|
||||
comment.printed = true;
|
||||
printedComments.add(comment);
|
||||
}
|
||||
}
|
||||
|
||||
return originalText.slice(start, end);
|
||||
return { doc: originalText.slice(start, end), printedComments };
|
||||
}
|
||||
|
||||
function callPluginPrintFunction(path, options, printPath, args) {
|
||||
@@ -108,10 +110,11 @@ function callPluginPrintFunction(path, options, printPath, args) {
|
||||
const { printer } = options;
|
||||
|
||||
let doc;
|
||||
let printedComments;
|
||||
|
||||
// Escape hatch
|
||||
if (printer.hasPrettierIgnore && printer.hasPrettierIgnore(path)) {
|
||||
doc = printPrettierIgnoredNode(node, options);
|
||||
({ doc, printedComments } = printPrettierIgnoredNode(node, options));
|
||||
} else {
|
||||
if (node) {
|
||||
try {
|
||||
@@ -139,7 +142,7 @@ function callPluginPrintFunction(path, options, printPath, args) {
|
||||
) {
|
||||
// printComments will call the plugin print function and check for
|
||||
// comments to print
|
||||
doc = printComments(path, doc, options);
|
||||
doc = printComments(path, doc, options, printedComments);
|
||||
}
|
||||
|
||||
return doc;
|
||||
|
||||
+56
-62
@@ -15,7 +15,6 @@ const {
|
||||
addLeadingComment,
|
||||
addDanglingComment,
|
||||
addTrailingComment,
|
||||
isNonEmptyArray,
|
||||
} = require("../common/util");
|
||||
|
||||
const childNodesCache = new WeakMap();
|
||||
@@ -420,10 +419,10 @@ function breakTies(tiesToBreak, text, options) {
|
||||
tiesToBreak.length = 0;
|
||||
}
|
||||
|
||||
function printComment(commentPath, options) {
|
||||
const comment = commentPath.getValue();
|
||||
function printComment(path, options) {
|
||||
const comment = path.getValue();
|
||||
comment.printed = true;
|
||||
return options.printer.printComment(commentPath, options);
|
||||
return options.printer.printComment(path, options);
|
||||
}
|
||||
|
||||
function findExpressionIndexForComment(quasis, comment, options) {
|
||||
@@ -441,40 +440,45 @@ function findExpressionIndexForComment(quasis, comment, options) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
function printLeadingComment(commentPath, options) {
|
||||
const comment = commentPath.getValue();
|
||||
const contents = printComment(commentPath, options);
|
||||
/* istanbul ignore next */
|
||||
if (!contents) {
|
||||
return "";
|
||||
}
|
||||
const isBlock =
|
||||
options.printer.isBlockComment && options.printer.isBlockComment(comment);
|
||||
function printLeadingComment(path, options) {
|
||||
const comment = path.getValue();
|
||||
const parts = [printComment(path, options)];
|
||||
|
||||
const { printer, originalText, locStart, locEnd } = options;
|
||||
const isBlock = printer.isBlockComment && printer.isBlockComment(comment);
|
||||
|
||||
// Leading block comments should see if they need to stay on the
|
||||
// same line or not.
|
||||
if (isBlock) {
|
||||
const lineBreak = hasNewline(options.originalText, options.locEnd(comment))
|
||||
? hasNewline(options.originalText, options.locStart(comment), {
|
||||
const lineBreak = hasNewline(originalText, locEnd(comment))
|
||||
? hasNewline(originalText, locStart(comment), {
|
||||
backwards: true,
|
||||
})
|
||||
? hardline
|
||||
: line
|
||||
: " ";
|
||||
|
||||
return [contents, lineBreak];
|
||||
parts.push(lineBreak);
|
||||
} else {
|
||||
parts.push(hardline);
|
||||
}
|
||||
|
||||
return [contents, hardline];
|
||||
const index = skipNewline(
|
||||
originalText,
|
||||
skipSpaces(originalText, locEnd(comment))
|
||||
);
|
||||
|
||||
if (index !== false && hasNewline(originalText, index)) {
|
||||
parts.push(hardline);
|
||||
}
|
||||
|
||||
return parts;
|
||||
}
|
||||
|
||||
function printTrailingComment(commentPath, options) {
|
||||
const comment = commentPath.getValue();
|
||||
const contents = printComment(commentPath, options);
|
||||
/* istanbul ignore next */
|
||||
if (!contents) {
|
||||
return "";
|
||||
}
|
||||
function printTrailingComment(path, options) {
|
||||
const comment = path.getValue();
|
||||
const printed = printComment(path, options);
|
||||
|
||||
const { printer, originalText, locStart } = options;
|
||||
const isBlock = printer.isBlockComment && printer.isBlockComment(comment);
|
||||
|
||||
@@ -497,17 +501,17 @@ function printTrailingComment(commentPath, options) {
|
||||
locStart
|
||||
);
|
||||
|
||||
return lineSuffix([hardline, isLineBeforeEmpty ? hardline : "", contents]);
|
||||
return lineSuffix([hardline, isLineBeforeEmpty ? hardline : "", printed]);
|
||||
}
|
||||
|
||||
let printed = [" ", contents];
|
||||
let parts = [" ", printed];
|
||||
|
||||
// Trailing block comments never need a newline
|
||||
if (!isBlock) {
|
||||
printed = [lineSuffix(printed), breakParent];
|
||||
parts = [lineSuffix(parts), breakParent];
|
||||
}
|
||||
|
||||
return printed;
|
||||
return parts;
|
||||
}
|
||||
|
||||
function printDanglingComments(path, options, sameIndent, filter) {
|
||||
@@ -518,15 +522,10 @@ function printDanglingComments(path, options, sameIndent, filter) {
|
||||
return "";
|
||||
}
|
||||
|
||||
path.each((commentPath) => {
|
||||
const comment = commentPath.getValue();
|
||||
if (
|
||||
comment &&
|
||||
!comment.leading &&
|
||||
!comment.trailing &&
|
||||
(!filter || filter(comment))
|
||||
) {
|
||||
parts.push(printComment(commentPath, options));
|
||||
path.each(() => {
|
||||
const comment = path.getValue();
|
||||
if (!comment.leading && !comment.trailing && (!filter || filter(comment))) {
|
||||
parts.push(printComment(path, options));
|
||||
}
|
||||
}, "comments");
|
||||
|
||||
@@ -540,41 +539,36 @@ function printDanglingComments(path, options, sameIndent, filter) {
|
||||
return indent([hardline, join(hardline, parts)]);
|
||||
}
|
||||
|
||||
function printCommentsSeparately(path, options) {
|
||||
function printCommentsSeparately(path, options, ignored) {
|
||||
const value = path.getValue();
|
||||
const hasComments = isNonEmptyArray(value && value.comments);
|
||||
const isCursorNode = Boolean(value && value === options.cursorNode);
|
||||
if (!value) {
|
||||
return {};
|
||||
}
|
||||
|
||||
if (!hasComments) {
|
||||
let comments = value.comments || [];
|
||||
if (ignored) {
|
||||
comments = comments.filter((comment) => !ignored.has(comment));
|
||||
}
|
||||
const isCursorNode = value === options.cursorNode;
|
||||
|
||||
if (comments.length === 0) {
|
||||
const maybeCursor = isCursorNode ? cursor : "";
|
||||
return { leading: maybeCursor, trailing: maybeCursor };
|
||||
}
|
||||
|
||||
const leadingParts = [];
|
||||
const trailingParts = [];
|
||||
path.each(() => {
|
||||
const comment = path.getValue();
|
||||
if (ignored && ignored.has(comment)) {
|
||||
return;
|
||||
}
|
||||
|
||||
path.each((commentPath) => {
|
||||
const comment = commentPath.getValue();
|
||||
const { leading, trailing } = comment;
|
||||
|
||||
if (leading) {
|
||||
const contents = printLeadingComment(commentPath, options);
|
||||
/* istanbul ignore next */
|
||||
if (!contents) {
|
||||
return;
|
||||
}
|
||||
leadingParts.push(contents);
|
||||
|
||||
const text = options.originalText;
|
||||
const index = skipNewline(
|
||||
text,
|
||||
skipSpaces(text, options.locEnd(comment))
|
||||
);
|
||||
if (index !== false && hasNewline(text, index)) {
|
||||
leadingParts.push(hardline);
|
||||
}
|
||||
leadingParts.push(printLeadingComment(path, options));
|
||||
} else if (trailing) {
|
||||
trailingParts.push(printTrailingComment(commentPath, options));
|
||||
trailingParts.push(printTrailingComment(path, options));
|
||||
}
|
||||
}, "comments");
|
||||
|
||||
@@ -586,8 +580,8 @@ function printCommentsSeparately(path, options) {
|
||||
return { leading: leadingParts, trailing: trailingParts };
|
||||
}
|
||||
|
||||
function printComments(path, doc, options) {
|
||||
const { leading, trailing } = printCommentsSeparately(path, options);
|
||||
function printComments(path, doc, options, ignored) {
|
||||
const { leading, trailing } = printCommentsSeparately(path, options, ignored);
|
||||
if (!leading && !trailing) {
|
||||
return doc;
|
||||
}
|
||||
|
||||
@@ -43,7 +43,7 @@ const unstableTests = new Map(
|
||||
const [file, isUnstable = () => true] = Array.isArray(fixture)
|
||||
? fixture
|
||||
: [fixture];
|
||||
return [path.join(__dirname, "../tests/", file), isUnstable];
|
||||
return [path.join(__dirname, "../format/", file), isUnstable];
|
||||
})
|
||||
);
|
||||
|
||||
@@ -53,7 +53,7 @@ const espreeDisabledTests = new Set(
|
||||
[
|
||||
// These tests only work for `babel`
|
||||
"comments-closure-typecast",
|
||||
].map((directory) => path.join(__dirname, "../tests/js", directory))
|
||||
].map((directory) => path.join(__dirname, "../format/js", directory))
|
||||
);
|
||||
const meriyahDisabledTests = espreeDisabledTests;
|
||||
|
||||
@@ -94,7 +94,7 @@ const shouldThrowOnFormat = (filename, options) => {
|
||||
|
||||
const isTestDirectory = (dirname, name) =>
|
||||
(dirname + path.sep).startsWith(
|
||||
path.join(__dirname, "../tests", name) + path.sep
|
||||
path.join(__dirname, "../format", name) + path.sep
|
||||
);
|
||||
|
||||
function runSpec(fixtures, parsers, options) {
|
||||
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
@@ -2,6 +2,6 @@
|
||||
|
||||
Object.defineProperty(global, "run_spec", {
|
||||
get() {
|
||||
return require("./run_spec.js");
|
||||
return require("./format-test");
|
||||
},
|
||||
});
|
||||
Loaded 100 of 6814 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user