@featurevisor/core 1.25.0 → 1.27.0

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.
Files changed (91) hide show
  1. package/.eslintcache +1 -1
  2. package/CHANGELOG.md +22 -0
  3. package/coverage/clover.xml +2 -2
  4. package/coverage/lcov-report/index.html +1 -1
  5. package/coverage/lcov-report/lib/builder/allocator.js.html +1 -1
  6. package/coverage/lcov-report/lib/builder/index.html +1 -1
  7. package/coverage/lcov-report/lib/builder/revision.js.html +1 -1
  8. package/coverage/lcov-report/lib/builder/traffic.js.html +1 -1
  9. package/coverage/lcov-report/lib/tester/checkIfObjectsAreEqual.js.html +1 -1
  10. package/coverage/lcov-report/lib/tester/index.html +1 -1
  11. package/coverage/lcov-report/lib/tester/matrix.js.html +1 -1
  12. package/coverage/lcov-report/src/builder/allocator.ts.html +1 -1
  13. package/coverage/lcov-report/src/builder/index.html +1 -1
  14. package/coverage/lcov-report/src/builder/revision.ts.html +1 -1
  15. package/coverage/lcov-report/src/builder/traffic.ts.html +1 -1
  16. package/coverage/lcov-report/src/tester/checkIfObjectsAreEqual.ts.html +1 -1
  17. package/coverage/lcov-report/src/tester/index.html +1 -1
  18. package/coverage/lcov-report/src/tester/matrix.ts.html +1 -1
  19. package/lib/assess-distribution/index.d.ts +2 -0
  20. package/lib/assess-distribution/index.js +37 -1
  21. package/lib/assess-distribution/index.js.map +1 -1
  22. package/lib/benchmark/index.d.ts +2 -0
  23. package/lib/benchmark/index.js +43 -1
  24. package/lib/benchmark/index.js.map +1 -1
  25. package/lib/builder/buildProject.d.ts +3 -0
  26. package/lib/builder/buildProject.js +52 -4
  27. package/lib/builder/buildProject.js.map +1 -1
  28. package/lib/cli/cli.d.ts +26 -0
  29. package/lib/cli/cli.js +133 -0
  30. package/lib/cli/cli.js.map +1 -0
  31. package/lib/cli/index.d.ts +2 -0
  32. package/lib/cli/index.js +19 -0
  33. package/lib/cli/index.js.map +1 -0
  34. package/lib/cli/plugins.d.ts +4 -0
  35. package/lib/cli/plugins.js +37 -0
  36. package/lib/cli/plugins.js.map +1 -0
  37. package/lib/config/projectConfig.d.ts +3 -0
  38. package/lib/config/projectConfig.js +69 -1
  39. package/lib/config/projectConfig.js.map +1 -1
  40. package/lib/evaluate/index.d.ts +2 -0
  41. package/lib/evaluate/index.js +35 -1
  42. package/lib/evaluate/index.js.map +1 -1
  43. package/lib/find-duplicate-segments/index.d.ts +2 -0
  44. package/lib/find-duplicate-segments/index.js +34 -1
  45. package/lib/find-duplicate-segments/index.js.map +1 -1
  46. package/lib/find-usage/index.d.ts +2 -0
  47. package/lib/find-usage/index.js +50 -1
  48. package/lib/find-usage/index.js.map +1 -1
  49. package/lib/generate-code/index.d.ts +2 -0
  50. package/lib/generate-code/index.js +31 -1
  51. package/lib/generate-code/index.js.map +1 -1
  52. package/lib/index.d.ts +1 -0
  53. package/lib/index.js +1 -0
  54. package/lib/index.js.map +1 -1
  55. package/lib/info/index.d.ts +2 -0
  56. package/lib/info/index.js +28 -1
  57. package/lib/info/index.js.map +1 -1
  58. package/lib/init/index.d.ts +2 -0
  59. package/lib/init/index.js +65 -1
  60. package/lib/init/index.js.map +1 -1
  61. package/lib/linter/lintProject.d.ts +2 -0
  62. package/lib/linter/lintProject.js +56 -1
  63. package/lib/linter/lintProject.js.map +1 -1
  64. package/lib/restore/index.d.ts +2 -0
  65. package/lib/restore/index.js +28 -1
  66. package/lib/restore/index.js.map +1 -1
  67. package/lib/site/index.d.ts +2 -2
  68. package/lib/site/index.js +86 -14
  69. package/lib/site/index.js.map +1 -1
  70. package/lib/tester/testProject.d.ts +2 -0
  71. package/lib/tester/testProject.js +52 -1
  72. package/lib/tester/testProject.js.map +1 -1
  73. package/package.json +3 -2
  74. package/src/assess-distribution/index.ts +32 -0
  75. package/src/benchmark/index.ts +40 -0
  76. package/src/builder/buildProject.ts +49 -4
  77. package/src/cli/cli.ts +105 -0
  78. package/src/cli/index.ts +2 -0
  79. package/src/cli/plugins.ts +38 -0
  80. package/src/config/projectConfig.ts +28 -0
  81. package/src/evaluate/index.ts +30 -0
  82. package/src/find-duplicate-segments/index.ts +28 -0
  83. package/src/find-usage/index.ts +44 -0
  84. package/src/generate-code/index.ts +25 -0
  85. package/src/index.ts +1 -0
  86. package/src/info/index.ts +19 -0
  87. package/src/init/index.ts +21 -0
  88. package/src/linter/lintProject.ts +51 -0
  89. package/src/restore/index.ts +19 -0
  90. package/src/site/index.ts +46 -2
  91. package/src/tester/testProject.ts +46 -0
