Skip to content

Commit afe06dd

Browse files
aspeddrocknitt
andauthored
Improve deprecated attribute extraction and support record form (#8396)
* improve deprecated attribute extraction and support record form - Enhance `findDeprecatedAttribute` to extract the `reason` from record-form `@deprecated` attributes. - Ensure deprecated attribute extraction works regardless of attribute order by reversing the list in `newDeclared`. - Update tests and expected outputs to reflect improved deprecated reason extraction, including record-form deprecations. * Update CHANGELOG.md --------- Co-authored-by: Christoph Knittel <ck@cca.io>
1 parent b304b9a commit afe06dd

14 files changed

Lines changed: 179 additions & 116 deletions

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@
3333
- Resolve workspace dependencies in editor analysis. https://github.com/rescript-lang/rescript/pull/8392
3434
- Build system: Add OpenTelemetry tracing support for cli commands. https://github.com/rescript-lang/rescript/pull/8370
3535
- Use a single vendored @rescript/react package across the repo. https://github.com/rescript-lang/rescript/pull/7525
36+
- Improve deprecated attribute extraction and support record form. https://github.com/rescript-lang/rescript/pull/8396
3637

3738
#### :house: Internal
3839

analysis/src/ProcessAttributes.ml

Lines changed: 20 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -22,15 +22,25 @@ let rec findDeprecatedAttribute attributes =
2222
match attributes with
2323
| [] -> None
2424
| ( {Asttypes.txt = "deprecated"},
25-
PStr
26-
[
27-
{
28-
pstr_desc =
29-
Pstr_eval ({pexp_desc = Pexp_constant (Pconst_string (msg, _))}, _);
30-
};
31-
] )
32-
:: _ ->
33-
Some msg
25+
PStr [{pstr_desc = Pstr_eval ({pexp_desc = expr}, _)}] )
26+
:: _ -> (
27+
match expr with
28+
(* Simple deprecated attr @deprecated("message") *)
29+
| Pexp_constant (Pconst_string (_msg, _)) -> Some _msg
30+
(* deprecated attr with record *)
31+
| Pexp_record (fields, _) ->
32+
let reason = ref "" in
33+
34+
fields
35+
|> List.iter (fun {lid = {txt}; x} ->
36+
match (txt, x) with
37+
| ( Lident "reason",
38+
{pexp_desc = Pexp_constant (Pconst_string (msg, _))} ) ->
39+
reason := msg
40+
| _ -> ());
41+
42+
Some !reason
43+
| _ -> None)
3444
| ({Asttypes.txt = "deprecated"}, _) :: _ -> Some ""
3545
| _ :: rest -> findDeprecatedAttribute rest
3646

