@featurevisor/core 2.17.0 → 2.19.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.
- package/CHANGELOG.md +22 -0
- package/coverage/clover.xml +1692 -1196
- package/coverage/coverage-final.json +29 -22
- package/coverage/lcov-report/builder/allocator.ts.html +26 -26
- package/coverage/lcov-report/builder/buildDatafile.ts.html +2017 -0
- package/coverage/lcov-report/builder/buildScopedConditions.ts.html +35 -35
- package/coverage/lcov-report/builder/buildScopedDatafile.ts.html +213 -45
- package/coverage/lcov-report/builder/buildScopedSegments.ts.html +28 -28
- package/coverage/lcov-report/builder/convertToV1.ts.html +583 -0
- package/coverage/lcov-report/builder/getFeatureRanges.ts.html +268 -0
- package/coverage/lcov-report/builder/hashes.ts.html +412 -0
- package/coverage/lcov-report/builder/index.html +90 -30
- package/coverage/lcov-report/builder/mutateVariables.ts.html +66 -45
- package/coverage/lcov-report/builder/mutator.ts.html +95 -95
- package/coverage/lcov-report/builder/revision.ts.html +1 -1
- package/coverage/lcov-report/builder/traffic.ts.html +60 -57
- package/coverage/lcov-report/config/index.html +1 -1
- package/coverage/lcov-report/config/index.ts.html +2 -2
- package/coverage/lcov-report/config/projectConfig.ts.html +28 -28
- package/coverage/lcov-report/datasource/adapter.ts.html +2 -2
- package/coverage/lcov-report/datasource/datasource.ts.html +4 -4
- package/coverage/lcov-report/datasource/filesystemAdapter.ts.html +34 -34
- package/coverage/lcov-report/datasource/index.html +1 -1
- package/coverage/lcov-report/datasource/index.ts.html +1 -1
- package/coverage/lcov-report/index.html +39 -39
- package/coverage/lcov-report/linter/attributeSchema.ts.html +1 -1
- package/coverage/lcov-report/linter/checkCircularDependency.ts.html +1 -1
- package/coverage/lcov-report/linter/checkPercentageExceedingSlot.ts.html +1 -1
- package/coverage/lcov-report/linter/conditionSchema.ts.html +17 -17
- package/coverage/lcov-report/linter/featureSchema.ts.html +879 -417
- package/coverage/lcov-report/linter/groupSchema.ts.html +1 -1
- package/coverage/lcov-report/linter/index.html +34 -34
- package/coverage/lcov-report/linter/lintProject.ts.html +25 -25
- package/coverage/lcov-report/linter/mutationNotation.ts.html +224 -122
- package/coverage/lcov-report/linter/printError.ts.html +1 -1
- package/coverage/lcov-report/linter/schema.ts.html +175 -85
- package/coverage/lcov-report/linter/segmentSchema.ts.html +1 -1
- package/coverage/lcov-report/linter/testSchema.ts.html +5 -5
- package/coverage/lcov-report/list/index.html +1 -1
- package/coverage/lcov-report/list/matrix.ts.html +1 -1
- package/coverage/lcov-report/parsers/index.html +1 -1
- package/coverage/lcov-report/parsers/index.ts.html +4 -4
- package/coverage/lcov-report/parsers/json.ts.html +2 -2
- package/coverage/lcov-report/parsers/yml.ts.html +6 -6
- package/coverage/lcov-report/tester/cliFormat.ts.html +1 -1
- package/coverage/lcov-report/tester/helpers.ts.html +1 -1
- package/coverage/lcov-report/tester/index.html +1 -1
- package/coverage/lcov-report/utils/extractKeys.ts.html +493 -0
- package/coverage/lcov-report/utils/git.ts.html +3 -3
- package/coverage/lcov-report/utils/index.html +54 -9
- package/coverage/lcov-report/utils/index.ts.html +94 -0
- package/coverage/lcov-report/utils/pretty.ts.html +121 -0
- package/coverage/lcov.info +3206 -2260
- package/json-schema/attribute.json +25 -9
- package/json-schema/feature.json +319 -238
- package/json-schema/segment.json +76 -45
- package/lib/builder/buildDatafile.js +50 -3
- package/lib/builder/buildDatafile.js.map +1 -1
- package/lib/builder/buildDatafile.spec.d.ts +1 -0
- package/lib/builder/buildDatafile.spec.js +233 -0
- package/lib/builder/buildDatafile.spec.js.map +1 -0
- package/lib/builder/buildScopedDatafile.js +37 -1
- package/lib/builder/buildScopedDatafile.js.map +1 -1
- package/lib/builder/buildScopedDatafile.spec.js +289 -0
- package/lib/builder/buildScopedDatafile.spec.js.map +1 -1
- package/lib/builder/mutateVariables.d.ts +1 -1
- package/lib/builder/mutateVariables.js +4 -1
- package/lib/builder/mutateVariables.js.map +1 -1
- package/lib/builder/mutateVariables.spec.js +29 -0
- package/lib/builder/mutateVariables.spec.js.map +1 -1
- package/lib/builder/traffic.js +1 -0
- package/lib/builder/traffic.js.map +1 -1
- package/lib/builder/traffic.spec.js +26 -0
- package/lib/builder/traffic.spec.js.map +1 -1
- package/lib/generate-code/typescript.js +63 -20
- package/lib/generate-code/typescript.js.map +1 -1
- package/lib/linter/featureSchema.d.ts +237 -22
- package/lib/linter/featureSchema.js +175 -84
- package/lib/linter/featureSchema.js.map +1 -1
- package/lib/linter/featureSchema.spec.js +268 -0
- package/lib/linter/featureSchema.spec.js.map +1 -1
- package/lib/linter/mutationNotation.js +54 -19
- package/lib/linter/mutationNotation.js.map +1 -1
- package/lib/linter/mutationNotation.spec.js +49 -0
- package/lib/linter/mutationNotation.spec.js.map +1 -1
- package/lib/linter/schema.d.ts +1 -0
- package/lib/linter/schema.js +13 -0
- package/lib/linter/schema.js.map +1 -1
- package/lib/linter/schema.spec.js +51 -0
- package/lib/linter/schema.spec.js.map +1 -1
- package/package.json +5 -5
- package/src/builder/buildDatafile.spec.ts +267 -0
- package/src/builder/buildDatafile.ts +85 -4
- package/src/builder/buildScopedDatafile.spec.ts +330 -0
- package/src/builder/buildScopedDatafile.ts +57 -1
- package/src/builder/mutateVariables.spec.ts +45 -0
- package/src/builder/mutateVariables.ts +7 -0
- package/src/builder/traffic.spec.ts +33 -0
- package/src/builder/traffic.ts +1 -0
- package/src/generate-code/typescript.ts +87 -20
- package/src/linter/featureSchema.spec.ts +315 -0
- package/src/linter/featureSchema.ts +269 -115
- package/src/linter/mutationNotation.spec.ts +62 -0
- package/src/linter/mutationNotation.ts +47 -13
- package/src/linter/schema.spec.ts +72 -0
- package/src/linter/schema.ts +30 -0
|
@@ -610,6 +610,34 @@ describe("featureSchema.ts :: getFeatureZodSchema (variablesSchema and variable
|
|
|
610
610
|
"maxLength",
|
|
611
611
|
);
|
|
612
612
|
});
|
|
613
|
+
|
|
614
|
+
it("accepts plain-key partial object overrides for structured object schemas", () => {
|
|
615
|
+
expectParseSuccess(
|
|
616
|
+
baseFeature({
|
|
617
|
+
variablesSchema: {
|
|
618
|
+
config: {
|
|
619
|
+
type: "object",
|
|
620
|
+
properties: {
|
|
621
|
+
theme: { type: "string" },
|
|
622
|
+
compact: { type: "boolean" },
|
|
623
|
+
},
|
|
624
|
+
required: ["theme", "compact"],
|
|
625
|
+
defaultValue: { theme: "light", compact: true },
|
|
626
|
+
},
|
|
627
|
+
},
|
|
628
|
+
variations: [
|
|
629
|
+
{ value: "control", weight: 50 },
|
|
630
|
+
{
|
|
631
|
+
value: "treatment",
|
|
632
|
+
weight: 50,
|
|
633
|
+
variableOverrides: {
|
|
634
|
+
config: [{ segments: "*", value: { theme: "dark" } }],
|
|
635
|
+
},
|
|
636
|
+
},
|
|
637
|
+
],
|
|
638
|
+
}),
|
|
639
|
+
);
|
|
640
|
+
});
|
|
613
641
|
});
|
|
614
642
|
|
|
615
643
|
describe("rules: variables", () => {
|
|
@@ -701,6 +729,175 @@ describe("featureSchema.ts :: getFeatureZodSchema (variablesSchema and variable
|
|
|
701
729
|
});
|
|
702
730
|
});
|
|
703
731
|
|
|
732
|
+
describe("rules: variableOverrides", () => {
|
|
733
|
+
it("accepts rule variableOverrides with values matching variablesSchema", () => {
|
|
734
|
+
expectParseSuccess(
|
|
735
|
+
baseFeature({
|
|
736
|
+
variablesSchema: {
|
|
737
|
+
config: {
|
|
738
|
+
type: "object",
|
|
739
|
+
properties: {
|
|
740
|
+
title: { type: "string" },
|
|
741
|
+
nested: {
|
|
742
|
+
type: "object",
|
|
743
|
+
properties: {
|
|
744
|
+
count: { type: "integer" },
|
|
745
|
+
},
|
|
746
|
+
},
|
|
747
|
+
},
|
|
748
|
+
defaultValue: {
|
|
749
|
+
title: "default",
|
|
750
|
+
nested: { count: 0 },
|
|
751
|
+
},
|
|
752
|
+
},
|
|
753
|
+
},
|
|
754
|
+
rules: {
|
|
755
|
+
staging: [
|
|
756
|
+
{
|
|
757
|
+
key: "r1",
|
|
758
|
+
segments: "*",
|
|
759
|
+
percentage: 100,
|
|
760
|
+
variableOverrides: {
|
|
761
|
+
config: [
|
|
762
|
+
{
|
|
763
|
+
segments: "countries/germany",
|
|
764
|
+
value: {
|
|
765
|
+
"nested.count": 5,
|
|
766
|
+
},
|
|
767
|
+
},
|
|
768
|
+
],
|
|
769
|
+
},
|
|
770
|
+
},
|
|
771
|
+
],
|
|
772
|
+
production: [{ key: "r1", segments: "*", percentage: 100 }],
|
|
773
|
+
},
|
|
774
|
+
}),
|
|
775
|
+
);
|
|
776
|
+
});
|
|
777
|
+
|
|
778
|
+
it("rejects rule variableOverrides for unknown variable key", () => {
|
|
779
|
+
expectParseFailure(
|
|
780
|
+
baseFeature({
|
|
781
|
+
variablesSchema: {
|
|
782
|
+
config: { type: "string", defaultValue: "x" },
|
|
783
|
+
},
|
|
784
|
+
rules: {
|
|
785
|
+
staging: [
|
|
786
|
+
{
|
|
787
|
+
key: "r1",
|
|
788
|
+
segments: "*",
|
|
789
|
+
percentage: 100,
|
|
790
|
+
variableOverrides: {
|
|
791
|
+
unknown: [{ segments: "*", value: "x" }],
|
|
792
|
+
},
|
|
793
|
+
},
|
|
794
|
+
],
|
|
795
|
+
production: [{ key: "r1", segments: "*", percentage: 100 }],
|
|
796
|
+
},
|
|
797
|
+
}),
|
|
798
|
+
"not defined in",
|
|
799
|
+
);
|
|
800
|
+
});
|
|
801
|
+
|
|
802
|
+
it("rejects mutation notation in rule variableOverrides key", () => {
|
|
803
|
+
expectParseFailure(
|
|
804
|
+
baseFeature({
|
|
805
|
+
variablesSchema: {
|
|
806
|
+
config: {
|
|
807
|
+
type: "object",
|
|
808
|
+
properties: { title: { type: "string" } },
|
|
809
|
+
defaultValue: { title: "x" },
|
|
810
|
+
},
|
|
811
|
+
},
|
|
812
|
+
rules: {
|
|
813
|
+
staging: [
|
|
814
|
+
{
|
|
815
|
+
key: "r1",
|
|
816
|
+
segments: "*",
|
|
817
|
+
percentage: 100,
|
|
818
|
+
variableOverrides: {
|
|
819
|
+
"config.title": [{ segments: "*", value: "y" }],
|
|
820
|
+
},
|
|
821
|
+
},
|
|
822
|
+
],
|
|
823
|
+
production: [{ key: "r1", segments: "*", percentage: 100 }],
|
|
824
|
+
},
|
|
825
|
+
}),
|
|
826
|
+
"must be a declared variable key",
|
|
827
|
+
);
|
|
828
|
+
});
|
|
829
|
+
|
|
830
|
+
it("rejects rule variableOverride path not present in schema", () => {
|
|
831
|
+
expectParseFailure(
|
|
832
|
+
baseFeature({
|
|
833
|
+
variablesSchema: {
|
|
834
|
+
config: {
|
|
835
|
+
type: "object",
|
|
836
|
+
properties: { title: { type: "string" } },
|
|
837
|
+
defaultValue: { title: "x" },
|
|
838
|
+
},
|
|
839
|
+
},
|
|
840
|
+
rules: {
|
|
841
|
+
staging: [
|
|
842
|
+
{
|
|
843
|
+
key: "r1",
|
|
844
|
+
segments: "*",
|
|
845
|
+
percentage: 100,
|
|
846
|
+
variableOverrides: {
|
|
847
|
+
config: [
|
|
848
|
+
{
|
|
849
|
+
segments: "*",
|
|
850
|
+
value: {
|
|
851
|
+
"nested.missing": "x",
|
|
852
|
+
},
|
|
853
|
+
},
|
|
854
|
+
],
|
|
855
|
+
},
|
|
856
|
+
},
|
|
857
|
+
],
|
|
858
|
+
production: [{ key: "r1", segments: "*", percentage: 100 }],
|
|
859
|
+
},
|
|
860
|
+
}),
|
|
861
|
+
"invalid for variable",
|
|
862
|
+
);
|
|
863
|
+
});
|
|
864
|
+
|
|
865
|
+
it("rejects non-null payload for :remove in rule variableOverrides", () => {
|
|
866
|
+
expectParseFailure(
|
|
867
|
+
baseFeature({
|
|
868
|
+
variablesSchema: {
|
|
869
|
+
config: {
|
|
870
|
+
type: "object",
|
|
871
|
+
properties: { title: { type: "string" }, optional: { type: "string" } },
|
|
872
|
+
defaultValue: { title: "x", optional: "y" },
|
|
873
|
+
},
|
|
874
|
+
},
|
|
875
|
+
rules: {
|
|
876
|
+
staging: [
|
|
877
|
+
{
|
|
878
|
+
key: "r1",
|
|
879
|
+
segments: "*",
|
|
880
|
+
percentage: 100,
|
|
881
|
+
variableOverrides: {
|
|
882
|
+
config: [
|
|
883
|
+
{
|
|
884
|
+
conditions: [{ attribute: "country", operator: "equals", value: "de" }],
|
|
885
|
+
value: {
|
|
886
|
+
"optional:remove": "not-null",
|
|
887
|
+
},
|
|
888
|
+
},
|
|
889
|
+
],
|
|
890
|
+
},
|
|
891
|
+
},
|
|
892
|
+
],
|
|
893
|
+
production: [{ key: "r1", segments: "*", percentage: 100 }],
|
|
894
|
+
},
|
|
895
|
+
}),
|
|
896
|
+
"must use `null` as value",
|
|
897
|
+
);
|
|
898
|
+
});
|
|
899
|
+
});
|
|
900
|
+
|
|
704
901
|
describe("force: variables", () => {
|
|
705
902
|
it("accepts force variables that match variablesSchema", () => {
|
|
706
903
|
expectParseSuccess(
|
|
@@ -852,6 +1049,89 @@ describe("featureSchema.ts :: getFeatureZodSchema (variablesSchema and variable
|
|
|
852
1049
|
);
|
|
853
1050
|
});
|
|
854
1051
|
|
|
1052
|
+
it("accepts object variable with additionalProperties only and arbitrary keys", () => {
|
|
1053
|
+
expectParseSuccess(
|
|
1054
|
+
baseFeature({
|
|
1055
|
+
variablesSchema: {
|
|
1056
|
+
labels: {
|
|
1057
|
+
type: "object",
|
|
1058
|
+
additionalProperties: { type: "string" },
|
|
1059
|
+
defaultValue: { title: "Welcome", subtitle: "Hello" },
|
|
1060
|
+
},
|
|
1061
|
+
},
|
|
1062
|
+
}),
|
|
1063
|
+
);
|
|
1064
|
+
});
|
|
1065
|
+
|
|
1066
|
+
it("accepts object variable with properties and additionalProperties together", () => {
|
|
1067
|
+
expectParseSuccess(
|
|
1068
|
+
baseFeature({
|
|
1069
|
+
variablesSchema: {
|
|
1070
|
+
metadata: {
|
|
1071
|
+
type: "object",
|
|
1072
|
+
properties: {
|
|
1073
|
+
fixed: { type: "integer" },
|
|
1074
|
+
},
|
|
1075
|
+
additionalProperties: { type: "string" },
|
|
1076
|
+
required: ["fixed"],
|
|
1077
|
+
defaultValue: { fixed: 1, dynamicKey: "value" },
|
|
1078
|
+
},
|
|
1079
|
+
},
|
|
1080
|
+
}),
|
|
1081
|
+
);
|
|
1082
|
+
});
|
|
1083
|
+
|
|
1084
|
+
it("rejects object variable when unknown key is present and additionalProperties is not defined", () => {
|
|
1085
|
+
expectParseFailure(
|
|
1086
|
+
baseFeature({
|
|
1087
|
+
variablesSchema: {
|
|
1088
|
+
settings: {
|
|
1089
|
+
type: "object",
|
|
1090
|
+
properties: {
|
|
1091
|
+
theme: { type: "string" },
|
|
1092
|
+
},
|
|
1093
|
+
defaultValue: { theme: "light", subtitle: "hello" },
|
|
1094
|
+
},
|
|
1095
|
+
},
|
|
1096
|
+
}),
|
|
1097
|
+
"Unknown property",
|
|
1098
|
+
);
|
|
1099
|
+
});
|
|
1100
|
+
|
|
1101
|
+
it("accepts object variable with additionalProperties that references reusable schema", () => {
|
|
1102
|
+
expectParseSuccess(
|
|
1103
|
+
baseFeature({
|
|
1104
|
+
variablesSchema: {
|
|
1105
|
+
linksByLocale: {
|
|
1106
|
+
type: "object",
|
|
1107
|
+
additionalProperties: { schema: "link" },
|
|
1108
|
+
defaultValue: {
|
|
1109
|
+
en: { title: "Home", url: "/" },
|
|
1110
|
+
de: { title: "Start", url: "/de" },
|
|
1111
|
+
},
|
|
1112
|
+
},
|
|
1113
|
+
},
|
|
1114
|
+
}),
|
|
1115
|
+
);
|
|
1116
|
+
});
|
|
1117
|
+
|
|
1118
|
+
it("rejects object variable when additionalProperties value does not match schema", () => {
|
|
1119
|
+
expectParseFailure(
|
|
1120
|
+
baseFeature({
|
|
1121
|
+
variablesSchema: {
|
|
1122
|
+
linksByLocale: {
|
|
1123
|
+
type: "object",
|
|
1124
|
+
additionalProperties: { schema: "link" },
|
|
1125
|
+
defaultValue: {
|
|
1126
|
+
en: { title: "Home" },
|
|
1127
|
+
},
|
|
1128
|
+
},
|
|
1129
|
+
},
|
|
1130
|
+
}),
|
|
1131
|
+
"Missing required property",
|
|
1132
|
+
);
|
|
1133
|
+
});
|
|
1134
|
+
|
|
855
1135
|
it("rejects inline object variable when defaultValue is missing required property", () => {
|
|
856
1136
|
expectParseFailure(
|
|
857
1137
|
baseFeature({
|
|
@@ -1417,5 +1697,40 @@ describe("featureSchema.ts :: getFeatureZodSchema (variablesSchema and variable
|
|
|
1417
1697
|
},
|
|
1418
1698
|
);
|
|
1419
1699
|
});
|
|
1700
|
+
|
|
1701
|
+
it("additionalProperties type mismatch: error path includes dynamic object key", () => {
|
|
1702
|
+
expectErrorSurfaces(
|
|
1703
|
+
baseFeature({
|
|
1704
|
+
variablesSchema: {
|
|
1705
|
+
labels: {
|
|
1706
|
+
type: "object",
|
|
1707
|
+
additionalProperties: { type: "string" },
|
|
1708
|
+
defaultValue: {
|
|
1709
|
+
title: 123,
|
|
1710
|
+
},
|
|
1711
|
+
},
|
|
1712
|
+
},
|
|
1713
|
+
}),
|
|
1714
|
+
{
|
|
1715
|
+
pathContains: ["variablesSchema", "labels", "defaultValue", "title"],
|
|
1716
|
+
messageContains: "type string",
|
|
1717
|
+
},
|
|
1718
|
+
);
|
|
1719
|
+
});
|
|
1720
|
+
|
|
1721
|
+
it("rejects variable schema with schema reference mixed with inline additionalProperties", () => {
|
|
1722
|
+
expectParseFailure(
|
|
1723
|
+
baseFeature({
|
|
1724
|
+
variablesSchema: {
|
|
1725
|
+
myLink: {
|
|
1726
|
+
schema: "link",
|
|
1727
|
+
additionalProperties: { type: "string" },
|
|
1728
|
+
defaultValue: { title: "Home", url: "/" },
|
|
1729
|
+
},
|
|
1730
|
+
},
|
|
1731
|
+
}),
|
|
1732
|
+
"additionalProperties",
|
|
1733
|
+
);
|
|
1734
|
+
});
|
|
1420
1735
|
});
|
|
1421
1736
|
});
|