@@ -1,5 +1,6 @@
1
1
  import { findDuplicateSegments, DuplicateSegmentsOptions } from "./findDuplicateSegments";
2
2
  import { Dependencies } from "../dependencies";
3
+ import { Plugin } from "../cli";
3
4
 
4
5
  export async function findDuplicateSegmentsInProject(
5
6
  deps: Dependencies,
@@ -26,3 +27,30 @@ export async function findDuplicateSegmentsInProject(
26
27
  }
27
28
  });
28
29
  }
30
+
31
+ export const findDuplicateSegmentsPlugin: Plugin = {
32
+ command: "find-duplicate-segments",
33
+ handler: async ({ rootDirectoryPath, projectConfig, datasource, parsed }) => {
34
+ await findDuplicateSegmentsInProject(
35
+ {
36
+ rootDirectoryPath,
37
+ projectConfig,
38
+ datasource,
39
+ options: parsed,
40
+ },
41
+ {
42
+ authors: parsed.authors,
43
+ },
44
+ );
45
+ },
46
+ examples: [
47
+ {
48
+ command: "find-duplicate-segments",
49
+ description: "Find duplicate segments in the project",
50
+ },
51
+ {
52
+ command: "find-duplicate-segments --authors",
53
+ description: "Find duplicate segments in the project and list authors",
54
+ },
55
+ ],
56
+ };
@@ -1,6 +1,7 @@
1
1
  import { Condition, FeatureKey, SegmentKey, AttributeKey } from "@featurevisor/types";
2
2
 
3
3
  import { Dependencies } from "../dependencies";
