@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
package/lib/site/index.js CHANGED
@@ -1,19 +1,91 @@
1
1
  "use strict";
2
- var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
- if (k2 === undefined) k2 = k;
4
- var desc = Object.getOwnPropertyDescriptor(m, k);
5
- if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
- desc = { enumerable: true, get: function() { return m[k]; } };
2
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
+ return new (P || (P = Promise))(function (resolve, reject) {
5
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
6
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
7
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
8
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
9
+ });
10
+ };
11
+ var __generator = (this && this.__generator) || function (thisArg, body) {
12
+ var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;
13
+ return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
14
+ function verb(n) { return function (v) { return step([n, v]); }; }
15
+ function step(op) {
16
+ if (f) throw new TypeError("Generator is already executing.");
17
+ while (g && (g = 0, op[0] && (_ = 0)), _) try {
18
+ if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
19
+ if (y = 0, t) op = [op[0] & 2, t.value];
20
+ switch (op[0]) {
21
+ case 0: case 1: t = op; break;
22
+ case 4: _.label++; return { value: op[1], done: false };
23
+ case 5: _.label++; y = op[1]; op = [0]; continue;
24
+ case 7: op = _.ops.pop(); _.trys.pop(); continue;
25
+ default:
26
+ if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
27
+ if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
28
+ if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
29
+ if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
30
+ if (t[2]) _.ops.pop();
31
+ _.trys.pop(); continue;
32
+ }
33
+ op = body.call(thisArg, _);
34
+ } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
35
+ if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
7
36
  }
8
- Object.defineProperty(o, k2, desc);
9
- }) : (function(o, m, k, k2) {
10
- if (k2 === undefined) k2 = k;
11
- o[k2] = m[k];
12
- }));
13
- var __exportStar = (this && this.__exportStar) || function(m, exports) {
14
- for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
15
37
  };
16
38
  Object.defineProperty(exports, "__esModule", { value: true });
17
- __exportStar(require("./exportSite"), exports);
18
- __exportStar(require("./serveSite"), exports);
39
+ exports.sitePlugin = void 0;
40
+ var exportSite_1 = require("./exportSite");
41
+ var serveSite_1 = require("./serveSite");
42
+ exports.sitePlugin = {
43
+ command: "site [subcommand]",
44
+ handler: function (_a) {
45
+ var rootDirectoryPath = _a.rootDirectoryPath, projectConfig = _a.projectConfig, datasource = _a.datasource, parsed = _a.parsed;
46
+ return __awaiter(this, void 0, void 0, function () {
47
+ var deps, allowedSubcommands, hasError;
48
+ return __generator(this, function (_b) {
49
+ switch (_b.label) {
50
+ case 0:
51
+ deps = {
52
+ rootDirectoryPath: rootDirectoryPath,
53
+ projectConfig: projectConfig,
54
+ datasource: datasource,
55
+ options: parsed,
56
+ };
57
+ allowedSubcommands = ["export", "serve"];
58
+ if (!allowedSubcommands.includes(parsed.subcommand)) {
59
+ console.log("Please specify a subcommand: `export` or `serve`");
60
+ return [2 /*return*/];
61
+ }
62
+ if (!(parsed.subcommand === "export")) return [3 /*break*/, 2];
63
+ return [4 /*yield*/, (0, exportSite_1.exportSite)(deps)];
64
+ case 1:
65
+ hasError = _b.sent();
66
+ if (hasError) {
67
+ return [2 /*return*/, false];
68
+ }
69
+ _b.label = 2;
70
+ case 2:
71
+ // serve
72
+ if (parsed.subcommand === "serve") {
73
+ (0, serveSite_1.serveSite)(deps);
74
+ }
75
+ return [2 /*return*/];
76
+ }
77
+ });
78
+ });
79
+ },
80
+ examples: [
81
+ {
82
+ command: "site export",
83
+ description: "generate static site with project data",
84
+ },
85
+ {
86
+ command: "site serve",
87
+ description: "serve already exported site locally",
88
+ },
89
+ ],
90
+ };
19
91
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/site/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAAA,+CAA6B;AAC7B,8CAA4B"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/site/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AACA,2CAA0C;AAC1C,yCAAwC;AAE3B,QAAA,UAAU,GAAW;IAChC,OAAO,EAAE,mBAAmB;IAC5B,OAAO,EAAE,UAAgB,EAAwD;YAAtD,iBAAiB,uBAAA,EAAE,aAAa,mBAAA,EAAE,UAAU,gBAAA,EAAE,MAAM,YAAA;;;;;;wBACvE,IAAI,GAAG;4BACX,iBAAiB,mBAAA;4BACjB,aAAa,eAAA;4BACb,UAAU,YAAA;4BACV,OAAO,EAAE,MAAM;yBAChB,CAAC;wBAEI,kBAAkB,GAAG,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;wBAE/C,IAAI,CAAC,kBAAkB,CAAC,QAAQ,CAAC,MAAM,CAAC,UAAU,CAAC,EAAE;4BACnD,OAAO,CAAC,GAAG,CAAC,kDAAkD,CAAC,CAAC;4BAChE,sBAAO;yBACR;6BAGG,CAAA,MAAM,CAAC,UAAU,KAAK,QAAQ,CAAA,EAA9B,wBAA8B;wBACf,qBAAM,IAAA,uBAAU,EAAC,IAAI,CAAC,EAAA;;wBAAjC,QAAQ,GAAG,SAAsB;wBAEvC,IAAI,QAAQ,EAAE;4BACZ,sBAAO,KAAK,EAAC;yBACd;;;wBAGH,QAAQ;wBACR,IAAI,MAAM,CAAC,UAAU,KAAK,OAAO,EAAE;4BACjC,IAAA,qBAAS,EAAC,IAAI,CAAC,CAAC;yBACjB;;;;;KACF;IACD,QAAQ,EAAE;QACR;YACE,OAAO,EAAE,aAAa;YACtB,WAAW,EAAE,wCAAwC;SACtD;QACD;YACE,OAAO,EAAE,YAAY;YACrB,WAAW,EAAE,qCAAqC;SACnD;KACF;CACF,CAAC"}
@@ -1,5 +1,6 @@
1
1
  import { DatafileContent } from "@featurevisor/types";
