@featurevisor/core
Version:
Core package of Featurevisor for Node.js usage
387 lines • 14.1 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.listPlugin = void 0;
exports.listEntities = listEntities;
exports.listProject = listProject;
const matrix_1 = require("./matrix");
async function getEntitiesWithTests(deps) {
const { datasource } = deps;
const featuresWithTests = new Set();
const segmentsWithTests = new Set();
const tests = await datasource.listTests();
for (const testKey of tests) {
const test = await datasource.readTest(testKey);
if (test.feature) {
featuresWithTests.add(test.feature);
}
if (test.segment) {
segmentsWithTests.add(test.segment);
}
}
return {
features: Array.from(featuresWithTests),
segments: Array.from(segmentsWithTests),
};
}
async function listEntities(deps, entityType) {
const { datasource, options } = deps;
const result = [];
let entityKeys = [];
if (entityType === "feature") {
entityKeys = await datasource.listFeatures();
}
else if (entityType === "segment") {
entityKeys = await datasource.listSegments();
}
else if (entityType === "attribute") {
entityKeys = await datasource.listAttributes();
}
else if (entityType === "test") {
entityKeys = await datasource.listTests();
}
if (entityKeys.length === 0) {
return result;
}
let entitiesWithTests = {
features: [],
segments: [],
};
let entitiesWithTestsInitialized = false;
async function initializeEntitiesWithTests() {
if (entitiesWithTestsInitialized) {
return;
}
entitiesWithTests = await getEntitiesWithTests(deps);
entitiesWithTestsInitialized = true;
}
for (const key of entityKeys) {
let entity = {};
if (entityType === "feature") {
entity = (await datasource.readFeature(key));
}
else if (entityType === "segment") {
entity = (await datasource.readSegment(key));
}
else if (entityType === "attribute") {
entity = (await datasource.readAttribute(key));
}
else if (entityType === "test") {
entity = (await datasource.readTest(key));
}
// filter
if (entityType === "feature") {
const parsedFeature = entity;
// --archived=true|false
if (parsedFeature.archived) {
const archivedStatus = options.archived === "false";
if (parsedFeature.archived !== archivedStatus) {
continue;
}
}
// --description=<pattern>
if (options.description) {
const description = parsedFeature.description || "";
const regex = new RegExp(options.description, "i");
if (!regex.test(description)) {
continue;
}
}
// --disabledIn=<environment>
if (options.disabledIn && parsedFeature.rules && parsedFeature.rules[options.disabledIn]) {
const disabledInEnvironment = parsedFeature.rules[options.disabledIn].every((rule) => {
return rule.percentage === 0;
});
if (!disabledInEnvironment) {
continue;
}
}
// --enabledIn=<environment>
if (options.enabledIn && parsedFeature.rules && parsedFeature.rules[options.enabledIn]) {
const enabledInEnvironment = parsedFeature.rules[options.enabledIn].some((rule) => {
return rule.percentage > 0;
});
if (!enabledInEnvironment) {
continue;
}
}
// --keyPattern=<pattern>
if (options.keyPattern) {
const regex = new RegExp(options.keyPattern, "i");
if (!regex.test(key)) {
continue;
}
}
// --tag=<tag>
if (options.tag) {
const tags = Array.isArray(options.tag) ? options.tag : [options.tag];
const hasTags = tags.every((tag) => parsedFeature.tags.includes(tag));
if (!hasTags) {
continue;
}
}
// --variable=<variableKey>
if (options.variable) {
const lookForVariables = Array.isArray(options.variable)
? options.variable
: [options.variable];
let variablesInFeature = Object.keys(parsedFeature.variablesSchema || {});
const hasVariables = lookForVariables.every((variable) => variablesInFeature.includes(variable));
if (!hasVariables) {
continue;
}
}
// --variation=<variationValue>
if (options.variation) {
const lookForVariations = Array.isArray(options.variation)
? options.variation
: [options.variation];
let variationsInFeature = parsedFeature.variations
? parsedFeature.variations.map((v) => v.value)
: [];
const hasVariations = lookForVariations.every((variation) => variationsInFeature.includes(variation));
if (!hasVariations) {
continue;
}
}
// --with-tests
if (options.withTests) {
await initializeEntitiesWithTests();
if (!entitiesWithTests.features.includes(key)) {
continue;
}
}
// --with-variables
if (options.withVariables) {
const hasVariables = parsedFeature.variablesSchema;
if (!hasVariables) {
continue;
}
}
// --with-variations
if (options.withVariations) {
const hasVariations = parsedFeature.variations;
if (!hasVariations) {
continue;
}
}
// --without-tests
if (options.withoutTests) {
await initializeEntitiesWithTests();
if (entitiesWithTests.features.includes(key)) {
continue;
}
}
// --without-variables
if (options.withoutVariables) {
const hasVariables = parsedFeature.variablesSchema;
if (hasVariables) {
continue;
}
}
// --without-variations
if (options.withoutVariations) {
const hasVariations = parsedFeature.variations;
if (hasVariations) {
continue;
}
}
}
else if (entityType === "segment") {
const segment = entity;
// --archived=true|false
if (segment.archived) {
const archivedStatus = options.archived === "false";
if (segment.archived !== archivedStatus) {
continue;
}
}
// --description=<pattern>
if (options.description) {
const description = segment.description || "";
const regex = new RegExp(options.description, "i");
if (!regex.test(description)) {
continue;
}
}
// --keyPattern=<pattern>
if (options.keyPattern) {
const regex = new RegExp(options.keyPattern, "i");
if (!regex.test(key)) {
continue;
}
}
// --with-tests
if (options.withTests) {
await initializeEntitiesWithTests();
if (!entitiesWithTests.segments.includes(key)) {
continue;
}
}
// --without-tests
if (options.withoutTests) {
await initializeEntitiesWithTests();
if (entitiesWithTests.segments.includes(key)) {
continue;
}
}
}
else if (entityType === "attribute") {
const attribute = entity;
// --archived=true|false
if (options.archived) {
const archivedStatus = options.archived === "false";
if (attribute.archived !== archivedStatus) {
continue;
}
}
// --description=<pattern>
if (options.description) {
const description = attribute.description || "";
const regex = new RegExp(options.description, "i");
if (!regex.test(description)) {
continue;
}
}
// --keyPattern=<pattern>
if (options.keyPattern) {
const regex = new RegExp(options.keyPattern, "i");
if (!regex.test(key)) {
continue;
}
}
}
else if (entityType === "test") {
let test = entity;
const testEntityKey = test.feature || test.segment;
const testEntityType = test.segment ? "segment" : "feature";
let testAssertions = test.assertions;
// --entityType=<type>
if (options.entityType && options.entityType !== testEntityType) {
continue;
}
// --apply-matrix
if (options.applyMatrix) {
if (testEntityType === "feature") {
let assertionsAfterApplyingMatrix = [];
for (let aIndex = 0; aIndex < testAssertions.length; aIndex++) {
const processedAssertions = (0, matrix_1.getFeatureAssertionsFromMatrix)(aIndex, testAssertions[aIndex]);
assertionsAfterApplyingMatrix =
assertionsAfterApplyingMatrix.concat(processedAssertions);
}
testAssertions = assertionsAfterApplyingMatrix;
}
else if (testEntityType === "segment") {
let assertionsAfterApplyingMatrix = [];
for (let aIndex = 0; aIndex < testAssertions.length; aIndex++) {
const processedAssertions = (0, matrix_1.getSegmentAssertionsFromMatrix)(aIndex, testAssertions[aIndex]);
assertionsAfterApplyingMatrix =
assertionsAfterApplyingMatrix.concat(processedAssertions);
}
testAssertions = assertionsAfterApplyingMatrix;
}
}
// --keyPattern=<pattern>
if (options.keyPattern) {
const regex = new RegExp(options.keyPattern, "i");
if (!regex.test(testEntityKey)) {
continue;
}
}
// --assertionPattern=<pattern>
if (options.assertionPattern) {
const regex = new RegExp(options.assertionPattern, "i");
testAssertions = testAssertions.filter((assertion) => {
if (!assertion.description) {
return false;
}
return regex.test(assertion.description);
});
if (testAssertions.length === 0) {
continue;
}
}
entity.assertions = testAssertions;
}
result.push({
...entity,
key,
});
}
return result;
}
function ucfirst(str) {
return str.charAt(0).toUpperCase() + str.slice(1);
}
function printResult({ result, entityType, options }) {
if (options.json) {
console.log(options.pretty ? JSON.stringify(result, null, 2) : JSON.stringify(result));
return;
}
if (result.length === 0) {
console.log(`No ${entityType}s found.`);
return;
}
console.log(`\n${ucfirst(entityType)}s:\n`);
for (const item of result) {
console.log(`- ${item.key}`);
}
console.log(`\n\nFound ${result.length} ${entityType}s.`);
}
async function listProject(deps) {
const { options } = deps;
// features
if (options.features) {
const result = await listEntities(deps, "feature");
return printResult({
result,
entityType: "feature",
options,
});
}
// segments
if (options.segments) {
const result = await listEntities(deps, "segment");
return printResult({
result,
entityType: "segment",
options,
});
}
// attributes
if (options.attributes) {
const result = await listEntities(deps, "attribute");
return printResult({
result,
entityType: "attribute",
options,
});
}
// tests
if (options.tests) {
const result = await listEntities(deps, "test");
return printResult({
result,
entityType: "test",
options,
});
}
console.log("\nNothing to list. \n\nPlease pass `--features`, `--segments`, or `--attributes`.");
}
exports.listPlugin = {
command: "list",
handler: async function ({ rootDirectoryPath, projectConfig, datasource, parsed }) {
await listProject({
rootDirectoryPath,
projectConfig,
datasource,
options: parsed,
});
},
examples: [
{
command: "list",
description: "list entities",
},
],
};
//# sourceMappingURL=index.js.map