@abaplint/cli 2.107.0 → 2.107.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/build/cli.js +124 -26
- package/package.json +5 -5
package/build/cli.js
CHANGED
|
@@ -51462,7 +51462,7 @@ class Registry {
|
|
|
51462
51462
|
}
|
|
51463
51463
|
static abaplintVersion() {
|
|
51464
51464
|
// magic, see build script "version.sh"
|
|
51465
|
-
return "2.107.
|
|
51465
|
+
return "2.107.2";
|
|
51466
51466
|
}
|
|
51467
51467
|
getDDICReferences() {
|
|
51468
51468
|
return this.ddicReferences;
|
|
@@ -51784,6 +51784,8 @@ https://help.sap.com/doc/abapdocu_750_index_htm/7.50/en-US/abencharacter_set_gui
|
|
|
51784
51784
|
|
|
51785
51785
|
Checkes files with extensions ".abap" and ".asddls"`,
|
|
51786
51786
|
tags: [_irule_1.RuleTag.SingleFile],
|
|
51787
|
+
badExample: `WRITE '뽑'.`,
|
|
51788
|
+
goodExample: `WRITE cl_abap_conv_in_ce=>uccp( 'BF51' ).`,
|
|
51787
51789
|
};
|
|
51788
51790
|
}
|
|
51789
51791
|
initialize(_reg) {
|
|
@@ -52490,17 +52492,23 @@ exports.AlignParameters = AlignParameters;
|
|
|
52490
52492
|
|
|
52491
52493
|
Object.defineProperty(exports, "__esModule", ({ value: true }));
|
|
52492
52494
|
exports.AlignTypeExpressions = exports.AlignTypeExpressionsConf = void 0;
|
|
52493
|
-
const issue_1 = __webpack_require__(/*! ../issue */ "./node_modules/@abaplint/core/build/src/issue.js");
|
|
52494
52495
|
const _abap_rule_1 = __webpack_require__(/*! ./_abap_rule */ "./node_modules/@abaplint/core/build/src/rules/_abap_rule.js");
|
|
52495
52496
|
const _basic_rule_config_1 = __webpack_require__(/*! ./_basic_rule_config */ "./node_modules/@abaplint/core/build/src/rules/_basic_rule_config.js");
|
|
52497
|
+
const objects_1 = __webpack_require__(/*! ../objects */ "./node_modules/@abaplint/core/build/src/objects/index.js");
|
|
52498
|
+
const ddic_1 = __webpack_require__(/*! ../ddic */ "./node_modules/@abaplint/core/build/src/ddic.js");
|
|
52496
52499
|
const _irule_1 = __webpack_require__(/*! ./_irule */ "./node_modules/@abaplint/core/build/src/rules/_irule.js");
|
|
52497
|
-
const
|
|
52498
|
-
const
|
|
52500
|
+
const issue_1 = __webpack_require__(/*! ../issue */ "./node_modules/@abaplint/core/build/src/issue.js");
|
|
52501
|
+
const position_1 = __webpack_require__(/*! ../position */ "./node_modules/@abaplint/core/build/src/position.js");
|
|
52499
52502
|
const Expressions = __webpack_require__(/*! ../abap/2_statements/expressions */ "./node_modules/@abaplint/core/build/src/abap/2_statements/expressions/index.js");
|
|
52500
|
-
|
|
52501
|
-
|
|
52502
|
-
*/
|
|
52503
|
+
const Statements = __webpack_require__(/*! ../abap/2_statements/statements */ "./node_modules/@abaplint/core/build/src/abap/2_statements/statements/index.js");
|
|
52504
|
+
const Structures = __webpack_require__(/*! ../abap/3_structures/structures */ "./node_modules/@abaplint/core/build/src/abap/3_structures/structures/index.js");
|
|
52505
|
+
const edit_helper_1 = __webpack_require__(/*! ../edit_helper */ "./node_modules/@abaplint/core/build/src/edit_helper.js");
|
|
52503
52506
|
class AlignTypeExpressionsConf extends _basic_rule_config_1.BasicRuleConfig {
|
|
52507
|
+
constructor() {
|
|
52508
|
+
super(...arguments);
|
|
52509
|
+
/** Ignore global exception classes */
|
|
52510
|
+
this.ignoreExceptions = true;
|
|
52511
|
+
}
|
|
52504
52512
|
}
|
|
52505
52513
|
exports.AlignTypeExpressionsConf = AlignTypeExpressionsConf;
|
|
52506
52514
|
class AlignTypeExpressions extends _abap_rule_1.ABAPRule {
|
|
@@ -52516,9 +52524,11 @@ class AlignTypeExpressions extends _abap_rule_1.ABAPRule {
|
|
|
52516
52524
|
extendedInformation: `
|
|
52517
52525
|
Currently works for METHODS + BEGIN OF
|
|
52518
52526
|
|
|
52527
|
+
If BEGIN OF has an INCLUDE TYPE its ignored
|
|
52528
|
+
|
|
52519
52529
|
Also note that clean ABAP does not recommend aligning TYPE clauses:
|
|
52520
52530
|
https://github.com/SAP/styleguides/blob/main/clean-abap/CleanABAP.md#dont-align-type-clauses`,
|
|
52521
|
-
tags: [_irule_1.RuleTag.SingleFile, _irule_1.RuleTag.Whitespace],
|
|
52531
|
+
tags: [_irule_1.RuleTag.SingleFile, _irule_1.RuleTag.Whitespace, _irule_1.RuleTag.Quickfix],
|
|
52522
52532
|
badExample: `
|
|
52523
52533
|
TYPES: BEGIN OF foo,
|
|
52524
52534
|
bar TYPE i,
|
|
@@ -52551,16 +52561,45 @@ ENDINTERFACE.`,
|
|
|
52551
52561
|
setConfig(conf) {
|
|
52552
52562
|
this.conf = conf;
|
|
52553
52563
|
}
|
|
52554
|
-
runParsed(file) {
|
|
52564
|
+
runParsed(file, obj) {
|
|
52555
52565
|
const issues = [];
|
|
52556
52566
|
const stru = file.getStructure();
|
|
52557
52567
|
if (stru === undefined) {
|
|
52558
52568
|
return issues; // parser error
|
|
52559
52569
|
}
|
|
52570
|
+
const ddic = new ddic_1.DDIC(this.reg);
|
|
52571
|
+
if (obj instanceof objects_1.Class) {
|
|
52572
|
+
const definition = obj.getClassDefinition();
|
|
52573
|
+
if (definition === undefined) {
|
|
52574
|
+
return [];
|
|
52575
|
+
}
|
|
52576
|
+
else if (this.conf.ignoreExceptions && ddic.isException(definition, obj)) {
|
|
52577
|
+
return [];
|
|
52578
|
+
}
|
|
52579
|
+
}
|
|
52560
52580
|
issues.push(...this.checkTypes(stru, file));
|
|
52561
52581
|
issues.push(...this.checkMethods(stru, file));
|
|
52562
52582
|
return issues;
|
|
52563
52583
|
}
|
|
52584
|
+
check(fields, column, file) {
|
|
52585
|
+
const issues = [];
|
|
52586
|
+
for (const f of fields) {
|
|
52587
|
+
if (f.after.getCol() === column) {
|
|
52588
|
+
continue;
|
|
52589
|
+
}
|
|
52590
|
+
let fix = undefined;
|
|
52591
|
+
if (f.after.getCol() < column) {
|
|
52592
|
+
fix = edit_helper_1.EditHelper.insertAt(file, f.after, " ".repeat(column - f.after.getCol()));
|
|
52593
|
+
}
|
|
52594
|
+
else {
|
|
52595
|
+
fix = edit_helper_1.EditHelper.deleteRange(file, new position_1.Position(f.after.getRow(), column), f.after);
|
|
52596
|
+
}
|
|
52597
|
+
const message = `Align TYPE expressions to column ${column}`;
|
|
52598
|
+
const issue = issue_1.Issue.atPosition(file, f.after, message, this.getMetadata().key, this.conf.severity, fix);
|
|
52599
|
+
issues.push(issue);
|
|
52600
|
+
}
|
|
52601
|
+
return issues;
|
|
52602
|
+
}
|
|
52564
52603
|
checkMethods(stru, file) {
|
|
52565
52604
|
const issues = [];
|
|
52566
52605
|
const methods = stru.findAllStatements(Statements.MethodDef);
|
|
@@ -52587,14 +52626,7 @@ ENDINTERFACE.`,
|
|
|
52587
52626
|
});
|
|
52588
52627
|
column = Math.max(column, name.getLastToken().getEnd().getCol() + 1);
|
|
52589
52628
|
}
|
|
52590
|
-
|
|
52591
|
-
if (f.after.getCol() !== column) {
|
|
52592
|
-
// const fix = this.buildFix(f.name, column);
|
|
52593
|
-
const message = `Align TYPE expressions to column ${column}`;
|
|
52594
|
-
const issue = issue_1.Issue.atPosition(file, f.after, message, this.getMetadata().key, this.conf.severity);
|
|
52595
|
-
issues.push(issue);
|
|
52596
|
-
}
|
|
52597
|
-
}
|
|
52629
|
+
issues.push(...this.check(fields, column, file));
|
|
52598
52630
|
}
|
|
52599
52631
|
return issues;
|
|
52600
52632
|
}
|
|
@@ -52602,6 +52634,9 @@ ENDINTERFACE.`,
|
|
|
52602
52634
|
const issues = [];
|
|
52603
52635
|
const types = stru.findAllStructuresRecursive(Structures.Types);
|
|
52604
52636
|
for (const t of types) {
|
|
52637
|
+
if (t.findDirectStatement(Statements.IncludeType)) {
|
|
52638
|
+
continue;
|
|
52639
|
+
}
|
|
52605
52640
|
const fields = [];
|
|
52606
52641
|
let column = 0;
|
|
52607
52642
|
const st = t.findDirectStatements(Statements.Type);
|
|
@@ -52613,14 +52648,7 @@ ENDINTERFACE.`,
|
|
|
52613
52648
|
});
|
|
52614
52649
|
column = Math.max(column, name.getFirstToken().getEnd().getCol() + 1);
|
|
52615
52650
|
}
|
|
52616
|
-
|
|
52617
|
-
if (f.after.getCol() !== column) {
|
|
52618
|
-
// const fix = this.buildFix(f.name, column);
|
|
52619
|
-
const message = `Align TYPE expressions to column ${column}`;
|
|
52620
|
-
const issue = issue_1.Issue.atPosition(file, f.after, message, this.getMetadata().key, this.conf.severity);
|
|
52621
|
-
issues.push(issue);
|
|
52622
|
-
}
|
|
52623
|
-
}
|
|
52651
|
+
issues.push(...this.check(fields, column, file));
|
|
52624
52652
|
}
|
|
52625
52653
|
return issues;
|
|
52626
52654
|
}
|
|
@@ -53161,7 +53189,8 @@ STATICS BEGIN OF bar.
|
|
|
53161
53189
|
INCLUDE STRUCTURE syst.
|
|
53162
53190
|
STATICS END OF bar.`,
|
|
53163
53191
|
goodExample: `DATA BEGIN OF foo.
|
|
53164
|
-
|
|
53192
|
+
DATA field TYPE i.
|
|
53193
|
+
INCLUDE STRUCTURE dselc.
|
|
53165
53194
|
DATA END OF foo.`,
|
|
53166
53195
|
};
|
|
53167
53196
|
}
|
|
@@ -55016,6 +55045,7 @@ class CommentedCode extends _abap_rule_1.ABAPRule {
|
|
|
55016
55045
|
extendedInformation: `https://github.com/SAP/styleguides/blob/main/clean-abap/CleanABAP.md#delete-code-instead-of-commenting-it
|
|
55017
55046
|
https://docs.abapopenchecks.org/checks/14/`,
|
|
55018
55047
|
tags: [_irule_1.RuleTag.Styleguide, _irule_1.RuleTag.Quickfix, _irule_1.RuleTag.SingleFile],
|
|
55048
|
+
badExample: `* WRITE 'hello world'.`,
|
|
55019
55049
|
};
|
|
55020
55050
|
}
|
|
55021
55051
|
getMessage() {
|
|
@@ -55327,6 +55357,8 @@ class ContainsTab extends _abap_rule_1.ABAPRule {
|
|
|
55327
55357
|
https://docs.abapopenchecks.org/checks/09/
|
|
55328
55358
|
https://github.com/SAP/styleguides/blob/main/clean-abap/CleanABAP.md#indent-and-snap-to-tab`,
|
|
55329
55359
|
tags: [_irule_1.RuleTag.Whitespace, _irule_1.RuleTag.Quickfix, _irule_1.RuleTag.Styleguide, _irule_1.RuleTag.SingleFile],
|
|
55360
|
+
badExample: `\tWRITE 'hello world'.`,
|
|
55361
|
+
goodExample: ` WRITE 'hello world'.`,
|
|
55330
55362
|
};
|
|
55331
55363
|
}
|
|
55332
55364
|
getMessage() {
|
|
@@ -59484,6 +59516,8 @@ class EmptyStatement extends _abap_rule_1.ABAPRule {
|
|
|
59484
59516
|
title: "Remove empty statement",
|
|
59485
59517
|
shortDescription: `Checks for empty statements (an empty statement is a single dot)`,
|
|
59486
59518
|
tags: [_irule_1.RuleTag.Quickfix, _irule_1.RuleTag.SingleFile],
|
|
59519
|
+
badExample: `WRITE 'hello world'..`,
|
|
59520
|
+
goodExample: `WRITE 'hello world'.`,
|
|
59487
59521
|
};
|
|
59488
59522
|
}
|
|
59489
59523
|
getConfig() {
|
|
@@ -61872,6 +61906,24 @@ class Indentation extends _abap_rule_1.ABAPRule {
|
|
|
61872
61906
|
title: "Indentation",
|
|
61873
61907
|
shortDescription: `Checks indentation`,
|
|
61874
61908
|
tags: [_irule_1.RuleTag.Whitespace, _irule_1.RuleTag.Quickfix, _irule_1.RuleTag.SingleFile],
|
|
61909
|
+
badExample: `CLASS lcl DEFINITION.
|
|
61910
|
+
PRIVATE SECTION.
|
|
61911
|
+
METHODS constructor.
|
|
61912
|
+
ENDCLASS.
|
|
61913
|
+
|
|
61914
|
+
CLASS lcl IMPLEMENTATION.
|
|
61915
|
+
METHOD constructor.
|
|
61916
|
+
ENDMETHOD.
|
|
61917
|
+
ENDCLASS.`,
|
|
61918
|
+
goodExample: `CLASS lcl DEFINITION.
|
|
61919
|
+
PRIVATE SECTION.
|
|
61920
|
+
METHODS constructor.
|
|
61921
|
+
ENDCLASS.
|
|
61922
|
+
|
|
61923
|
+
CLASS lcl IMPLEMENTATION.
|
|
61924
|
+
METHOD constructor.
|
|
61925
|
+
ENDMETHOD.
|
|
61926
|
+
ENDCLASS.`,
|
|
61875
61927
|
};
|
|
61876
61928
|
}
|
|
61877
61929
|
getConfig() {
|
|
@@ -62685,6 +62737,8 @@ class KeywordCase extends _abap_rule_1.ABAPRule {
|
|
|
62685
62737
|
shortDescription: `Checks that keywords have the same case. Non-keywords must be lower case.`,
|
|
62686
62738
|
extendedInformation: `https://github.com/SAP/styleguides/blob/main/clean-abap/CleanABAP.md#use-your-pretty-printer-team-settings`,
|
|
62687
62739
|
tags: [_irule_1.RuleTag.Styleguide, _irule_1.RuleTag.SingleFile, _irule_1.RuleTag.Quickfix],
|
|
62740
|
+
badExample: `write 'hello world'.`,
|
|
62741
|
+
goodExample: `WRITE 'hello world'.`,
|
|
62688
62742
|
};
|
|
62689
62743
|
}
|
|
62690
62744
|
getConfig() {
|
|
@@ -63346,6 +63400,12 @@ class LocalVariableNames extends _abap_rule_1.ABAPRule {
|
|
|
63346
63400
|
Allows you to enforce a pattern, such as a prefix, for local variables, constants and field symbols.
|
|
63347
63401
|
Regexes are case-insensitive.`,
|
|
63348
63402
|
tags: [_irule_1.RuleTag.Naming, _irule_1.RuleTag.SingleFile],
|
|
63403
|
+
badExample: `FORM bar.
|
|
63404
|
+
DATA foo.
|
|
63405
|
+
ENDFORM.`,
|
|
63406
|
+
goodExample: `FORM bar.
|
|
63407
|
+
DATA lv_foo.
|
|
63408
|
+
ENDFORM.`,
|
|
63349
63409
|
};
|
|
63350
63410
|
}
|
|
63351
63411
|
getDescription(expected, actual) {
|
|
@@ -64319,6 +64379,15 @@ https://github.com/SAP/styleguides/blob/main/clean-abap/CleanABAP.md#avoid-obscu
|
|
|
64319
64379
|
|
|
64320
64380
|
Interface method names are ignored`,
|
|
64321
64381
|
tags: [_irule_1.RuleTag.Naming, _irule_1.RuleTag.SingleFile, _irule_1.RuleTag.Styleguide],
|
|
64382
|
+
badExample: `CLASS lcl DEFINITION.
|
|
64383
|
+
PUBLIC SECTION.
|
|
64384
|
+
METHODS matches.
|
|
64385
|
+
ENDCLASS.
|
|
64386
|
+
|
|
64387
|
+
CLASS lcl IMPLEMENTATION.
|
|
64388
|
+
METHOD matches.
|
|
64389
|
+
ENDMETHOD.
|
|
64390
|
+
ENDCLASS.`,
|
|
64322
64391
|
};
|
|
64323
64392
|
}
|
|
64324
64393
|
getConfig() {
|
|
@@ -64508,6 +64577,13 @@ class MixReturning extends _abap_rule_1.ABAPRule {
|
|
|
64508
64577
|
// eslint-disable-next-line max-len
|
|
64509
64578
|
extendedInformation: `https://github.com/SAP/styleguides/blob/main/clean-abap/CleanABAP.md#use-either-returning-or-exporting-or-changing-but-not-a-combination`,
|
|
64510
64579
|
tags: [_irule_1.RuleTag.Styleguide, _irule_1.RuleTag.SingleFile],
|
|
64580
|
+
badExample: `CLASS lcl DEFINITION.
|
|
64581
|
+
PUBLIC SECTION.
|
|
64582
|
+
METHODS
|
|
64583
|
+
foobar
|
|
64584
|
+
EXPORTING foo TYPE i
|
|
64585
|
+
RETURNING VALUE(rv_string) TYPE string.
|
|
64586
|
+
ENDCLASS.`,
|
|
64511
64587
|
};
|
|
64512
64588
|
}
|
|
64513
64589
|
getMessage() {
|
|
@@ -67804,6 +67880,10 @@ class PreferReturningToExporting extends _abap_rule_1.ABAPRule {
|
|
|
67804
67880
|
extendedInformation: `https://github.com/SAP/styleguides/blob/main/clean-abap/CleanABAP.md#prefer-returning-to-exporting
|
|
67805
67881
|
https://docs.abapopenchecks.org/checks/44/`,
|
|
67806
67882
|
tags: [_irule_1.RuleTag.Styleguide, _irule_1.RuleTag.SingleFile],
|
|
67883
|
+
badExample: `CLASS lcl DEFINITION.
|
|
67884
|
+
PUBLIC SECTION.
|
|
67885
|
+
METHODS test EXPORTING ev_foo TYPE i.
|
|
67886
|
+
ENDCLASS.`,
|
|
67807
67887
|
};
|
|
67808
67888
|
}
|
|
67809
67889
|
getConfig() {
|
|
@@ -67971,6 +68051,10 @@ class PreferredCompareOperator extends _abap_rule_1.ABAPRule {
|
|
|
67971
68051
|
title: "Preferred compare operator",
|
|
67972
68052
|
shortDescription: `Configure undesired operator variants`,
|
|
67973
68053
|
tags: [_irule_1.RuleTag.SingleFile, _irule_1.RuleTag.Quickfix],
|
|
68054
|
+
badExample: `IF foo EQ bar.
|
|
68055
|
+
ENDIF.`,
|
|
68056
|
+
goodExample: `IF foo = bar.
|
|
68057
|
+
ENDIF.`,
|
|
67974
68058
|
};
|
|
67975
68059
|
}
|
|
67976
68060
|
getDescription(operator) {
|
|
@@ -68684,6 +68768,8 @@ add ORDER BY PRIMARY KEY if in doubt
|
|
|
68684
68768
|
|
|
68685
68769
|
If the target is a sorted/hashed table, no issue is reported`,
|
|
68686
68770
|
tags: [_irule_1.RuleTag.SingleFile],
|
|
68771
|
+
badExample: `SELECT * FROM db INTO TABLE @DATA(tab).`,
|
|
68772
|
+
goodExample: `SELECT * FROM db INTO TABLE @DATA(tab) ORDER BY PRIMARY KEY.`,
|
|
68687
68773
|
};
|
|
68688
68774
|
}
|
|
68689
68775
|
getConfig() {
|
|
@@ -70701,6 +70787,8 @@ class TypesNaming extends _abap_rule_1.ABAPRule {
|
|
|
70701
70787
|
shortDescription: `Allows you to enforce a pattern for TYPES definitions`,
|
|
70702
70788
|
extendedInformation: `Does not run for TYPE POOLS`,
|
|
70703
70789
|
tags: [_irule_1.RuleTag.Naming, _irule_1.RuleTag.SingleFile],
|
|
70790
|
+
badExample: `TYPES foo TYPE i.`,
|
|
70791
|
+
goodExample: `TYPES ty_foo TYPE i.`,
|
|
70704
70792
|
};
|
|
70705
70793
|
}
|
|
70706
70794
|
getConfig() {
|
|
@@ -72676,6 +72764,16 @@ class UseClassBasedExceptions extends _abap_rule_1.ABAPRule {
|
|
|
72676
72764
|
shortDescription: `Use class based exceptions, checks interface and class definitions`,
|
|
72677
72765
|
extendedInformation: `https://github.com/SAP/styleguides/blob/main/clean-abap/CleanABAP.md#use-class-based-exceptions`,
|
|
72678
72766
|
tags: [_irule_1.RuleTag.Styleguide, _irule_1.RuleTag.SingleFile],
|
|
72767
|
+
badExample: `INTERFACE lif.
|
|
72768
|
+
METHODS load_data
|
|
72769
|
+
EXCEPTIONS
|
|
72770
|
+
invalid_parameter.
|
|
72771
|
+
ENDINTERFACE.`,
|
|
72772
|
+
goodExample: `INTERFACE lif.
|
|
72773
|
+
METHODS load_data
|
|
72774
|
+
RAISING
|
|
72775
|
+
cx_something.
|
|
72776
|
+
ENDINTERFACE.`,
|
|
72679
72777
|
};
|
|
72680
72778
|
}
|
|
72681
72779
|
getMessage() {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@abaplint/cli",
|
|
3
|
-
"version": "2.107.
|
|
3
|
+
"version": "2.107.2",
|
|
4
4
|
"description": "abaplint - Command Line Interface",
|
|
5
5
|
"funding": "https://github.com/sponsors/larshp",
|
|
6
6
|
"bin": {
|
|
@@ -38,19 +38,19 @@
|
|
|
38
38
|
},
|
|
39
39
|
"homepage": "https://abaplint.org",
|
|
40
40
|
"devDependencies": {
|
|
41
|
-
"@abaplint/core": "^2.107.
|
|
42
|
-
"@types/chai": "^4.3.
|
|
41
|
+
"@abaplint/core": "^2.107.2",
|
|
42
|
+
"@types/chai": "^4.3.15",
|
|
43
43
|
"@types/glob": "^8.1.0",
|
|
44
44
|
"@types/minimist": "^1.2.5",
|
|
45
45
|
"@types/mocha": "^10.0.6",
|
|
46
|
-
"@types/node": "^20.12.
|
|
46
|
+
"@types/node": "^20.12.8",
|
|
47
47
|
"@types/progress": "^2.0.7",
|
|
48
48
|
"chai": "^4.4.1",
|
|
49
49
|
"chalk": "^5.3.0",
|
|
50
50
|
"eslint": "^8.57.0",
|
|
51
51
|
"glob": "^7.2.3",
|
|
52
52
|
"json5": "^2.2.3",
|
|
53
|
-
"memfs": "^4.
|
|
53
|
+
"memfs": "^4.9.2",
|
|
54
54
|
"minimist": "^1.2.8",
|
|
55
55
|
"mocha": "^10.4.0",
|
|
56
56
|
"progress": "^2.0.3",
|