2
2
  import { Dependencies } from "../dependencies";
3
+ import { Plugin } from "../cli";
3
4
  export interface TestProjectOptions {
4
5
  keyPattern?: string;
5
6
  assertionPattern?: string;
@@ -23,3 +24,4 @@ export interface DatafileContentByEnvironment {
23
24
  }
24
25
  export declare function executeTest(testFile: string, deps: Dependencies, options: TestProjectOptions, patterns: TestPatterns, datafileContentByEnvironment: DatafileContentByEnvironment): Promise<ExecutionResult | undefined>;
25
26
  export declare function testProject(deps: Dependencies, options?: TestProjectOptions): Promise<boolean>;
27
+ export declare const testPlugin: Plugin;
@@ -36,7 +36,7 @@ var __generator = (this && this.__generator) || function (thisArg, body) {
36
36
  }
37
37
  };
38
38
  Object.defineProperty(exports, "__esModule", { value: true });
39
- exports.testProject = exports.executeTest = void 0;
39
+ exports.testPlugin = exports.testProject = exports.executeTest = void 0;
40
40
  var fs = require("fs");
41
41
  var testSegment_1 = require("./testSegment");
42
42
  var testFeature_1 = require("./testFeature");
@@ -210,4 +210,55 @@ function testProject(deps, options) {
210
210
  });
211
211
  }
212
212
  exports.testProject = testProject;
213
+ exports.testPlugin = {
214
+ command: "test",
215
+ handler: function (_a) {
216
+ var rootDirectoryPath = _a.rootDirectoryPath, projectConfig = _a.projectConfig, datasource = _a.datasource, parsed = _a.parsed;
217
+ return __awaiter(this, void 0, void 0, function () {
218
+ var hasError;
219
+ return __generator(this, function (_b) {
220
+ switch (_b.label) {
221
+ case 0: return [4 /*yield*/, testProject({
222
+ rootDirectoryPath: rootDirectoryPath,
223
+ projectConfig: projectConfig,
224
+ datasource: datasource,
225
+ options: parsed,
226
+ }, parsed)];
227
+ case 1:
228
+ hasError = _b.sent();
229
+ if (hasError) {
230
+ return [2 /*return*/, false];
231
+ }
232
+ return [2 /*return*/];
233
+ }
234
+ });
235
+ });
236
+ },
237
+ examples: [
238
+ {
239
+ command: "test",
240
+ description: "run all tests",
241
+ },
242
+ {
243
+ command: "test --keyPattern=pattern",
244
+ description: "run tests matching key pattern",
245
+ },
246
+ {
247
+ command: "test --assertionPattern=pattern",
248
+ description: "run tests matching assertion pattern",
249
+ },
250
+ {
251
+ command: "test --onlyFailures",
252
+ description: "run only failed tests",
253
+ },
254
+ {
255
+ command: "test --showDatafile",
256
+ description: "show datafile content for each test",
257
+ },
258
+ {
259
+ command: "test --verbose",
260
+ description: "show all test results",
261
+ },
262
+ ],
263
+ };
213
264
  //# sourceMappingURL=testProject.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"testProject.js","sourceRoot":"","sources":["../../src/tester/testProject.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"testProject.js","sourceRoot":"","sources":["../../src/tester/testProject.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@featurevisor/core",
