@player-tools/complexity-check-plugin 0.8.1--canary.169.3663
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/dist/cjs/index.cjs +219 -0
- package/dist/cjs/index.cjs.map +1 -0
- package/dist/index.legacy-esm.js +197 -0
- package/dist/index.mjs +197 -0
- package/dist/index.mjs.map +1 -0
- package/package.json +35 -0
- package/src/__tests__/complexity-check-plugin.test.ts +470 -0
- package/src/complexity-check.ts +261 -0
- package/src/index.ts +1 -0
- package/types/complexity-check.d.ts +30 -0
- package/types/index.d.ts +2 -0
package/package.json
ADDED
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
{
|
|
2
|
+
"sideEffects": false,
|
|
3
|
+
"files": [
|
|
4
|
+
"dist",
|
|
5
|
+
"src",
|
|
6
|
+
"types"
|
|
7
|
+
],
|
|
8
|
+
"name": "@player-tools/complexity-check-plugin",
|
|
9
|
+
"version": "0.8.1--canary.169.3663",
|
|
10
|
+
"main": "dist/cjs/index.cjs",
|
|
11
|
+
"dependencies": {
|
|
12
|
+
"@player-tools/json-language-service": "0.8.1--canary.169.3663",
|
|
13
|
+
"@player-ui/player": "0.7.3",
|
|
14
|
+
"jsonc-parser": "^2.3.1",
|
|
15
|
+
"typescript-template-language-service-decorator": "^2.3.1",
|
|
16
|
+
"vscode-languageserver-types": "^3.15.1",
|
|
17
|
+
"typescript": "5.5.4",
|
|
18
|
+
"tslib": "^2.6.2"
|
|
19
|
+
},
|
|
20
|
+
"devDependencies": {
|
|
21
|
+
"@player-tools/static-xlrs": "workspace:*"
|
|
22
|
+
},
|
|
23
|
+
"module": "dist/index.legacy-esm.js",
|
|
24
|
+
"types": "types/index.d.ts",
|
|
25
|
+
"exports": {
|
|
26
|
+
"./package.json": "./package.json",
|
|
27
|
+
"./dist/index.css": "./dist/index.css",
|
|
28
|
+
".": {
|
|
29
|
+
"types": "./types/index.d.ts",
|
|
30
|
+
"import": "./dist/index.mjs",
|
|
31
|
+
"default": "./dist/cjs/index.cjs"
|
|
32
|
+
}
|
|
33
|
+
},
|
|
34
|
+
"peerDependencies": {}
|
|
35
|
+
}
|
|
@@ -0,0 +1,470 @@
|
|
|
1
|
+
import { test, expect, describe, beforeEach } from "vitest";
|
|
2
|
+
import {
|
|
3
|
+
ReferenceAssetsWebPluginManifest,
|
|
4
|
+
Types,
|
|
5
|
+
} from "@player-tools/static-xlrs";
|
|
6
|
+
import {
|
|
7
|
+
PlayerLanguageService,
|
|
8
|
+
toTextDocument,
|
|
9
|
+
} from "@player-tools/json-language-service";
|
|
10
|
+
|
|
11
|
+
import { ComplexityCheck } from "../complexity-check";
|
|
12
|
+
|
|
13
|
+
describe("complexity plugin", () => {
|
|
14
|
+
let service: PlayerLanguageService;
|
|
15
|
+
|
|
16
|
+
beforeEach(async () => {
|
|
17
|
+
service = new PlayerLanguageService();
|
|
18
|
+
service.addLSPPlugin(
|
|
19
|
+
new ComplexityCheck({
|
|
20
|
+
maxAcceptableComplexity: 0,
|
|
21
|
+
options: { verbose: true },
|
|
22
|
+
})
|
|
23
|
+
);
|
|
24
|
+
await service.setAssetTypesFromModule([
|
|
25
|
+
Types,
|
|
26
|
+
ReferenceAssetsWebPluginManifest,
|
|
27
|
+
]);
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
test("Measures complexity for single view", async () => {
|
|
31
|
+
const textDocument = toTextDocument(
|
|
32
|
+
JSON.stringify({
|
|
33
|
+
id: "test",
|
|
34
|
+
views: [
|
|
35
|
+
{
|
|
36
|
+
id: "yes",
|
|
37
|
+
type: "info",
|
|
38
|
+
title: {
|
|
39
|
+
asset: {
|
|
40
|
+
id: "info-title",
|
|
41
|
+
type: "text",
|
|
42
|
+
value: "{{some.text}}",
|
|
43
|
+
},
|
|
44
|
+
},
|
|
45
|
+
subTitle: {
|
|
46
|
+
asset: {
|
|
47
|
+
id: "info-subTitle",
|
|
48
|
+
type: "text",
|
|
49
|
+
value: "@[somethingSubtitle]@",
|
|
50
|
+
},
|
|
51
|
+
},
|
|
52
|
+
},
|
|
53
|
+
],
|
|
54
|
+
navigation: {
|
|
55
|
+
BEGIN: "FLOW_1",
|
|
56
|
+
FLOW_1: {
|
|
57
|
+
startState: "ACTION_1",
|
|
58
|
+
ACTION_1: {
|
|
59
|
+
state_type: "ACTION",
|
|
60
|
+
exp: ["something"],
|
|
61
|
+
transitions: {
|
|
62
|
+
"*": "VIEW_1",
|
|
63
|
+
},
|
|
64
|
+
},
|
|
65
|
+
VIEW_1: {
|
|
66
|
+
state_type: "VIEW",
|
|
67
|
+
ref: "yes",
|
|
68
|
+
transitions: {
|
|
69
|
+
"*": "ACTION_2",
|
|
70
|
+
},
|
|
71
|
+
},
|
|
72
|
+
ACTION_2: {
|
|
73
|
+
state_type: "ACTION",
|
|
74
|
+
exp: ["{{somethingElse}} = 1", "something else"],
|
|
75
|
+
transitions: {
|
|
76
|
+
"*": "VIEW_1",
|
|
77
|
+
},
|
|
78
|
+
},
|
|
79
|
+
},
|
|
80
|
+
},
|
|
81
|
+
})
|
|
82
|
+
);
|
|
83
|
+
|
|
84
|
+
const validations = await service.validateTextDocument(textDocument);
|
|
85
|
+
expect(validations).toHaveLength(1);
|
|
86
|
+
/**
|
|
87
|
+
* Score break down
|
|
88
|
+
* 1 x for each view node (1 total) = 1
|
|
89
|
+
* 1 x from exps in ACTION states (3 total) = 3
|
|
90
|
+
* 1 x for each asset node (2 total) = 2
|
|
91
|
+
* 2 x for each expression (`2 total) = 4
|
|
92
|
+
* 2 x for each data evaluated (1 total) = 2
|
|
93
|
+
*/
|
|
94
|
+
expect(validations?.map((v) => v.message)).toMatchInlineSnapshot(`
|
|
95
|
+
[
|
|
96
|
+
"Error: Content complexity is 12",
|
|
97
|
+
]
|
|
98
|
+
`);
|
|
99
|
+
});
|
|
100
|
+
|
|
101
|
+
test("Measures complexity for evaluating nested bindings", async () => {
|
|
102
|
+
const textDocument = toTextDocument(
|
|
103
|
+
JSON.stringify({
|
|
104
|
+
id: "test",
|
|
105
|
+
views: [
|
|
106
|
+
{
|
|
107
|
+
id: "yes",
|
|
108
|
+
type: "info",
|
|
109
|
+
title: {
|
|
110
|
+
asset: {
|
|
111
|
+
id: "info-title",
|
|
112
|
+
type: "text",
|
|
113
|
+
value: "{{some.infoText}}",
|
|
114
|
+
},
|
|
115
|
+
},
|
|
116
|
+
subTitle: {
|
|
117
|
+
asset: {
|
|
118
|
+
id: "info-subTitle",
|
|
119
|
+
type: "text",
|
|
120
|
+
value: "@[something]@",
|
|
121
|
+
},
|
|
122
|
+
},
|
|
123
|
+
body: {
|
|
124
|
+
asset: {
|
|
125
|
+
id: "info-body",
|
|
126
|
+
type: "text",
|
|
127
|
+
value:
|
|
128
|
+
"@[conditional({{bar}} == true, {{foo}} = 1, {{foo}} = 2)]@",
|
|
129
|
+
},
|
|
130
|
+
},
|
|
131
|
+
},
|
|
132
|
+
],
|
|
133
|
+
navigation: {
|
|
134
|
+
BEGIN: "FLOW_1",
|
|
135
|
+
FLOW_1: {
|
|
136
|
+
startState: "ACTION_1",
|
|
137
|
+
ACTION_1: {
|
|
138
|
+
state_type: "ACTION",
|
|
139
|
+
exp: ["something"],
|
|
140
|
+
transitions: {
|
|
141
|
+
"*": "VIEW_1",
|
|
142
|
+
},
|
|
143
|
+
},
|
|
144
|
+
VIEW_1: {
|
|
145
|
+
onStart: [
|
|
146
|
+
"setDataVal('returns.IRS1040.Return.ReturnData.PPPerson.TaxpayerFilerInfoPP.FieldAttributes.PresidentialElectionCampaignIndPP.Covered', true)",
|
|
147
|
+
"dob = {{returns.IRS1040.Return.ReturnData.PPPerson.TaxpayerFilerInfoPP.DateOfBirthPP}}",
|
|
148
|
+
"dob_year = concat(dob[6], dob[7], dob[8], dob[9])",
|
|
149
|
+
"{{local.taxpayer.age}} = {{returns.IRS1040.Return.ReturnHeader.TaxYr}} - dob_year",
|
|
150
|
+
"conditional(dob == (concat('01/01/', year_18)), {{local.taxpayer.age}} = 18)",
|
|
151
|
+
],
|
|
152
|
+
state_type: "VIEW",
|
|
153
|
+
ref: "yes",
|
|
154
|
+
transitions: {
|
|
155
|
+
"*": "ACTION_2",
|
|
156
|
+
},
|
|
157
|
+
},
|
|
158
|
+
ACTION_2: {
|
|
159
|
+
state_type: "ACTION",
|
|
160
|
+
exp: ["{{something}} = 1", "something else"],
|
|
161
|
+
transitions: {
|
|
162
|
+
"*": "VIEW_2",
|
|
163
|
+
},
|
|
164
|
+
},
|
|
165
|
+
VIEW_2: {
|
|
166
|
+
state_type: "VIEW",
|
|
167
|
+
ref: "yes",
|
|
168
|
+
transitions: {
|
|
169
|
+
"*": "ACTION_3",
|
|
170
|
+
},
|
|
171
|
+
},
|
|
172
|
+
ACTION_3: {
|
|
173
|
+
state_type: "ACTION",
|
|
174
|
+
exp: ["{{something}} = 1", "something else"],
|
|
175
|
+
transitions: {
|
|
176
|
+
"*": "VIEW_1",
|
|
177
|
+
},
|
|
178
|
+
},
|
|
179
|
+
},
|
|
180
|
+
},
|
|
181
|
+
})
|
|
182
|
+
);
|
|
183
|
+
|
|
184
|
+
const validations = await service.validateTextDocument(textDocument);
|
|
185
|
+
expect(validations).toHaveLength(1);
|
|
186
|
+
/**
|
|
187
|
+
* Score break down
|
|
188
|
+
* 1 x for each view node (1 total) = 1
|
|
189
|
+
* 1 x from exps in ACTION states (5 total) = 5
|
|
190
|
+
* 1 x for each asset node (3 total) = 3
|
|
191
|
+
* 2 x for each expression (2 total) = 4
|
|
192
|
+
* 2 x for each data evaluated (10 total) = 20
|
|
193
|
+
*/
|
|
194
|
+
expect(validations?.map((v) => v.message)).toMatchInlineSnapshot(`
|
|
195
|
+
[
|
|
196
|
+
"Error: Content complexity is 33",
|
|
197
|
+
]
|
|
198
|
+
`);
|
|
199
|
+
});
|
|
200
|
+
|
|
201
|
+
test("Measures complexity for templates", async () => {
|
|
202
|
+
const textDocument = toTextDocument(
|
|
203
|
+
JSON.stringify({
|
|
204
|
+
id: "test",
|
|
205
|
+
views: [
|
|
206
|
+
{
|
|
207
|
+
id: "yes",
|
|
208
|
+
type: "info",
|
|
209
|
+
title: {
|
|
210
|
+
asset: {
|
|
211
|
+
id: "info-title",
|
|
212
|
+
type: "text",
|
|
213
|
+
value: "{{some.text}}",
|
|
214
|
+
},
|
|
215
|
+
},
|
|
216
|
+
template: [
|
|
217
|
+
{
|
|
218
|
+
data: "foo.pets",
|
|
219
|
+
output: "values",
|
|
220
|
+
value: {
|
|
221
|
+
asset: {
|
|
222
|
+
type: "collection",
|
|
223
|
+
id: "outer-collection-_index_",
|
|
224
|
+
template: [
|
|
225
|
+
{
|
|
226
|
+
data: "foo.people",
|
|
227
|
+
output: "values",
|
|
228
|
+
value: {
|
|
229
|
+
asset: {
|
|
230
|
+
id: "info-title-2",
|
|
231
|
+
type: "text",
|
|
232
|
+
value: "{{foo.people._index_}}",
|
|
233
|
+
},
|
|
234
|
+
},
|
|
235
|
+
},
|
|
236
|
+
],
|
|
237
|
+
},
|
|
238
|
+
},
|
|
239
|
+
},
|
|
240
|
+
],
|
|
241
|
+
data: {
|
|
242
|
+
foo: [1, 2],
|
|
243
|
+
},
|
|
244
|
+
},
|
|
245
|
+
],
|
|
246
|
+
navigation: {
|
|
247
|
+
BEGIN: "FLOW_1",
|
|
248
|
+
FLOW_1: {
|
|
249
|
+
startState: "ACTION_1",
|
|
250
|
+
ACTION_1: {
|
|
251
|
+
state_type: "ACTION",
|
|
252
|
+
exp: ["something"],
|
|
253
|
+
transitions: {
|
|
254
|
+
"*": "VIEW_1",
|
|
255
|
+
},
|
|
256
|
+
},
|
|
257
|
+
VIEW_1: {
|
|
258
|
+
state_type: "VIEW",
|
|
259
|
+
ref: "yes",
|
|
260
|
+
transitions: {
|
|
261
|
+
"*": "ACTION_2",
|
|
262
|
+
},
|
|
263
|
+
},
|
|
264
|
+
ACTION_2: {
|
|
265
|
+
state_type: "ACTION",
|
|
266
|
+
exp: ["{{somethingElse}} = 1", "something else"],
|
|
267
|
+
transitions: {
|
|
268
|
+
"*": "VIEW_1",
|
|
269
|
+
},
|
|
270
|
+
},
|
|
271
|
+
},
|
|
272
|
+
},
|
|
273
|
+
})
|
|
274
|
+
);
|
|
275
|
+
|
|
276
|
+
const validations = await service.validateTextDocument(textDocument);
|
|
277
|
+
expect(validations).toHaveLength(1);
|
|
278
|
+
/**
|
|
279
|
+
* Score break down
|
|
280
|
+
* 1 x for each view node (1 total) = 1
|
|
281
|
+
* 1 x from exps in ACTION states (3 total) = 3
|
|
282
|
+
* 1 x for each asset node (1 total) = 1
|
|
283
|
+
* 2 x for template asset (1 total) = 2
|
|
284
|
+
* 3 x for nested template asset (1 total) = 3
|
|
285
|
+
* 2 x for each expression (2 total) = 4
|
|
286
|
+
* 2 x for each data evaluated (1 total) = 2
|
|
287
|
+
*/
|
|
288
|
+
expect(validations?.map((v) => v.message)).toMatchInlineSnapshot(`
|
|
289
|
+
[
|
|
290
|
+
"Error: Content complexity is 16",
|
|
291
|
+
]
|
|
292
|
+
`);
|
|
293
|
+
});
|
|
294
|
+
|
|
295
|
+
test("Measures asset complexity", async () => {
|
|
296
|
+
let customService: PlayerLanguageService = new PlayerLanguageService();
|
|
297
|
+
|
|
298
|
+
customService = new PlayerLanguageService();
|
|
299
|
+
customService.addLSPPlugin(
|
|
300
|
+
new ComplexityCheck({
|
|
301
|
+
maxAcceptableComplexity: 0,
|
|
302
|
+
assetComplexity: { text: 1, info: 2, table: 5 },
|
|
303
|
+
options: { verbose: true },
|
|
304
|
+
})
|
|
305
|
+
);
|
|
306
|
+
await customService.setAssetTypesFromModule([
|
|
307
|
+
Types,
|
|
308
|
+
ReferenceAssetsWebPluginManifest,
|
|
309
|
+
]);
|
|
310
|
+
|
|
311
|
+
const textDocument = toTextDocument(
|
|
312
|
+
JSON.stringify({
|
|
313
|
+
id: "test",
|
|
314
|
+
views: [
|
|
315
|
+
{
|
|
316
|
+
id: "yes",
|
|
317
|
+
type: "info",
|
|
318
|
+
title: {
|
|
319
|
+
asset: {
|
|
320
|
+
id: "info-title",
|
|
321
|
+
type: "text",
|
|
322
|
+
value: "{{some.infoText}}",
|
|
323
|
+
},
|
|
324
|
+
},
|
|
325
|
+
subTitle: {
|
|
326
|
+
asset: {
|
|
327
|
+
id: "info-subTitle",
|
|
328
|
+
type: "text",
|
|
329
|
+
value: "@[something]@",
|
|
330
|
+
},
|
|
331
|
+
},
|
|
332
|
+
},
|
|
333
|
+
],
|
|
334
|
+
navigation: {
|
|
335
|
+
BEGIN: "FLOW_1",
|
|
336
|
+
FLOW_1: {
|
|
337
|
+
startState: "ACTION_1",
|
|
338
|
+
ACTION_1: {
|
|
339
|
+
state_type: "ACTION",
|
|
340
|
+
exp: ["something"],
|
|
341
|
+
transitions: {
|
|
342
|
+
"*": "VIEW_1",
|
|
343
|
+
},
|
|
344
|
+
},
|
|
345
|
+
VIEW_1: {
|
|
346
|
+
state_type: "VIEW",
|
|
347
|
+
ref: "yes",
|
|
348
|
+
transitions: {
|
|
349
|
+
"*": "ACTION_2",
|
|
350
|
+
},
|
|
351
|
+
},
|
|
352
|
+
ACTION_2: {
|
|
353
|
+
state_type: "ACTION",
|
|
354
|
+
exp: ["{{somethingElse}} = 1", "something else"],
|
|
355
|
+
transitions: {
|
|
356
|
+
"*": "VIEW_1",
|
|
357
|
+
},
|
|
358
|
+
},
|
|
359
|
+
},
|
|
360
|
+
},
|
|
361
|
+
})
|
|
362
|
+
);
|
|
363
|
+
|
|
364
|
+
const validations = await customService.validateTextDocument(textDocument);
|
|
365
|
+
expect(validations).toHaveLength(1);
|
|
366
|
+
/**
|
|
367
|
+
* Score break down
|
|
368
|
+
* 1 x for each view node (1 total) = 1
|
|
369
|
+
* 2 x for each view type = info (1 total) = 2
|
|
370
|
+
* 1 x from exps in ACTION states (3 total) = 3
|
|
371
|
+
* 1 x for each asset node (2 total) = 2
|
|
372
|
+
* 1 x for each asset type = text (2 total) = 2
|
|
373
|
+
* 2 x for each expression (2 total) = 4
|
|
374
|
+
* 2 x for each data evaluated (1 total) = 2
|
|
375
|
+
*/
|
|
376
|
+
expect(validations?.map((v) => v.message)).toMatchInlineSnapshot(`
|
|
377
|
+
[
|
|
378
|
+
"Error: Content complexity is 16",
|
|
379
|
+
]
|
|
380
|
+
`);
|
|
381
|
+
});
|
|
382
|
+
|
|
383
|
+
test("Outputs warning message correctly", async () => {
|
|
384
|
+
let customService: PlayerLanguageService = new PlayerLanguageService();
|
|
385
|
+
|
|
386
|
+
customService = new PlayerLanguageService();
|
|
387
|
+
customService.addLSPPlugin(
|
|
388
|
+
new ComplexityCheck({
|
|
389
|
+
maxAcceptableComplexity: 15,
|
|
390
|
+
maxWarningLevel: 10,
|
|
391
|
+
options: { verbose: true },
|
|
392
|
+
})
|
|
393
|
+
);
|
|
394
|
+
await customService.setAssetTypesFromModule([
|
|
395
|
+
Types,
|
|
396
|
+
ReferenceAssetsWebPluginManifest,
|
|
397
|
+
]);
|
|
398
|
+
|
|
399
|
+
const textDocument = toTextDocument(
|
|
400
|
+
JSON.stringify({
|
|
401
|
+
id: "test",
|
|
402
|
+
views: [
|
|
403
|
+
{
|
|
404
|
+
id: "yes",
|
|
405
|
+
type: "info",
|
|
406
|
+
title: {
|
|
407
|
+
asset: {
|
|
408
|
+
id: "info-title",
|
|
409
|
+
type: "text",
|
|
410
|
+
value: "{{some.infoText}}",
|
|
411
|
+
},
|
|
412
|
+
},
|
|
413
|
+
subTitle: {
|
|
414
|
+
asset: {
|
|
415
|
+
id: "info-subTitle",
|
|
416
|
+
type: "text",
|
|
417
|
+
value: "@[something]@",
|
|
418
|
+
},
|
|
419
|
+
},
|
|
420
|
+
},
|
|
421
|
+
],
|
|
422
|
+
navigation: {
|
|
423
|
+
BEGIN: "FLOW_1",
|
|
424
|
+
FLOW_1: {
|
|
425
|
+
startState: "ACTION_1",
|
|
426
|
+
ACTION_1: {
|
|
427
|
+
state_type: "ACTION",
|
|
428
|
+
exp: ["something"],
|
|
429
|
+
transitions: {
|
|
430
|
+
"*": "VIEW_1",
|
|
431
|
+
},
|
|
432
|
+
},
|
|
433
|
+
VIEW_1: {
|
|
434
|
+
state_type: "VIEW",
|
|
435
|
+
ref: "yes",
|
|
436
|
+
transitions: {
|
|
437
|
+
"*": "ACTION_2",
|
|
438
|
+
},
|
|
439
|
+
},
|
|
440
|
+
ACTION_2: {
|
|
441
|
+
state_type: "ACTION",
|
|
442
|
+
exp: ["{{somethingElse}} = 1", "something else"],
|
|
443
|
+
transitions: {
|
|
444
|
+
"*": "VIEW_1",
|
|
445
|
+
},
|
|
446
|
+
},
|
|
447
|
+
},
|
|
448
|
+
},
|
|
449
|
+
})
|
|
450
|
+
);
|
|
451
|
+
|
|
452
|
+
const validations = await customService.validateTextDocument(textDocument);
|
|
453
|
+
expect(validations).toHaveLength(1);
|
|
454
|
+
/**
|
|
455
|
+
* Score break down
|
|
456
|
+
* 1 x for each view node (1 total) = 1
|
|
457
|
+
* 2 x for each view type = info (1 total) = 2
|
|
458
|
+
* 1 x from exps in ACTION states (3 total) = 3
|
|
459
|
+
* 1 x for each asset node (2 total) = 2
|
|
460
|
+
* 1 x for each asset type = text (2 total) = 2
|
|
461
|
+
* 2 x for each expression (2 total) = 4
|
|
462
|
+
* 2 x for each data evaluated (1 total) = 2
|
|
463
|
+
*/
|
|
464
|
+
expect(validations?.map((v) => v.message)).toMatchInlineSnapshot(`
|
|
465
|
+
[
|
|
466
|
+
"Warning: Content complexity is 12",
|
|
467
|
+
]
|
|
468
|
+
`);
|
|
469
|
+
});
|
|
470
|
+
});
|