4
+ import { Plugin } from "../cli";
4
5
  import {
5
6
  extractAttributeKeysFromConditions,
6
7
  extractSegmentKeysFromGroupSegments,
@@ -371,3 +372,46 @@ export async function findUsageInProject(deps: Dependencies, options: FindUsageO
371
372
 
372
373
  console.log("Please specify a segment or attribute.");
373
374
  }
375
+
376
+ export const findUsagePlugin: Plugin = {
377
+ command: "find-usage",
378
+ handler: async ({ rootDirectoryPath, projectConfig, datasource, parsed }) => {
379
+ await findUsageInProject(
380
+ {
381
+ rootDirectoryPath,
382
+ projectConfig,
383
+ datasource,
384
+ options: parsed,
385
+ },
386
+ {
387
+ segment: parsed.segment,
388
+ attribute: parsed.attribute,
389
+ unusedSegments: parsed.unusedSegments,
390
+ unusedAttributes: parsed.unusedAttributes,
391
+ authors: parsed.authors,
392
+ },
393
+ );
394
+ },
395
+ examples: [
396
+ {
397
+ command: "find-usage --segment=<segmentKey>",
398
+ description: "Find usage of a segment",
399
+ },
400
+ {
401
+ command: "find-usage --attribute=<attributeKey>",
402
+ description: "Find usage of an attribute",
403
+ },
404
+ {
405
+ command: "find-usage --unused-segments",
406
+ description: "Find unused segments",
407
+ },
408
+ {
409
+ command: "find-usage --unused-attributes",
410
+ description: "Find unused attributes",
411
+ },
412
+ {
413
+ command: "find-usage --authors",
414
+ description: "List authors of the usage",
415
+ },
416
+ ],
417
+ };
@@ -5,6 +5,7 @@ import * as mkdirp from "mkdirp";
5
5
 
6
6
  import { generateTypeScriptCodeForProject } from "./typescript";
7
7
  import { Dependencies } from "../dependencies";
8
+ import { Plugin } from "../cli";
8
9
 
9
10
  export const ALLOWED_LANGUAGES_FOR_CODE_GENERATION = ["typescript"];
10
11
 
@@ -50,3 +51,27 @@ export async function generateCodeForProject(
50
51
 
51
52
  throw new Error(`Language ${cliOptions.language} is not supported`);
52
53
  }
54
+
55
+ export const generateCodePlugin: Plugin = {
56
+ command: "generate-code",
57
+ handler: async function ({ rootDirectoryPath, projectConfig, datasource, parsed }) {
58
+ await generateCodeForProject(
59
+ {
60
+ rootDirectoryPath,
61
+ projectConfig,
62
+ datasource,
63
+ options: parsed,
64
+ },
65
+ {
66
+ language: parsed.language,
67
+ outDir: parsed.outDir,
68
+ },
69
+ );
70
+ },
71
+ examples: [
72
+ {
73
+ command: "generate-code --language typescript --out-dir src/generated",
74
+ description: "Generate TypeScript code for the project",
75
+ },
76
+ ],
77
+ };
package/src/index.ts CHANGED
@@ -14,3 +14,4 @@ export * from "./benchmark";
14
14
  export * from "./evaluate";
15
15
  export * from "./assess-distribution";
16
16
  export * from "./info";
17
+ export * from "./cli";
package/src/info/index.ts CHANGED
@@ -1,5 +1,6 @@
1
1
  import { Dependencies } from "../dependencies";
2
2
  import { getMatrixCombinations } from "../tester/matrix";
3
+ import { Plugin } from "../cli";
3
4
 
4
5
  export async function showProjectInfo(deps: Dependencies) {
5
6
  const { datasource } = deps;
@@ -52,3 +53,21 @@ export async function showProjectInfo(deps: Dependencies) {
52
53
 
53
54
  console.log(" - Total assertions: ", assertionsCount);
54
55
  }
56
+
57
+ export const infoPlugin: Plugin = {
58
+ command: "info",
59
+ handler: async function ({ rootDirectoryPath, projectConfig, datasource, parsed }) {
60
+ await showProjectInfo({
61
+ rootDirectoryPath,
62
+ projectConfig,
63
+ datasource,
64
+ options: parsed,
65
+ });
66
+ },
67
+ examples: [
68
+ {
69
+ command: "info",
70
+ description: "show various stats for the project",
71
+ },
72
+ ],
73
+ };
package/src/init/index.ts CHANGED
@@ -1,6 +1,8 @@
1
1
  import axios from "axios";
2
2
  import * as tar from "tar";
3
3
 
4
+ import { Plugin } from "../cli";
5
+
4
6
  export const DEFAULT_EXAMPLE = "example-yml";
5
7
 
6
8
  export const EXAMPLES_ORG_NAME = "fahad19";
@@ -42,3 +44,22 @@ export function initProject(
42
44
  });
43
45
  });
44
46
  }
47
+
48
+ export const initPlugin: Plugin = {
49
+ command: "init",
50
+ handler: async function (options) {
51
+ const { rootDirectoryPath, parsed } = options;
52
+
53
+ await initProject(rootDirectoryPath, parsed.example);
54
+ },
55
+ examples: [
56
+ {
57
+ command: "init",
58
+ description: "scaffold a new project in current directory",
59
+ },
60
+ {
61
+ command: "init --example=exampleName",
62
+ description: "scaffold a new project in current directory from known example",
63
+ },
64
+ ],
65
+ };
@@ -13,6 +13,7 @@ import { checkForFeatureExceedingGroupSlotPercentage } from "./checkPercentageEx
13
13
  import { printZodError } from "./printError";
14
14
  import { Dependencies } from "../dependencies";
15
15
  import { CLI_FORMAT_RED, CLI_FORMAT_UNDERLINE } from "../tester/cliFormat";
16
+ import { Plugin } from "../cli";
16
17
 