3
- "version": "1.25.0",
3
+ "version": "1.27.0",
4
4
  "description": "Core package of Featurevisor for Node.js usage",
5
5
  "main": "lib/index.js",
6
6
  "types": "lib/index.d.ts",
@@ -51,11 +51,12 @@
51
51
  "js-yaml": "^4.1.0",
52
52
  "mkdirp": "^2.1.3",
53
53
  "tar": "^6.1.13",
54
+ "yargs": "^17.7.2",
54
55
  "zod": "^3.22.4"
55
56
  },
56
57
  "devDependencies": {
57
58
  "@types/js-yaml": "^4.0.5",
58
59
  "@types/tar": "^6.1.4"
59
60
  },
60
- "gitHead": "4ba871333e577b6164af64e9d66955306fb0fc04"
61
+ "gitHead": "8b06b8f1bb33dd9a80988c013c91381c06c3b606"
61
62
  }
@@ -7,6 +7,7 @@ import { Dependencies } from "../dependencies";
7
7
  import { buildDatafile } from "../builder";
8
8
  import { SCHEMA_VERSION } from "../config";
9
9
  import { prettyPercentage, prettyNumber } from "../utils";
10
+ import { Plugin } from "../cli";
10
11
 
11
12
  const UUID_LENGTHS = [4, 2, 2, 2, 6];
12
13
 
@@ -165,3 +166,34 @@ export async function assessDistribution(deps: Dependencies, options: AssessDist
165
166
  printCounts(variationEvaluations, options.n);
166
167
  }
167
168
  }
169
+
170
+ export const assessDistributionPlugin: Plugin = {
171
+ command: "assess-distribution",
172
+ handler: async ({ rootDirectoryPath, projectConfig, datasource, parsed }) => {
173
+ await assessDistribution(
174
+ {
175
+ rootDirectoryPath,
176
+ projectConfig,
177
+ datasource,
178
+ options: parsed,
179
+ },
180
+ {
181
+ environment: parsed.environment,
182
+ feature: parsed.feature,
183
+ n: parseInt(parsed.n, 10) || 1,
184
+ context: parsed.context ? JSON.parse(parsed.context) : {},
185
+ populateUuid: Array.isArray(parsed.populateUuid)
186
+ ? parsed.populateUuid
187
+ : [parsed.populateUuid as string].filter(Boolean),
188
+ verbose: parsed.verbose,
189
+ },
190
+ );
191
+ },
192
+ examples: [
193
+ {
194
+ command:
195
+ "assess-distribution --environment=production --feature=my_feature --context='{}' --populateUuid=userId -n=100",
196
+ description: "test traffic distribution a feature against provided context",
197
+ },
198
+ ],
199
+ };
@@ -5,6 +5,7 @@ import { SCHEMA_VERSION } from "../config";
5
5
  import { buildDatafile } from "../builder";
6
6
  import { Dependencies } from "../dependencies";
7
7
  import { prettyDuration } from "../tester/prettyDuration";
8
+ import { Plugin } from "../cli";
8
9
 