@@ -41,7 +51,7 @@ let newDeclared ~item ~extent ~name ~stamp ~modulePath isExported attributes =
4151
extentLoc = extent;
4252
isExported;
4353
modulePath;
44-
deprecated = findDeprecatedAttribute attributes;
54+
deprecated = findDeprecatedAttribute (List.rev attributes);
4555
docstring =
4656
(match findDocAttribute attributes with
4757
| None -> []

tests/analysis_tests/tests/src/expected/Completion.res.txt

Lines changed: 21 additions & 21 deletions
Large diffs are not rendered by default.

tests/analysis_tests/tests/src/expected/CompletionInferValues.res.txt

Lines changed: 16 additions & 16 deletions
Large diffs are not rendered by default.

tests/analysis_tests/tests/src/expected/CompletionJsx.res.txt

Lines changed: 12 additions & 12 deletions
Large diffs are not rendered by default.

tests/analysis_tests/tests/src/expected/CompletionNullNullable.res.txt

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ Path
5353
"kind": 12,
5454
"tags": [1],
5555
"detail": "t<'a> => 'a",
56-
"documentation": {"kind": "markdown", "value": "Deprecated: \n\n\n`getExn(value)` throws an exception if `null`, otherwise returns the value.\n\n```rescript\nNull.getExn(Null.make(3)) == 3\n\nswitch Null.getExn(%raw(\"'ReScript'\")) {\n| exception Invalid_argument(_) => assert(false)\n| value => value == \"ReScript\"\n}\n\nswitch Null.getExn(%raw(\"null\")) {\n| exception Invalid_argument(_) => assert(true)\n| _ => assert(false)\n}\n```\n\n## Exceptions\n\n- Throws `Invalid_argument` if `value` is `null`\n"},
56+
"documentation": {"kind": "markdown", "value": "Deprecated: Use `getOrThrow` instead\n\n\n`getExn(value)` throws an exception if `null`, otherwise returns the value.\n\n```rescript\nNull.getExn(Null.make(3)) == 3\n\nswitch Null.getExn(%raw(\"'ReScript'\")) {\n| exception Invalid_argument(_) => assert(false)\n| value => value == \"ReScript\"\n}\n\nswitch Null.getExn(%raw(\"null\")) {\n| exception Invalid_argument(_) => assert(true)\n| _ => assert(false)\n}\n```\n\n## Exceptions\n\n- Throws `Invalid_argument` if `value` is `null`\n"},
5757
"sortText": "getExn",
5858
"insertText": "->Null.getExn",
5959
"additionalTextEdits": [{
@@ -137,7 +137,7 @@ Path
137137
"kind": 12,
138138
"tags": [1],
139139
"detail": "(t<'a>, 'b, 'a => 'b) => 'b",
140-
"documentation": {"kind": "markdown", "value": "Deprecated: \n\n"},
140+
"documentation": {"kind": "markdown", "value": "Deprecated: Use mapOr instead\n\n"},
141141
"sortText": "mapWithDefault",
142142
"insertText": "->Null.mapWithDefault",
143143
"additionalTextEdits": [{
@@ -149,7 +149,7 @@ Path
149149
"kind": 12,
150150
"tags": [1],
151151
"detail": "(t<'a>, 'a) => 'a",
152-
"documentation": {"kind": "markdown", "value": "Deprecated: \n\n"},
152+
"documentation": {"kind": "markdown", "value": "Deprecated: Use getOr instead\n\n"},
153153
"sortText": "getWithDefault",
154154
"insertText": "->Null.getWithDefault",
155155
"additionalTextEdits": [{
@@ -249,7 +249,7 @@ Path
249249
"kind": 12,
250250
"tags": [1],
251251
"detail": "t<'a> => 'a",
252-
"documentation": {"kind": "markdown", "value": "Deprecated: \n\n\n`getExn(value)` throws an exception if `null` or `undefined`, otherwise returns the value.\n\n```rescript\nswitch Nullable.getExn(%raw(\"'Hello'\")) {\n| exception Invalid_argument(_) => assert(false)\n| value => value == \"Hello\"\n}\n\nswitch Nullable.getExn(%raw(\"null\")) {\n| exception Invalid_argument(_) => assert(true)\n| _ => assert(false)\n}\n\nswitch Nullable.getExn(%raw(\"undefined\")) {\n| exception Invalid_argument(_) => assert(true)\n| _ => assert(false)\n}\n```\n\n## Exceptions\n\n- Throws `Invalid_argument` if `value` is `null` or `undefined`\n"},
252+
"documentation": {"kind": "markdown", "value": "Deprecated: Use `getOrThrow` instead\n\n\n`getExn(value)` throws an exception if `null` or `undefined`, otherwise returns the value.\n\n```rescript\nswitch Nullable.getExn(%raw(\"'Hello'\")) {\n| exception Invalid_argument(_) => assert(false)\n| value => value == \"Hello\"\n}\n\nswitch Nullable.getExn(%raw(\"null\")) {\n| exception Invalid_argument(_) => assert(true)\n| _ => assert(false)\n}\n\nswitch Nullable.getExn(%raw(\"undefined\")) {\n| exception Invalid_argument(_) => assert(true)\n| _ => assert(false)\n}\n```\n\n## Exceptions\n\n- Throws `Invalid_argument` if `value` is `null` or `undefined`\n"},
253253
"sortText": "getExn",
254254
"insertText": "->Nullable.getExn",
255255
"additionalTextEdits": [{
@@ -333,7 +333,7 @@ Path
333333
"kind": 12,
334334
"tags": [1],
335335
"detail": "(t<'a>, 'b, 'a => 'b) => 'b",
336-
"documentation": {"kind": "markdown", "value": "Deprecated: \n\n"},
336+
"documentation": {"kind": "markdown", "value": "Deprecated: Use mapOr instead\n\n"},
337337
"sortText": "mapWithDefault",
338338
"insertText": "->Nullable.mapWithDefault",
339339
"additionalTextEdits": [{
@@ -345,7 +345,7 @@ Path
345345
"kind": 12,
346346
"tags": [1],
347347
"detail": "(t<'a>, 'a) => 'a",
348-
"documentation": {"kind": "markdown", "value": "Deprecated: \n\n"},
348+
"documentation": {"kind": "markdown", "value": "Deprecated: Use getOr instead\n\n"},
349349
"sortText": "getWithDefault",
350350
"insertText": "->Nullable.getWithDefault",
351351
"additionalTextEdits": [{

tests/analysis_tests/tests/src/expected/CompletionPipeChain.res.txt

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -329,25 +329,25 @@ Path t
329329
"kind": 12,
330330
"tags": [1],
331331
"detail": "(int, ~radix: int) => string",
332-
"documentation": {"kind": "markdown", "value": "Deprecated: \n\n\n`toStringWithRadix(n, ~radix)` return a `string` representing the given value.\n`~radix` specifies the radix base to use for the formatted number.\nSee [`Number.toString`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number/toString)\non MDN.\n\n## Examples\n\n```rescript\nInt.toStringWithRadix(6, ~radix=2) // \"110\"\nInt.toStringWithRadix(373592855, ~radix=16) // \"16449317\"\nInt.toStringWithRadix(123456, ~radix=36) // \"2n9c\"\n```\n\n## Exceptions\n\n`RangeError`: if `radix` is less than 2 or greater than 36.\n"}
332+
"documentation": {"kind": "markdown", "value": "Deprecated: Use `toString` instead\n\n\n`toStringWithRadix(n, ~radix)` return a `string` representing the given value.\n`~radix` specifies the radix base to use for the formatted number.\nSee [`Number.toString`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number/toString)\non MDN.\n\n## Examples\n\n```rescript\nInt.toStringWithRadix(6, ~radix=2) // \"110\"\nInt.toStringWithRadix(373592855, ~radix=16) // \"16449317\"\nInt.toStringWithRadix(123456, ~radix=36) // \"2n9c\"\n```\n\n## Exceptions\n\n`RangeError`: if `radix` is less than 2 or greater than 36.\n"}
333333
}, {
334334
"label": "Int.toExponentialWithPrecision",
335335
"kind": 12,
336336
"tags": [1],
337337
"detail": "(int, ~digits: int) => string",
338-
"documentation": {"kind": "markdown", "value": "Deprecated: \n\n\n`toExponential(n, ~digits)` return a `string` representing the given value in\nexponential notation. `digits` specifies how many digits should appear after\nthe decimal point. See [`Number.toExponential`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number/toExponential)\non MDN.\n\n## Examples\n\n```rescript\nInt.toExponentialWithPrecision(77, ~digits=2) // \"7.70e+1\"\nInt.toExponentialWithPrecision(5678, ~digits=2) // \"5.68e+3\"\n```\n\n## Exceptions\n\n- `RangeError`: If `digits` less than 0 or greater than 10.\n"}
338+
"documentation": {"kind": "markdown", "value": "Deprecated: Use `toExponential` instead\n\n\n`toExponential(n, ~digits)` return a `string` representing the given value in\nexponential notation. `digits` specifies how many digits should appear after\nthe decimal point. See [`Number.toExponential`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number/toExponential)\non MDN.\n\n## Examples\n\n```rescript\nInt.toExponentialWithPrecision(77, ~digits=2) // \"7.70e+1\"\nInt.toExponentialWithPrecision(5678, ~digits=2) // \"5.68e+3\"\n```\n\n## Exceptions\n\n- `RangeError`: If `digits` less than 0 or greater than 10.\n"}
339339
}, {
340340
"label": "Int.toFixedWithPrecision",
341341
"kind": 12,
342342
"tags": [1],
343343
"detail": "(int, ~digits: int) => string",
344-
"documentation": {"kind": "markdown", "value": "Deprecated: \n\n\n`toFixedWithPrecision(n, ~digits)` return a `string` representing the given\nvalue using fixed-point notation. `digits` specifies how many digits should\nappear after the decimal point. See [`Number.toFixed`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number/toFixed)\non MDN.\n\n## Examples\n\n```rescript\nInt.toFixedWithPrecision(300, ~digits=4) // \"300.0000\"\nInt.toFixedWithPrecision(300, ~digits=1) // \"300.0\"\n```\n\n## Exceptions\n\n- `RangeError`: If `digits` is less than 0 or larger than 100.\n"}
344+
"documentation": {"kind": "markdown", "value": "Deprecated: Use `toFixed` instead\n\n\n`toFixedWithPrecision(n, ~digits)` return a `string` representing the given\nvalue using fixed-point notation. `digits` specifies how many digits should\nappear after the decimal point. See [`Number.toFixed`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number/toFixed)\non MDN.\n\n## Examples\n\n```rescript\nInt.toFixedWithPrecision(300, ~digits=4) // \"300.0000\"\nInt.toFixedWithPrecision(300, ~digits=1) // \"300.0\"\n```\n\n## Exceptions\n\n- `RangeError`: If `digits` is less than 0 or larger than 100.\n"}
345345
}, {
346346
"label": "Int.toPrecisionWithPrecision",
347347
"kind": 12,
348348
"tags": [1],
349349
"detail": "(int, ~digits: int) => string",
350-
"documentation": {"kind": "markdown", "value": "Deprecated: \n\n\n`toPrecisionWithPrecision(n, ~digits)` return a `string` representing the giver value with\nprecision. `digits` specifies the number of significant digits. See [`Number.toPrecision`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number/toPrecision) on MDN.\n\n## Examples\n\n```rescript\nInt.toPrecisionWithPrecision(100, ~digits=2) // \"1.0e+2\"\nInt.toPrecisionWithPrecision(1, ~digits=2) // \"1.0\"\n```\n\n## Exceptions\n\n- `RangeError`: If `digits` is not between 1 and 100 (inclusive).\n Implementations are allowed to support larger and smaller values as well.\n ECMA-262 only requires a precision of up to 21 significant digits.\n"}
350+
"documentation": {"kind": "markdown", "value": "Deprecated: Use `toPrecision` instead\n\n\n`toPrecisionWithPrecision(n, ~digits)` return a `string` representing the giver value with\nprecision. `digits` specifies the number of significant digits. See [`Number.toPrecision`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number/toPrecision) on MDN.\n\n## Examples\n\n```rescript\nInt.toPrecisionWithPrecision(100, ~digits=2) // \"1.0e+2\"\nInt.toPrecisionWithPrecision(1, ~digits=2) // \"1.0\"\n```\n\n## Exceptions\n\n- `RangeError`: If `digits` is not between 1 and 100 (inclusive).\n Implementations are allowed to support larger and smaller values as well.\n ECMA-262 only requires a precision of up to 21 significant digits.\n"}
351351
}, {
352352
"label": "Int.toPrecision",
353353
"kind": 12,

0 commit comments

Comments
 (0)