Skip to content

Commit

Permalink
feat(rome_js_parser): EcmaScript @decorators rome#4252
Browse files Browse the repository at this point in the history
class member
  • Loading branch information
denbezrukov committed Apr 16, 2023
1 parent f6c4dc0 commit 18df5e4
Show file tree
Hide file tree
Showing 18 changed files with 1,595 additions and 836 deletions.
105 changes: 4 additions & 101 deletions crates/rome_js_formatter/tests/quick_test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,109 +13,12 @@ mod language {
// use this test check if your snippet prints as you wish, without using a snapshot
fn quick_test() {
let src = r#"
import { LitElement, html } from '@polymer/lit-element';
class MyElement extends LitElement {
static get properties() {
return {
mood: { type: String }
};
}
constructor() {
super();
this.mood = 'happy';
}
render() {
return html`
<style
>
.mood { color: green; }
</style
>
Web Components are <span
class="mood" >${
this.mood
}</span
>!
`;
@foo
export default class MyComponent {
@task
*foo() {
}
}
customElements.define('my-element', MyElement);
const someHtml1 = html`<div > hello ${world} </div >`;
const someHtml2 = /* HTML */ `<div > hello ${world} </div >`;
html``
html`<my-element obj=${obj}></my-element>`;
html` <${Footer} >footer content<// > `
html` <div /> `
html`
<div />
`
html`<span>one</span><span>two</span><span>three</span>`;
function HelloWorld() {
return html`
<h3>Bar List</h3>
${bars.map(bar => html`
<p>${bar}</p>
`)}
`;
}
const trickyParens = html`<script> f((${expr}) / 2); </script>`;
const nestedFun = /* HTML */ `${outerExpr( 1 )} <script>const tpl = html\`<div>\${innerExpr( 1 )} ${outerExpr( 2 )}</div>\`</script>`;
const closingScriptTagShouldBeEscapedProperly = /* HTML */ `
<script>
const html = /* HTML */ \`<script><\\/script>\`;
</script>
`;
const closingScriptTag2 = /* HTML */ `<script>const scriptTag='<\\/script>'; <\/script>`;
html`
<div style="
${ foo}
"></div>
`
html`
<div style=${
foo
}></div>
`
html`<div style=" color : red;
display :inline ">
</div>`
html`<div style=" color : red;
${ foo}
display :inline ">
</div>`
html`<div style=" color : red;
${ foo}:${bar};
display :inline ">
</div>`
"#;
let syntax = SourceType::tsx();
let tree = parse(src, syntax);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
---
source: crates/rome_formatter_test/src/snapshot_builder.rs
info: js/decorators/mixed.js
---

# Input

```js
// https://github.com/prettier/prettier/issues/6747

@foo
export default class MyComponent {
@task
*foo() {
}
}
```


# Prettier differences

```diff
--- Prettier
+++ Rome
@@ -2,6 +2,5 @@

@foo
export default class MyComponent {
- @task
- *foo() {}
+ @task *foo() {}
}
```

# Output

```js
// https://github.com/prettier/prettier/issues/6747

@foo
export default class MyComponent {
@task *foo() {}
}
```

# Errors
```
mixed.js:3:1 parse ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
× Decorators are not valid here
1 │ // https://github.com/prettier/prettier/issues/6747
2 │
> 3 │ @foo
│ ^^^^
4 │ export default class MyComponent {
5 │ @task
```


Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
---
source: crates/rome_formatter_test/src/snapshot_builder.rs
info:
test_file: typescript/decorators/decorators-comments.ts
info: typescript/decorators/decorators-comments.ts
---

# Input
Expand Down Expand Up @@ -58,7 +57,44 @@ class Something3 {
```diff
--- Prettier
+++ Rome
@@ -30,12 +30,12 @@
@@ -1,41 +1,36 @@
class Foo1 {
- @foo
- // comment
- async method() {}
+ @foo async // comment
+ method() {}
}

class Foo2 {
- @foo
- // comment
+ @foo // comment
private method() {}
}

class Foo3 {
- @foo
- // comment
- *method() {}
+ @foo *// comment
+ method() {}
}

class Foo4 {
- @foo
- // comment
- async *method() {}
+ @foo async *// comment
+ method() {}
}

class Something {
- @foo()
- // comment
+ @foo() // comment
readonly property: Array<string>;
}

class Something2 {
@foo()
Expand All @@ -81,32 +117,27 @@ class Something3 {

```ts
class Foo1 {
@foo
// comment
async method() {}
@foo async // comment
method() {}
}

class Foo2 {
@foo
// comment
@foo // comment
private method() {}
}

class Foo3 {
@foo
// comment
*method() {}
@foo *// comment
method() {}
}

class Foo4 {
@foo
// comment
async *method() {}
@foo async *// comment
method() {}
}

class Something {
@foo()
// comment
@foo() // comment
readonly property: Array<string>;
}

Expand Down Expand Up @@ -136,6 +167,16 @@ decorators-comments.ts:35:5 parse ━━━━━━━━━━━━━━━
36 │ }
37 │
decorators-comments.ts:33:5 parse ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
× Decorators are not valid here
32 │ class Something2 {
> 33 │ @foo()
│ ^^^^^^
34 │ // comment
35 │ abstract property: Array<string>
decorators-comments.ts:41:5 parse ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
× Only abstract classes can have abstract members
Expand All @@ -147,6 +188,16 @@ decorators-comments.ts:41:5 parse ━━━━━━━━━━━━━━━
42 │ }
43 │
decorators-comments.ts:39:5 parse ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
× Decorators are not valid here
38 │ class Something3 {
> 39 │ @foo()
│ ^^^^^^
40 │ // comment
41 │ abstract method(): Array<string>
```

Expand Down
4 changes: 2 additions & 2 deletions crates/rome_js_parser/src/syntax/class.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2605,7 +2605,7 @@ fn parse_decorator(p: &mut JsParser) -> ParsedSyntax {
p.bump(T![@]);

if let Some(mut complete_marker) =
parse_expression(p, ExpressionContext::default().and_in_ts_decorator(true))
parse_lhs_expr(p, ExpressionContext::default().and_in_decorator(true))
.or_add_diagnostic(p, expected_expression)
{
if !matches!(
Expand Down Expand Up @@ -2652,7 +2652,7 @@ fn parse_decorator_bogus(p: &mut JsParser) -> ParsedSyntax {
// @Decorator((val) => val)
// badField!: number
// }
parse_lhs_expr(p, ExpressionContext::default().and_in_ts_decorator(true))
parse_lhs_expr(p, ExpressionContext::default().and_in_decorator(true))
.or_add_diagnostic(p, expected_expression);

Present(m.complete(p, JS_BOGUS))
Expand Down
12 changes: 6 additions & 6 deletions crates/rome_js_parser/src/syntax/expr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ bitflags! {

/// If `true` then, don't parse computed member expressions because they can as well indicate
/// the start of a computed class member.
const IN_TS_DECORATOR = 1 << 2;
const IN_DECORATOR = 1 << 2;

/// If `true` allows a typescript type assertion.
/// Currently disabled on "new" expressions.
Expand All @@ -74,8 +74,8 @@ impl ExpressionContext {
self.and(ExpressionContextFlags::ALLOW_OBJECT_EXPRESSION, allowed)
}

pub(crate) fn and_in_ts_decorator(self, in_decorator: bool) -> Self {
self.and(ExpressionContextFlags::IN_TS_DECORATOR, in_decorator)
pub(crate) fn and_in_decorator(self, in_decorator: bool) -> Self {
self.and(ExpressionContextFlags::IN_DECORATOR, in_decorator)
}

pub(crate) fn and_ts_type_assertion_allowed(self, allowed: bool) -> Self {
Expand All @@ -94,8 +94,8 @@ impl ExpressionContext {
}

/// Returns `true` if currently parsing a decorator expression `@<expr>`.
pub(crate) const fn is_in_ts_decorator(&self) -> bool {
self.0.contains(ExpressionContextFlags::IN_TS_DECORATOR)
pub(crate) const fn is_in_decorator(&self) -> bool {
self.0.contains(ExpressionContextFlags::IN_DECORATOR)
}

/// Adds the `flag` if `set` is `true`, otherwise removes the `flag`
Expand Down Expand Up @@ -721,7 +721,7 @@ fn parse_member_expression_rest(
lhs = match p.cur() {
T![.] => parse_static_member_expression(p, lhs, T![.]).unwrap(),
// Don't parse out `[` as a member expression because it may as well be the start of a computed class member
T!['['] if !context.is_in_ts_decorator() => {
T!['['] if !context.is_in_decorator() => {
parse_computed_member_expression(p, lhs, false).unwrap()
}
T![?.] if allow_optional_chain => {
Expand Down
7 changes: 4 additions & 3 deletions crates/rome_js_parser/src/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -393,10 +393,11 @@ fn diagnostics_print_correctly() {
#[test]
pub fn quick_test() {
let code = r#"
class Foo {
method(@dec a: string) {}
export default class MyComponent {
@task
*foo() {
}
}
"#;
let root = parse(code, SourceType::ts());
Expand Down
Loading

0 comments on commit 18df5e4

Please sign in to comment.