9
10
  export interface BenchmarkOutput {
10
11
  value: any;
@@ -148,3 +149,42 @@ export async function benchmarkFeature(
148
149
  console.log(`Total duration : ${prettyDuration(output.duration)}`);
149
150
  console.log(`Average duration: ${prettyDuration(output.duration / options.n)}`);
150
151
  }
152
+
153
+ export const benchmarkPlugin: Plugin = {
154
+ command: "benchmark",
155
+ handler: async ({ rootDirectoryPath, projectConfig, datasource, parsed }) => {
156
+ await benchmarkFeature(
157
+ {
158
+ rootDirectoryPath,
159
+ projectConfig,
160
+ datasource,
161
+ options: parsed,
162
+ },
163
+ {
164
+ environment: parsed.environment,
165
+ feature: parsed.feature,
166
+ n: parseInt(parsed.n, 10) || 1,
167
+ context: parsed.context ? JSON.parse(parsed.context) : {},
168
+ variation: parsed.variation || undefined,
169
+ variable: parsed.variable || undefined,
170
+ },
171
+ );
172
+ },
173
+ examples: [
174
+ {
175
+ command:
176
+ 'benchmark --environment=production --feature=my_feature -n=1000 --context=\'{"userId": "123"}\'',
177
+ description: "Benchmark a feature flag",
178
+ },
179
+ {
180
+ command:
181
+ 'benchmark --environment=production --feature=my_feature -n=1000 --context=\'{"userId": "123"}\' --variation',
182
+ description: "Benchmark a feature variation",
183
+ },
184
+ {
185
+ command:
186
+ 'benchmark --environment=production --feature=my_feature -n=1000 --context=\'{"userId": "123"}\' --variable=my-variable',
187
+ description: "Benchmark a feature variable",
188
+ },
189
+ ],
190
+ };
@@ -3,6 +3,7 @@ import { SCHEMA_VERSION } from "../config";
3
3
  import { getNextRevision } from "./revision";
4
4
  import { buildDatafile, getCustomDatafile } from "./buildDatafile";
5
5
  import { Dependencies } from "../dependencies";
6
+ import { Plugin } from "../cli";
6
7
 
7
8
  export interface BuildCLIOptions {
8
9
  revision?: string;
@@ -12,6 +13,7 @@ export interface BuildCLIOptions {
12
13
  feature?: string;
13
14
  print?: boolean;
14
15
  pretty?: boolean;
16
+ stateFiles?: boolean; // --no-state-files in CLI
15
17
  }
16
18
 
17
19
  export async function buildProject(deps: Dependencies, cliOptions: BuildCLIOptions = {}) {
@@ -84,12 +86,55 @@ export async function buildProject(deps: Dependencies, cliOptions: BuildCLIOptio
84
86
  });
85
87
  }
86
88
 
87
- // write state for environment
88
- await datasource.writeState(environment, existingState);
89
+ if (typeof cliOptions.stateFiles === "undefined" || cliOptions.stateFiles) {
90
+ // write state for environment
91
+ await datasource.writeState(environment, existingState);
89
92
 
90
- // write revision
91
- await datasource.writeRevision(nextRevision);
93
+ // write revision
94
+ await datasource.writeRevision(nextRevision);
95
+ }
92
96
  }
93
97
 
94
98
  console.log("\nLatest revision:", nextRevision);
95
99
  }