17
18
  export interface LintProjectOptions {
18
19
  keyPattern?: string;
@@ -340,3 +341,53 @@ export async function lintProject(
340
341
 
341
342
  return hasError;
342
343
  }
344
+
345
+ export const lintPlugin: Plugin = {
346
+ command: "lint",
347
+ handler: async function (options) {
348
+ const { rootDirectoryPath, projectConfig, datasource, parsed } = options;
349
+
350
+ const hasError = await lintProject(
351
+ {
352
+ rootDirectoryPath,
353
+ projectConfig,
354
+ datasource,
355
+ options: parsed,
356
+ },
357
+ {
358
+ keyPattern: parsed.keyPattern,
359
+ entityType: parsed.entityType,
360
+ },
361
+ );
362
+
363
+ if (hasError) {
364
+ return false;
365
+ }
366
+ },
367
+ examples: [
368
+ {
369
+ command: "lint",
370
+ description: "lint all entities",
371
+ },
372
+ {
373
+ command: "lint --entityType=feature",
374
+ description: "lint only features",
375
+ },
376
+ {
377
+ command: "lint --entityType=segment",
378
+ description: "lint only segments",
379
+ },
380
+ {
381
+ command: "lint --entityType=group",
382
+ description: "lint only groups",
383
+ },
384
+ {
385
+ command: "lint --entityType=test",
386
+ description: "lint only tests",
387
+ },
388
+ {
389
+ command: 'lint --keyPattern="abc"',
390
+ description: `lint only entities with keys containing "abc"`,
391
+ },
392
+ ],
393
+ };
@@ -2,6 +2,7 @@ import * as path from "path";
2
2
  import { execSync } from "child_process";
3
3
 
4
4
  import { Dependencies } from "../dependencies";
5
+ import { Plugin } from "../cli";
5
6
 
6
7
  export async function restoreProject(deps: Dependencies) {
7
8
  const { rootDirectoryPath, projectConfig } = deps;
@@ -21,3 +22,21 @@ export async function restoreProject(deps: Dependencies) {
21
22
  throw new Error("Failed to restore state files.");
22
23
  }
23
24
  }
25
+
26
+ export const restorePlugin: Plugin = {
27
+ command: "restore",
28
+ handler: async function ({ rootDirectoryPath, projectConfig, datasource, parsed }) {
29
+ await restoreProject({
30
+ rootDirectoryPath,
31
+ projectConfig,
32
+ datasource,
33
+ options: parsed,
34
+ });
35
+ },
36
+ examples: [
37
+ {
38
+ command: "restore",
39
+ description: "restore state files",
40
+ },
41
+ ],
42
+ };
package/src/site/index.ts CHANGED
@@ -1,2 +1,46 @@
1
- export * from "./exportSite";
2
- export * from "./serveSite";
1
+ import { Plugin } from "../cli";
2
+ import { exportSite } from "./exportSite";
3
+ import { serveSite } from "./serveSite";
4
+
5
+ export const sitePlugin: Plugin = {
6
+ command: "site [subcommand]",
7
+ handler: async function ({ rootDirectoryPath, projectConfig, datasource, parsed }) {
8
+ const deps = {
9
+ rootDirectoryPath,
10
+ projectConfig,
11
+ datasource,
12
+ options: parsed,
13
+ };
14
+
15
+ const allowedSubcommands = ["export", "serve"];
16
+
17
+ if (!allowedSubcommands.includes(parsed.subcommand)) {
18
+ console.log("Please specify a subcommand: `export` or `serve`");
19
+ return;
20
+ }
21
+
22
+ // export
23
+ if (parsed.subcommand === "export") {
24
+ const hasError = await exportSite(deps);
25
+
26
+ if (hasError) {
27
+ return false;
28
+ }
29
+ }
30
+
31
+ // serve
32
+ if (parsed.subcommand === "serve") {
33
+ serveSite(deps);
34
+ }
35
+ },
36
+ examples: [
37
+ {
38
+ command: "site export",
39
+ description: "generate static site with project data",
40
+ },
41
+ {
42
+ command: "site serve",
43
+ description: "serve already exported site locally",
44
+ },
45
+ ],
46
+ };
@@ -11,6 +11,7 @@ import { printTestResult } from "./printTestResult";
11
11
 
12
12
  import { buildDatafile } from "../builder";
13
13
  import { SCHEMA_VERSION } from "../config";
14
+ import { Plugin } from "../cli";
14
15
 
15
16
  export interface TestProjectOptions {
16
17
  keyPattern?: string;
@@ -211,3 +212,48 @@ export async function testProject(
211
212
 
212
213
  return hasError;
213
214
  }
215
+
216
+ export const testPlugin: Plugin = {
217
+ command: "test",
218
+ handler: async function ({ rootDirectoryPath, projectConfig, datasource, parsed }) {
219
+ const hasError = await testProject(
220
+ {
221
+ rootDirectoryPath,
222
+ projectConfig,
223
+ datasource,
224
+ options: parsed,
225
+ },
226
+ parsed as TestProjectOptions,
227
+ );
228
+
229
+ if (hasError) {
230
+ return false;
231
+ }
232
+ },
233
+ examples: [
234
+ {
235
+ command: "test",
236
+ description: "run all tests",
237
+ },
238
+ {
239
+ command: "test --keyPattern=pattern",
240
+ description: "run tests matching key pattern",
241
+ },
242
+ {
243
+ command: "test --assertionPattern=pattern",
244
+ description: "run tests matching assertion pattern",
245
+ },
246
+ {
247
+ command: "test --onlyFailures",
248
+ description: "run only failed tests",
249
+ },
250
+ {
251
+ command: "test --showDatafile",
252
+ description: "show datafile content for each test",
253
+ },
254
+ {
255
+ command: "test --verbose",
256
+ description: "show all test results",
257
+ },
258
+ ],
259
+ };