100
+
101
+ export const buildPlugin: Plugin = {
102
+ command: "build",
103
+ handler: async function ({ rootDirectoryPath, projectConfig, datasource, parsed }) {
104
+ await buildProject(
105
+ {
106
+ rootDirectoryPath,
107
+ projectConfig,
108
+ datasource,
109
+ options: parsed,
110
+ },
111
+ parsed as BuildCLIOptions,
112
+ );
113
+ },
114
+ examples: [
115
+ {
116
+ command: "build",
117
+ description: "build datafiles for all environments and tags",
118
+ },
119
+ {
120
+ command: "build --revision=123",
121
+ description: "build datafiles starting with revision value as 123",
122
+ },
123
+ {
124
+ command: "build --environment=production",
125
+ description: "build datafiles for production environment",
126
+ },
127
+ {
128
+ command: "build --print --environment=production --feature=featureKey",
129
+ description: "print datafile for a feature in production environment",
130
+ },
131
+ {
132
+ command: "build --print --environment=production --pretty",
133
+ description: "print datafile with pretty print",
134
+ },
135
+ {
136
+ command: "build --no-state-files",
137
+ description: "build datafiles without writing state files",
138
+ },
139
+ ],
140
+ };
package/src/cli/cli.ts ADDED
@@ -0,0 +1,105 @@
1
+ import { ProjectConfig } from "../config";
2
+ import { Datasource } from "../datasource";
3
+
4
+ import { commonPlugins, nonProjectPlugins, projectBasedPlugins } from "./plugins";
5
+
6
+ export interface ParsedOptions {
7
+ _: string[];
8
+ [key: string]: any;
9
+ }
10
+
11
+ export interface PluginHandlerOptions {
12
+ rootDirectoryPath: string;
13
+ projectConfig: ProjectConfig;
14
+ datasource: Datasource;
15
+ parsed: ParsedOptions;
16
+ }
17
+
18
+ export interface Plugin {
19
+ command: string; // single word
20
+ handler: (options: PluginHandlerOptions) => Promise<void | boolean>;
21
+ examples: {
22
+ command: string; // full command usage
23
+ description: string;
24
+ }[];
25
+ }
26
+
27
+ export interface RunnerOptions {
28
+ rootDirectoryPath: string;
29
+
30
+ // optional because Featurevisor CLI can be used without a project
31
+ projectConfig?: ProjectConfig;
32
+ datasource?: Datasource;
33
+ }
34
+
35
+ export async function runCLI(runnerOptions: RunnerOptions) {
36
+ const yargs = require("yargs");
37
+
38
+ let y = yargs(process.argv.slice(2)).usage("Usage: <command> [options]");
39
+ const registeredSubcommands: string[] = [];
40
+
41
+ const { rootDirectoryPath, projectConfig, datasource } = runnerOptions;
42
+
43
+ function registerPlugin(plugin: Plugin) {
44
+ const subcommand = plugin.command.split(" ")[0];
45
+
46
+ if (registeredSubcommands.includes(subcommand)) {
47
+ console.warn(`Plugin "${subcommand}" already registered. Skipping.`);
48
+ return;
49
+ }
50
+
51
+ y = y.command({
52
+ command: plugin.command,
53
+ handler: async function (parsed: ParsedOptions) {
54
+ try {
55
+ const result = await plugin.handler({
56
+ rootDirectoryPath,
57
+ projectConfig,
58
+ datasource,
59
+ parsed,
60
+ } as PluginHandlerOptions);
61
+
62
+ if (result === false) {
63
+ process.exit(1);
64
+ }
65
+ } catch (error) {
66
+ console.error(error);
67
+ process.exit(1);
68
+ }
69
+ },
70
+ });
71
+
72
+ for (const example of plugin.examples) {
73
+ y = y.example(`$0 ${example.command}`, example.description);
74
+ }
75
+
76
+ registeredSubcommands.push(subcommand);
77
+ }
78
+
79
+ // non project-based plugins
80
+ if (!projectConfig) {
81
+ for (const plugin of nonProjectPlugins) {
82
+ registerPlugin(plugin);
83
+ }
84
+ }
85
+
86
+ // project-based plugins
87
+ if (projectConfig) {
88
+ for (const plugin of [...projectBasedPlugins, ...(projectConfig.plugins || [])]) {
89
+ registerPlugin(plugin);
90
+ }
91
+ }
92
+
93
+ // common plugins
94
+ for (const plugin of commonPlugins) {
95
+ registerPlugin(plugin);
96
+ }
97
+
98
+ // show help if no command is provided
99
+ y.command({
100
+ command: "*",
101
+ handler() {
102
+ y.showHelp();
103
+ },
104
+ }).argv;
105
+ }
@@ -0,0 +1,2 @@
1
+ export * from "./cli";
2
+ export * from "./plugins";
@@ -0,0 +1,38 @@
1
+ import type { Plugin } from "./cli";
2
+
3
+ import { initPlugin } from "../init";
4
+ import { lintPlugin } from "../linter";
5
+ import { buildPlugin } from "../builder";
6
+ import { restorePlugin } from "../restore";
7
+ import { testPlugin } from "../tester";
8
+ import { generateCodePlugin } from "../generate-code";
9
+ import { findDuplicateSegmentsPlugin } from "../find-duplicate-segments";
10
+ import { findUsagePlugin } from "../find-usage";
11
+ import { benchmarkPlugin } from "../benchmark";
12
+ import { configPlugin } from "../config";
13
+ import { evaluatePlugin } from "../evaluate";
14
+ import { assessDistributionPlugin } from "../assess-distribution";
15
+ import { infoPlugin } from "../info";
16
+ import { sitePlugin } from "../site";
17
+
18
+ // that do not require an existing project
19
+ export const nonProjectPlugins: Plugin[] = [initPlugin];
20
+
21
+ // that require an existing Featurevisor project
22
+ export const projectBasedPlugins: Plugin[] = [
23
+ lintPlugin,
24
+ buildPlugin,
25
+ restorePlugin,
26
+ testPlugin,
27
+ generateCodePlugin,
28
+ findDuplicateSegmentsPlugin,
29
+ findUsagePlugin,
30
+ benchmarkPlugin,
31
+ configPlugin,
32
+ evaluatePlugin,
33
+ assessDistributionPlugin,
34
+ infoPlugin,
35
+ sitePlugin,
36
+ ];
37
+
38
+ export const commonPlugins: Plugin[] = [];
@@ -4,6 +4,7 @@ import { BucketBy } from "@featurevisor/types";
4
4
 
5
5
  import { Parser, parsers } from "./parsers";
6
6
  import { FilesystemAdapter } from "../datasource/filesystemAdapter";
7
+ import type { Plugin } from "../cli";
7
8
 
8
9
  export const FEATURES_DIRECTORY_NAME = "features";
9
10
  export const SEGMENTS_DIRECTORY_NAME = "segments";
@@ -46,6 +47,7 @@ export interface ProjectConfig {
46
47
  siteExportDirectoryPath: string;
47
48
  enforceCatchAllRule?: boolean;
48
49
  adapter: any; // @TODO: type this properly later
50
+ plugins: Plugin[];
49
51
  }
50
52
 
51
53
  // rootDirectoryPath: path to the root directory of the project (without ending with a slash)
@@ -73,6 +75,7 @@ export function getProjectConfig(rootDirectoryPath: string): ProjectConfig {
73
75
  siteExportDirectoryPath: path.join(rootDirectoryPath, SITE_EXPORT_DIRECTORY_NAME),
74
76
 
75
77
  enforceCatchAllRule: false,
78
+ plugins: [],
76
79
  };
77
80
 
78
81
  const configModulePath = path.join(rootDirectoryPath, CONFIG_MODULE_NAME);
@@ -134,3 +137,28 @@ export function showProjectConfig(
134
137
  console.log(` - ${key.padEnd(longestKeyLength, " ")}: ${projectConfig[key]}`);
135
138
  }
136
139
  }
140
+
141
+ export const configPlugin: Plugin = {
142
+ command: "config",
143
+ handler: async ({ rootDirectoryPath, parsed }) => {
144
+ const projectConfig = getProjectConfig(rootDirectoryPath);
145
+ showProjectConfig(projectConfig, {
146
+ print: parsed.print,
147
+ pretty: parsed.pretty,
148
+ });
149
+ },
150
+ examples: [
151
+ {
152
+ command: "config",
153
+ description: "show the project configuration",
154
+ },
155
+ {
156
+ command: "config --print",
157
+ description: "show the project configuration as JSON",
158
+ },
159
+ {
160
+ command: "config --print --pretty",
161
+ description: "show the project configuration (as pretty JSON)",
162
+ },
163
+ ],
164
+ };
@@ -11,6 +11,7 @@ import {
11
11
  import { Dependencies } from "../dependencies";
12
12
  import { SCHEMA_VERSION } from "../config";
13
13
  import { buildDatafile } from "../builder";
14
+ import { Plugin } from "../cli";
14
15
 
15
16
  function printEvaluationDetails(evaluation: Evaluation) {
16
17
  const ignoreKeys = ["featureKey", "variableKey", "traffic", "force"];
@@ -191,3 +192,32 @@ export async function evaluateFeature(deps: Dependencies, options: EvaluateOptio
191
192
  console.log("No variables defined.");
192
193
  }
193
194
  }
195
+
196
+ export const evaluatePlugin: Plugin = {
197
+ command: "evaluate",
198
+ handler: async ({ rootDirectoryPath, projectConfig, datasource, parsed }) => {
199
+ await evaluateFeature(
200
+ {
201
+ rootDirectoryPath,
202
+ projectConfig,
203
+ datasource,
204
+ options: parsed,
205
+ },
206
+ {
207
+ environment: parsed.environment,
208
+ feature: parsed.feature,
209
+ context: parsed.context ? JSON.parse(parsed.context) : {},
210
+ print: parsed.print,
211
+ pretty: parsed.pretty,
212
+ verbose: parsed.verbose,
213
+ },
214
+ );
215
+ },
216
+ examples: [
217
+ {
218
+ command:
219
+ 'evaluate --environment=production --feature=my_feature --context=\'{"userId": "123"}\'',
220
+ description: "evaluate a feature against provided context",
221
+ },
222
+ ],
223
+ };