@featurevisor/core 2.26.1 → 3.0.1
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 +8 -0
- package/coverage/clover.xml +4991 -3130
- package/coverage/coverage-final.json +63 -39
- package/coverage/lcov-report/block-navigation.js +1 -1
- package/coverage/lcov-report/index.html +248 -98
- package/coverage/lcov-report/sorter.js +21 -7
- package/coverage/lcov-report/src/assess-distribution/index.html +116 -0
- package/coverage/lcov-report/src/assess-distribution/index.ts.html +754 -0
- package/coverage/lcov-report/{list → src/benchmark}/index.html +30 -30
- package/coverage/lcov-report/src/benchmark/index.ts.html +793 -0
- package/coverage/lcov-report/{builder → src/builder}/allocator.ts.html +38 -38
- package/coverage/lcov-report/{builder/buildScopedConditions.ts.html → src/builder/applyContextToConditions.ts.html} +80 -65
- package/coverage/lcov-report/{builder/buildScopedDatafile.ts.html → src/builder/applyContextToDatafile.ts.html} +92 -92
- package/coverage/lcov-report/{builder/buildScopedSegments.ts.html → src/builder/applyContextToSegments.ts.html} +103 -67
- package/coverage/lcov-report/{builder → src/builder}/buildDatafile.ts.html +336 -306
- package/coverage/lcov-report/src/builder/buildProject.ts.html +1117 -0
- package/coverage/lcov-report/src/builder/buildRuntimeDatafiles.ts.html +256 -0
- package/coverage/lcov-report/{builder → src/builder}/getFeatureRanges.ts.html +22 -22
- package/coverage/lcov-report/{builder → src/builder}/hashes.ts.html +50 -50
- package/coverage/lcov-report/{builder → src/builder}/index.html +114 -84
- package/coverage/lcov-report/{tester/cliFormat.ts.html → src/builder/index.ts.html} +17 -29
- package/coverage/lcov-report/{builder → src/builder}/mutateVariables.ts.html +55 -55
- package/coverage/lcov-report/{builder → src/builder}/mutator.ts.html +118 -118
- package/coverage/lcov-report/{builder → src/builder}/revision.ts.html +15 -15
- package/coverage/lcov-report/{builder → src/builder}/traffic.ts.html +86 -86
- package/coverage/lcov-report/src/cli/cli.ts.html +400 -0
- package/coverage/lcov-report/{tester → src/cli}/index.html +41 -41
- package/coverage/lcov-report/src/cli/plugins.ts.html +214 -0
- package/coverage/lcov-report/{config → src/config}/index.html +31 -31
- package/coverage/lcov-report/{config → src/config}/index.ts.html +12 -12
- package/coverage/lcov-report/{config → src/config}/projectConfig.ts.html +312 -96
- package/coverage/lcov-report/{datasource → src/datasource}/adapter.ts.html +28 -73
- package/coverage/lcov-report/{datasource → src/datasource}/datasource.ts.html +191 -104
- package/coverage/lcov-report/{datasource → src/datasource}/filesystemAdapter.ts.html +233 -635
- package/coverage/lcov-report/{datasource → src/datasource}/index.html +48 -48
- package/coverage/lcov-report/{datasource → src/datasource}/index.ts.html +14 -14
- package/coverage/lcov-report/src/evaluate/index.html +116 -0
- package/coverage/lcov-report/src/evaluate/index.ts.html +814 -0
- package/coverage/lcov-report/src/find-duplicate-segments/findDuplicateSegments.ts.html +313 -0
- package/coverage/lcov-report/src/find-duplicate-segments/index.html +131 -0
- package/coverage/lcov-report/src/find-duplicate-segments/index.ts.html +307 -0
- package/coverage/lcov-report/src/find-usage/index.html +116 -0
- package/coverage/lcov-report/src/find-usage/index.ts.html +1780 -0
- package/coverage/lcov-report/src/generate-code/index.html +131 -0
- package/coverage/lcov-report/src/generate-code/index.ts.html +403 -0
- package/coverage/lcov-report/{generate-code → src/generate-code}/typescript.ts.html +266 -1361
- package/coverage/lcov-report/{generate-code → src}/index.html +38 -23
- package/coverage/lcov-report/src/info/index.html +116 -0
- package/coverage/lcov-report/src/info/index.ts.html +472 -0
- package/coverage/lcov-report/src/init/index.html +116 -0
- package/coverage/lcov-report/src/init/index.ts.html +280 -0
- package/coverage/lcov-report/{linter → src/linter}/attributeSchema.ts.html +160 -157
- package/coverage/lcov-report/{linter → src/linter}/checkCircularDependency.ts.html +25 -25
- package/coverage/lcov-report/{linter → src/linter}/checkPercentageExceedingSlot.ts.html +42 -42
- package/coverage/lcov-report/{linter → src/linter}/conditionSchema.ts.html +207 -207
- package/coverage/lcov-report/{linter → src/linter}/featureSchema.ts.html +462 -471
- package/coverage/lcov-report/{linter → src/linter}/groupSchema.ts.html +25 -22
- package/coverage/lcov-report/{linter → src/linter}/index.html +129 -99
- package/coverage/lcov-report/src/linter/index.ts.html +88 -0
- package/coverage/lcov-report/{linter → src/linter}/lintProject.ts.html +740 -332
- package/coverage/lcov-report/{linter → src/linter}/mutationNotation.ts.html +130 -130
- package/coverage/lcov-report/{linter → src/linter}/printError.ts.html +27 -27
- package/coverage/lcov-report/{linter → src/linter}/schema.ts.html +153 -150
- package/coverage/lcov-report/{linter → src/linter}/segmentSchema.ts.html +18 -15
- package/coverage/lcov-report/src/linter/targetSchema.ts.html +223 -0
- package/coverage/lcov-report/{linter → src/linter}/testSchema.ts.html +54 -48
- package/coverage/lcov-report/{linter → src/linter}/zodHelpers.ts.html +17 -17
- package/coverage/lcov-report/src/list/index.html +131 -0
- package/coverage/lcov-report/src/list/index.ts.html +2065 -0
- package/coverage/lcov-report/{list → src/list}/matrix.ts.html +43 -58
- package/coverage/lcov-report/src/promoter/index.html +116 -0
- package/coverage/lcov-report/src/promoter/index.ts.html +3883 -0
- package/coverage/lcov-report/src/sets.ts.html +313 -0
- package/coverage/lcov-report/src/targeting.ts.html +403 -0
- package/coverage/lcov-report/src/tester/cliFormat.ts.html +133 -0
- package/coverage/lcov-report/{tester → src/tester}/helpers.ts.html +15 -15
- package/coverage/lcov-report/src/tester/index.html +206 -0
- package/coverage/lcov-report/src/tester/prettyDuration.ts.html +187 -0
- package/coverage/lcov-report/src/tester/printTestResult.ts.html +337 -0
- package/coverage/lcov-report/src/tester/testFeature.ts.html +1186 -0
- package/coverage/lcov-report/src/tester/testProject.ts.html +1018 -0
- package/coverage/lcov-report/src/tester/testSegment.ts.html +316 -0
- package/coverage/lcov-report/{utils → src/utils}/extractKeys.ts.html +68 -68
- package/coverage/lcov-report/{utils → src/utils}/git.ts.html +44 -68
- package/coverage/lcov-report/{utils → src/utils}/index.html +44 -44
- package/coverage/lcov-report/{utils → src/utils}/index.ts.html +14 -14
- package/coverage/lcov-report/{utils → src/utils}/pretty.ts.html +20 -20
- package/coverage/lcov.info +10121 -5723
- package/jest.config.js +13 -4
- package/lib/assess-distribution/index.d.ts +1 -1
- package/lib/assess-distribution/index.js +59 -40
- package/lib/assess-distribution/index.js.map +1 -1
- package/lib/benchmark/index.d.ts +8 -5
- package/lib/benchmark/index.js +82 -65
- package/lib/benchmark/index.js.map +1 -1
- package/lib/builder/applyContextToConditions.d.ts +5 -0
- package/lib/builder/{buildScopedConditions.js → applyContextToConditions.js} +19 -14
- package/lib/builder/applyContextToConditions.js.map +1 -0
- package/lib/builder/applyContextToDatafile.d.ts +2 -0
- package/lib/builder/{buildScopedDatafile.js → applyContextToDatafile.js} +26 -26
- package/lib/builder/applyContextToDatafile.js.map +1 -0
- package/lib/builder/applyContextToSegments.d.ts +5 -0
- package/lib/builder/{buildScopedSegments.js → applyContextToSegments.js} +19 -14
- package/lib/builder/applyContextToSegments.js.map +1 -0
- package/lib/builder/buildDatafile.d.ts +9 -6
- package/lib/builder/buildDatafile.js +86 -51
- package/lib/builder/buildDatafile.js.map +1 -1
- package/lib/builder/buildProject.d.ts +17 -3
- package/lib/builder/buildProject.js +151 -59
- package/lib/builder/buildProject.js.map +1 -1
- package/lib/builder/buildRuntimeDatafiles.d.ts +12 -0
- package/lib/builder/buildRuntimeDatafiles.js +35 -0
- package/lib/builder/buildRuntimeDatafiles.js.map +1 -0
- package/lib/builder/getFeatureRanges.js +34 -1
- package/lib/builder/getFeatureRanges.js.map +1 -1
- package/lib/builder/hashes.js +34 -1
- package/lib/builder/hashes.js.map +1 -1
- package/lib/builder/index.d.ts +0 -1
- package/lib/builder/index.js +0 -1
- package/lib/builder/index.js.map +1 -1
- package/lib/cli/cli.js +0 -4
- package/lib/cli/cli.js.map +1 -1
- package/lib/cli/plugins.js +7 -2
- package/lib/cli/plugins.js.map +1 -1
- package/lib/config/projectConfig.d.ts +17 -17
- package/lib/config/projectConfig.js +101 -15
- package/lib/config/projectConfig.js.map +1 -1
- package/lib/datasource/adapter.d.ts +7 -9
- package/lib/datasource/adapter.js +0 -7
- package/lib/datasource/adapter.js.map +1 -1
- package/lib/datasource/datasource.d.ts +15 -5
- package/lib/datasource/datasource.js +37 -9
- package/lib/datasource/datasource.js.map +1 -1
- package/lib/datasource/filesystemAdapter.d.ts +4 -10
- package/lib/datasource/filesystemAdapter.js +111 -149
- package/lib/datasource/filesystemAdapter.js.map +1 -1
- package/lib/evaluate/index.d.ts +1 -7
- package/lib/evaluate/index.js +81 -67
- package/lib/evaluate/index.js.map +1 -1
- package/lib/find-duplicate-segments/findDuplicateSegments.js +34 -1
- package/lib/find-duplicate-segments/findDuplicateSegments.js.map +1 -1
- package/lib/find-duplicate-segments/index.js +21 -13
- package/lib/find-duplicate-segments/index.js.map +1 -1
- package/lib/find-usage/index.js +57 -41
- package/lib/find-usage/index.js.map +1 -1
- package/lib/generate-code/index.d.ts +1 -1
- package/lib/generate-code/index.js +64 -21
- package/lib/generate-code/index.js.map +1 -1
- package/lib/generate-code/typescript.d.ts +1 -1
- package/lib/generate-code/typescript.js +59 -333
- package/lib/generate-code/typescript.js.map +1 -1
- package/lib/index.d.ts +2 -1
- package/lib/index.js +2 -1
- package/lib/index.js.map +1 -1
- package/lib/info/index.js +57 -16
- package/lib/info/index.js.map +1 -1
- package/lib/init/index.d.ts +2 -2
- package/lib/init/index.js +39 -3
- package/lib/init/index.js.map +1 -1
- package/lib/linter/attributeSchema.d.ts +1 -0
- package/lib/linter/attributeSchema.js +1 -0
- package/lib/linter/attributeSchema.js.map +1 -1
- package/lib/linter/conditionSchema.js +5 -5
- package/lib/linter/conditionSchema.js.map +1 -1
- package/lib/linter/featureSchema.d.ts +4 -1
- package/lib/linter/featureSchema.js +15 -13
- package/lib/linter/featureSchema.js.map +1 -1
- package/lib/linter/groupSchema.d.ts +1 -0
- package/lib/linter/groupSchema.js +1 -0
- package/lib/linter/groupSchema.js.map +1 -1
- package/lib/linter/lintProject.d.ts +1 -3
- package/lib/linter/lintProject.js +198 -68
- package/lib/linter/lintProject.js.map +1 -1
- package/lib/linter/schema.js +1 -0
- package/lib/linter/schema.js.map +1 -1
- package/lib/linter/segmentSchema.d.ts +1 -0
- package/lib/linter/segmentSchema.js +1 -0
- package/lib/linter/segmentSchema.js.map +1 -1
- package/lib/linter/targetSchema.d.ts +16 -0
- package/lib/linter/targetSchema.js +40 -0
- package/lib/linter/targetSchema.js.map +1 -0
- package/lib/linter/testSchema.d.ts +4 -3
- package/lib/linter/testSchema.js +9 -4
- package/lib/linter/testSchema.js.map +1 -1
- package/lib/list/index.d.ts +1 -0
- package/lib/list/index.js +131 -12
- package/lib/list/index.js.map +1 -1
- package/lib/list/matrix.js +3 -7
- package/lib/list/matrix.js.map +1 -1
- package/lib/promoter/index.d.ts +50 -0
- package/lib/promoter/index.js +880 -0
- package/lib/promoter/index.js.map +1 -0
- package/lib/sets.d.ts +11 -0
- package/lib/sets.js +81 -0
- package/lib/sets.js.map +1 -0
- package/lib/targeting.d.ts +14 -0
- package/lib/targeting.js +82 -0
- package/lib/targeting.js.map +1 -0
- package/lib/tester/cliFormat.d.ts +7 -1
- package/lib/tester/cliFormat.js +11 -2
- package/lib/tester/cliFormat.js.map +1 -1
- package/lib/tester/printTestResult.js +2 -2
- package/lib/tester/printTestResult.js.map +1 -1
- package/lib/tester/testFeature.d.ts +0 -1
- package/lib/tester/testFeature.js +8 -25
- package/lib/tester/testFeature.js.map +1 -1
- package/lib/tester/testProject.d.ts +2 -3
- package/lib/tester/testProject.js +93 -86
- package/lib/tester/testProject.js.map +1 -1
- package/lib/tester/testSegment.d.ts +1 -1
- package/lib/tester/testSegment.js +3 -21
- package/lib/tester/testSegment.js.map +1 -1
- package/lib/utils/git.js +45 -19
- package/lib/utils/git.js.map +1 -1
- package/package.json +12 -12
- package/src/assess-distribution/index.ts +72 -52
- package/src/benchmark/index.ts +124 -91
- package/src/builder/{buildScopedConditions.spec.ts → applyContextToConditions.spec.ts} +160 -142
- package/src/builder/{buildScopedConditions.ts → applyContextToConditions.ts} +19 -14
- package/src/builder/{buildScopedDatafile.spec.ts → applyContextToDatafile.spec.ts} +141 -81
- package/src/builder/{buildScopedDatafile.ts → applyContextToDatafile.ts} +33 -33
- package/src/builder/{buildScopedSegments.spec.ts → applyContextToSegments.spec.ts} +171 -151
- package/src/builder/{buildScopedSegments.ts → applyContextToSegments.ts} +26 -14
- package/src/builder/buildDatafile.spec.ts +192 -14
- package/src/builder/buildDatafile.ts +74 -64
- package/src/builder/buildProject.ts +171 -86
- package/src/builder/buildRuntimeDatafiles.ts +57 -0
- package/src/builder/index.ts +0 -1
- package/src/cli/cli.ts +0 -5
- package/src/cli/plugins.ts +7 -2
- package/src/config/projectConfig.spec.ts +171 -8
- package/src/config/projectConfig.ts +100 -28
- package/src/datasource/adapter.ts +8 -23
- package/src/datasource/datasource.ts +50 -21
- package/src/datasource/filesystemAdapter.spec.ts +133 -74
- package/src/datasource/filesystemAdapter.ts +93 -227
- package/src/evaluate/index.ts +109 -97
- package/src/find-duplicate-segments/index.ts +34 -16
- package/src/find-usage/index.ts +89 -44
- package/src/generate-code/index.ts +36 -24
- package/src/generate-code/typescript.spec.ts +106 -0
- package/src/generate-code/typescript.ts +33 -398
- package/src/index.ts +2 -1
- package/src/info/index.ts +72 -16
- package/src/init/index.ts +1 -1
- package/src/linter/attributeSchema.ts +1 -0
- package/src/linter/conditionSchema.spec.ts +23 -3
- package/src/linter/conditionSchema.ts +5 -5
- package/src/linter/featureSchema.spec.ts +107 -18
- package/src/linter/featureSchema.ts +25 -28
- package/src/linter/groupSchema.ts +1 -0
- package/src/linter/lintProject.spec.ts +131 -92
- package/src/linter/lintProject.ts +233 -97
- package/src/linter/schema.ts +1 -0
- package/src/linter/segmentSchema.spec.ts +5 -3
- package/src/linter/segmentSchema.ts +1 -0
- package/src/linter/targetSchema.spec.ts +159 -0
- package/src/linter/targetSchema.ts +46 -0
- package/src/linter/testSchema.spec.ts +70 -5
- package/src/linter/testSchema.ts +12 -10
- package/src/list/index.spec.ts +135 -0
- package/src/list/index.ts +188 -12
- package/src/list/matrix.ts +3 -8
- package/src/promoter/index.spec.ts +617 -0
- package/src/promoter/index.ts +1266 -0
- package/src/sets.ts +76 -0
- package/src/targeting.spec.ts +74 -0
- package/src/targeting.ts +106 -0
- package/src/tester/cliFormat.ts +11 -1
- package/src/tester/printTestResult.ts +12 -3
- package/src/tester/testFeature.ts +10 -36
- package/src/tester/testProject.spec.ts +50 -0
- package/src/tester/testProject.ts +89 -140
- package/src/tester/testSegment.ts +5 -22
- package/src/utils/git.ts +13 -21
- package/tsconfig.cjs.json +5 -1
- package/tsconfig.typecheck.json +9 -0
- package/coverage/lcov-report/builder/convertToV1.ts.html +0 -583
- package/lib/builder/allocator.spec.d.ts +0 -1
- package/lib/builder/allocator.spec.js +0 -85
- package/lib/builder/allocator.spec.js.map +0 -1
- package/lib/builder/buildDatafile.spec.d.ts +0 -1
- package/lib/builder/buildDatafile.spec.js +0 -233
- package/lib/builder/buildDatafile.spec.js.map +0 -1
- package/lib/builder/buildScopedConditions.d.ts +0 -5
- package/lib/builder/buildScopedConditions.js.map +0 -1
- package/lib/builder/buildScopedConditions.spec.d.ts +0 -1
- package/lib/builder/buildScopedConditions.spec.js +0 -2167
- package/lib/builder/buildScopedConditions.spec.js.map +0 -1
- package/lib/builder/buildScopedDatafile.d.ts +0 -2
- package/lib/builder/buildScopedDatafile.js.map +0 -1
- package/lib/builder/buildScopedDatafile.spec.d.ts +0 -1
- package/lib/builder/buildScopedDatafile.spec.js +0 -2277
- package/lib/builder/buildScopedDatafile.spec.js.map +0 -1
- package/lib/builder/buildScopedSegments.d.ts +0 -5
- package/lib/builder/buildScopedSegments.js.map +0 -1
- package/lib/builder/buildScopedSegments.spec.d.ts +0 -1
- package/lib/builder/buildScopedSegments.spec.js +0 -1062
- package/lib/builder/buildScopedSegments.spec.js.map +0 -1
- package/lib/builder/convertToV1.d.ts +0 -10
- package/lib/builder/convertToV1.js +0 -119
- package/lib/builder/convertToV1.js.map +0 -1
- package/lib/builder/mutateVariables.spec.d.ts +0 -1
- package/lib/builder/mutateVariables.spec.js +0 -1074
- package/lib/builder/mutateVariables.spec.js.map +0 -1
- package/lib/builder/mutator.spec.d.ts +0 -1
- package/lib/builder/mutator.spec.js +0 -368
- package/lib/builder/mutator.spec.js.map +0 -1
- package/lib/builder/revision.spec.d.ts +0 -1
- package/lib/builder/revision.spec.js +0 -21
- package/lib/builder/revision.spec.js.map +0 -1
- package/lib/builder/traffic.spec.d.ts +0 -1
- package/lib/builder/traffic.spec.js +0 -872
- package/lib/builder/traffic.spec.js.map +0 -1
- package/lib/config/projectConfig.spec.d.ts +0 -1
- package/lib/config/projectConfig.spec.js +0 -24
- package/lib/config/projectConfig.spec.js.map +0 -1
- package/lib/datasource/filesystemAdapter.spec.d.ts +0 -1
- package/lib/datasource/filesystemAdapter.spec.js +0 -88
- package/lib/datasource/filesystemAdapter.spec.js.map +0 -1
- package/lib/generate-code/typescript.spec.d.ts +0 -1
- package/lib/generate-code/typescript.spec.js +0 -78
- package/lib/generate-code/typescript.spec.js.map +0 -1
- package/lib/linter/attributeSchema.spec.d.ts +0 -1
- package/lib/linter/attributeSchema.spec.js +0 -266
- package/lib/linter/attributeSchema.spec.js.map +0 -1
- package/lib/linter/conditionSchema.spec.d.ts +0 -1
- package/lib/linter/conditionSchema.spec.js +0 -380
- package/lib/linter/conditionSchema.spec.js.map +0 -1
- package/lib/linter/featureSchema.spec.d.ts +0 -1
- package/lib/linter/featureSchema.spec.js +0 -1552
- package/lib/linter/featureSchema.spec.js.map +0 -1
- package/lib/linter/lintProject.spec.d.ts +0 -1
- package/lib/linter/lintProject.spec.js +0 -211
- package/lib/linter/lintProject.spec.js.map +0 -1
- package/lib/linter/mutationNotation.spec.d.ts +0 -1
- package/lib/linter/mutationNotation.spec.js +0 -598
- package/lib/linter/mutationNotation.spec.js.map +0 -1
- package/lib/linter/schema.spec.d.ts +0 -1
- package/lib/linter/schema.spec.js +0 -535
- package/lib/linter/schema.spec.js.map +0 -1
- package/lib/linter/segmentSchema.spec.d.ts +0 -1
- package/lib/linter/segmentSchema.spec.js +0 -303
- package/lib/linter/segmentSchema.spec.js.map +0 -1
- package/lib/linter/testSchema.spec.d.ts +0 -1
- package/lib/linter/testSchema.spec.js +0 -162
- package/lib/linter/testSchema.spec.js.map +0 -1
- package/lib/list/matrix.spec.d.ts +0 -1
- package/lib/list/matrix.spec.js +0 -42
- package/lib/list/matrix.spec.js.map +0 -1
- package/lib/site/exportSite.d.ts +0 -2
- package/lib/site/exportSite.js +0 -30
- package/lib/site/exportSite.js.map +0 -1
- package/lib/site/generateHistory.d.ts +0 -3
- package/lib/site/generateHistory.js +0 -31
- package/lib/site/generateHistory.js.map +0 -1
- package/lib/site/generateSiteSearchIndex.d.ts +0 -4
- package/lib/site/generateSiteSearchIndex.js +0 -195
- package/lib/site/generateSiteSearchIndex.js.map +0 -1
- package/lib/site/getLastModifiedFromHistory.d.ts +0 -2
- package/lib/site/getLastModifiedFromHistory.js +0 -18
- package/lib/site/getLastModifiedFromHistory.js.map +0 -1
- package/lib/site/getOwnerAndRepoFromUrl.d.ts +0 -4
- package/lib/site/getOwnerAndRepoFromUrl.js +0 -20
- package/lib/site/getOwnerAndRepoFromUrl.js.map +0 -1
- package/lib/site/getRelativePaths.d.ts +0 -6
- package/lib/site/getRelativePaths.js +0 -15
- package/lib/site/getRelativePaths.js.map +0 -1
- package/lib/site/getRepoDetails.d.ts +0 -8
- package/lib/site/getRepoDetails.js +0 -48
- package/lib/site/getRepoDetails.js.map +0 -1
- package/lib/site/index.d.ts +0 -2
- package/lib/site/index.js +0 -43
- package/lib/site/index.js.map +0 -1
- package/lib/site/serveSite.d.ts +0 -2
- package/lib/site/serveSite.js +0 -54
- package/lib/site/serveSite.js.map +0 -1
- package/lib/tester/helpers.spec.d.ts +0 -1
- package/lib/tester/helpers.spec.js +0 -115
- package/lib/tester/helpers.spec.js.map +0 -1
- package/src/builder/convertToV1.ts +0 -166
- package/src/site/exportSite.ts +0 -42
- package/src/site/generateHistory.ts +0 -40
- package/src/site/generateSiteSearchIndex.ts +0 -258
- package/src/site/getLastModifiedFromHistory.ts +0 -21
- package/src/site/getOwnerAndRepoFromUrl.ts +0 -17
- package/src/site/getRelativePaths.ts +0 -24
- package/src/site/getRepoDetails.ts +0 -62
- package/src/site/index.ts +0 -46
- package/src/site/serveSite.ts +0 -58
|
@@ -1,19 +1,22 @@
|
|
|
1
|
-
import
|
|
1
|
+
import * as path from "path";
|
|
2
|
+
|
|
3
|
+
import { ProjectConfig } from "../config";
|
|
2
4
|
import { Datasource } from "../datasource";
|
|
3
5
|
|
|
4
6
|
import { getNextRevision } from "./revision";
|
|
5
7
|
import { buildDatafile, getCustomDatafile } from "./buildDatafile";
|
|
6
|
-
import {
|
|
8
|
+
import { applyContextToDatafile } from "./applyContextToDatafile";
|
|
7
9
|
import { Dependencies } from "../dependencies";
|
|
8
10
|
import { Plugin } from "../cli";
|
|
9
|
-
import type { Scope } from "../config";
|
|
10
11
|
|
|
11
|
-
import type { DatafileContent } from "@featurevisor/types";
|
|
12
|
+
import type { DatafileContent, Target } from "@featurevisor/types";
|
|
13
|
+
import { assertProjectSetJsonSelection, getProjectSetExecutions, printSetHeader } from "../sets";
|
|
14
|
+
import { CLI_COLOR_CYAN, CLI_FORMAT_BOLD, CLI_FORMAT_GREEN, colorize } from "../tester/cliFormat";
|
|
15
|
+
import { resolveTargets } from "../targeting";
|
|
12
16
|
|
|
13
17
|
export interface BuildCLIOptions {
|
|
14
18
|
revision?: string;
|
|
15
19
|
revisionFromHash?: boolean;
|
|
16
|
-
schemaVersion?: string;
|
|
17
20
|
|
|
18
21
|
// all three together
|
|
19
22
|
environment?: string;
|
|
@@ -24,8 +27,8 @@ export interface BuildCLIOptions {
|
|
|
24
27
|
inflate?: number;
|
|
25
28
|
datafilesDir?: string;
|
|
26
29
|
|
|
27
|
-
|
|
28
|
-
|
|
30
|
+
target?: string | string[];
|
|
31
|
+
set?: string;
|
|
29
32
|
}
|
|
30
33
|
|
|
31
34
|
function getFeaturevisorVersion(): string {
|
|
@@ -39,91 +42,53 @@ function getFeaturevisorVersion(): string {
|
|
|
39
42
|
}
|
|
40
43
|
}
|
|
41
44
|
|
|
45
|
+
function getEnvironmentLabel(environment: string | false) {
|
|
46
|
+
return environment === false ? "No environment" : `Environment "${environment}"`;
|
|
47
|
+
}
|
|
48
|
+
|
|
42
49
|
async function buildForEnvironment({
|
|
43
50
|
projectConfig,
|
|
44
51
|
datasource,
|
|
45
52
|
nextRevision,
|
|
46
53
|
environment,
|
|
47
|
-
|
|
48
|
-
scopes,
|
|
54
|
+
targets,
|
|
49
55
|
cliOptions,
|
|
50
56
|
}: {
|
|
51
57
|
projectConfig: ProjectConfig;
|
|
52
58
|
datasource: Datasource;
|
|
53
59
|
nextRevision: string;
|
|
54
60
|
environment: string | false;
|
|
55
|
-
|
|
56
|
-
scopes?: Scope[];
|
|
61
|
+
targets: Array<Target & { key: string }>;
|
|
57
62
|
cliOptions: BuildCLIOptions;
|
|
58
63
|
}) {
|
|
59
|
-
console.log(
|
|
64
|
+
console.log("");
|
|
65
|
+
console.log(CLI_FORMAT_BOLD, getEnvironmentLabel(environment));
|
|
60
66
|
|
|
61
67
|
const existingState = await datasource.readState(environment);
|
|
62
68
|
const featurevisorVersion = getFeaturevisorVersion();
|
|
63
69
|
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
console.log(`\n => Tag: ${tag}`);
|
|
70
|
+
for (const target of targets) {
|
|
71
|
+
console.log(` ${colorize("Target", CLI_COLOR_CYAN)}: ${target.key}`);
|
|
67
72
|
|
|
68
|
-
const datafileContent = await
|
|
73
|
+
const datafileContent = await buildTargetDatafile({
|
|
69
74
|
projectConfig,
|
|
70
75
|
datasource,
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
revision: nextRevision,
|
|
74
|
-
revisionFromHash: cliOptions.revisionFromHash,
|
|
75
|
-
environment: environment,
|
|
76
|
-
tag: tag,
|
|
77
|
-
inflate: cliOptions.inflate,
|
|
78
|
-
featurevisorVersion,
|
|
79
|
-
},
|
|
76
|
+
target,
|
|
77
|
+
environment,
|
|
80
78
|
existingState,
|
|
81
|
-
|
|
79
|
+
revision: nextRevision,
|
|
80
|
+
revisionFromHash: cliOptions.revisionFromHash,
|
|
81
|
+
inflate: cliOptions.inflate,
|
|
82
|
+
featurevisorVersion,
|
|
83
|
+
});
|
|
82
84
|
|
|
83
|
-
|
|
84
|
-
await datasource.writeDatafile(datafileContent as DatafileContent, {
|
|
85
|
+
await datasource.writeDatafile(datafileContent, {
|
|
85
86
|
environment,
|
|
86
|
-
|
|
87
|
+
target: target.key,
|
|
87
88
|
datafilesDir: cliOptions.datafilesDir,
|
|
88
89
|
});
|
|
89
90
|
}
|
|
90
91
|
|
|
91
|
-
// by scope
|
|
92
|
-
if (scopes) {
|
|
93
|
-
for (const scope of scopes) {
|
|
94
|
-
console.log(`\n => Scope: ${scope.name}`);
|
|
95
|
-
|
|
96
|
-
const datafileContent = await buildDatafile(
|
|
97
|
-
projectConfig,
|
|
98
|
-
datasource,
|
|
99
|
-
{
|
|
100
|
-
schemaVersion: cliOptions.schemaVersion || SCHEMA_VERSION,
|
|
101
|
-
revision: nextRevision,
|
|
102
|
-
revisionFromHash: cliOptions.revisionFromHash,
|
|
103
|
-
environment: environment,
|
|
104
|
-
tag: scope.tag,
|
|
105
|
-
tags: scope.tags,
|
|
106
|
-
inflate: cliOptions.inflate,
|
|
107
|
-
featurevisorVersion,
|
|
108
|
-
},
|
|
109
|
-
existingState,
|
|
110
|
-
);
|
|
111
|
-
|
|
112
|
-
const scopedDatafileContent = buildScopedDatafile(
|
|
113
|
-
datafileContent as DatafileContent,
|
|
114
|
-
scope.context,
|
|
115
|
-
);
|
|
116
|
-
|
|
117
|
-
// write scoped datafile
|
|
118
|
-
await datasource.writeDatafile(scopedDatafileContent, {
|
|
119
|
-
environment,
|
|
120
|
-
tag: scope.tag,
|
|
121
|
-
scope: scope,
|
|
122
|
-
datafilesDir: cliOptions.datafilesDir,
|
|
123
|
-
});
|
|
124
|
-
}
|
|
125
|
-
}
|
|
126
|
-
|
|
127
92
|
if (typeof cliOptions.stateFiles === "undefined" || cliOptions.stateFiles) {
|
|
128
93
|
// write state for environment
|
|
129
94
|
await datasource.writeState(environment, existingState);
|
|
@@ -133,6 +98,51 @@ async function buildForEnvironment({
|
|
|
133
98
|
}
|
|
134
99
|
}
|
|
135
100
|
|
|
101
|
+
export async function buildTargetDatafile({
|
|
102
|
+
projectConfig,
|
|
103
|
+
datasource,
|
|
104
|
+
target,
|
|
105
|
+
environment,
|
|
106
|
+
existingState,
|
|
107
|
+
revision,
|
|
108
|
+
revisionFromHash,
|
|
109
|
+
inflate,
|
|
110
|
+
featurevisorVersion,
|
|
111
|
+
}: {
|
|
112
|
+
projectConfig: ProjectConfig;
|
|
113
|
+
datasource: Datasource;
|
|
114
|
+
target: Target;
|
|
115
|
+
environment: string | false;
|
|
116
|
+
existingState: Awaited<ReturnType<Datasource["readState"]>>;
|
|
117
|
+
revision: string;
|
|
118
|
+
revisionFromHash?: boolean;
|
|
119
|
+
inflate?: number;
|
|
120
|
+
featurevisorVersion?: string;
|
|
121
|
+
}): Promise<DatafileContent> {
|
|
122
|
+
const datafileContent = await buildDatafile(
|
|
123
|
+
projectConfig,
|
|
124
|
+
datasource,
|
|
125
|
+
{
|
|
126
|
+
revision,
|
|
127
|
+
revisionFromHash,
|
|
128
|
+
environment,
|
|
129
|
+
tag: target.tag,
|
|
130
|
+
tags: target.tags,
|
|
131
|
+
includeFeatures: target.includeFeatures,
|
|
132
|
+
excludeFeatures: target.excludeFeatures,
|
|
133
|
+
inflate,
|
|
134
|
+
featurevisorVersion,
|
|
135
|
+
},
|
|
136
|
+
existingState,
|
|
137
|
+
);
|
|
138
|
+
|
|
139
|
+
if (target.context) {
|
|
140
|
+
return applyContextToDatafile(datafileContent as DatafileContent, target.context);
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
return datafileContent as DatafileContent;
|
|
144
|
+
}
|
|
145
|
+
|
|
136
146
|
export async function buildProject(deps: Dependencies, cliOptions: BuildCLIOptions = {}) {
|
|
137
147
|
const { projectConfig, datasource } = deps;
|
|
138
148
|
|
|
@@ -146,24 +156,38 @@ export async function buildProject(deps: Dependencies, cliOptions: BuildCLIOptio
|
|
|
146
156
|
* This way we centralize the datafile generation in one place,
|
|
147
157
|
* while tests can be run anywhere else.
|
|
148
158
|
*/
|
|
149
|
-
if (cliOptions.
|
|
150
|
-
const
|
|
151
|
-
|
|
152
|
-
|
|
159
|
+
if (cliOptions.json) {
|
|
160
|
+
const environment = cliOptions.environment || false;
|
|
161
|
+
|
|
162
|
+
if (Array.isArray(projectConfig.environments) && !cliOptions.environment) {
|
|
163
|
+
throw new Error("Pass --environment=<environment> when printing a datafile.");
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
const targets = await resolveTargets(datasource, cliOptions.target, {
|
|
167
|
+
defaultToAll: false,
|
|
168
|
+
requireTargets: false,
|
|
169
|
+
});
|
|
170
|
+
if (targets.length > 1) {
|
|
171
|
+
throw new Error("Only one --target can be used with --json or --print.");
|
|
172
|
+
}
|
|
173
|
+
const target = targets[0];
|
|
153
174
|
|
|
154
175
|
let datafileContent = await getCustomDatafile({
|
|
155
176
|
featureKey: cliOptions.feature,
|
|
156
|
-
environment
|
|
177
|
+
environment,
|
|
157
178
|
projectConfig,
|
|
158
179
|
datasource,
|
|
159
180
|
revision: cliOptions.revision,
|
|
160
|
-
|
|
161
|
-
tag:
|
|
162
|
-
tags:
|
|
181
|
+
inflate: cliOptions.inflate,
|
|
182
|
+
tag: target?.tag,
|
|
183
|
+
tags: target?.tags,
|
|
184
|
+
includeFeatures: target?.includeFeatures,
|
|
185
|
+
excludeFeatures: target?.excludeFeatures,
|
|
186
|
+
featurevisorVersion: getFeaturevisorVersion(),
|
|
163
187
|
});
|
|
164
188
|
|
|
165
|
-
if (
|
|
166
|
-
datafileContent =
|
|
189
|
+
if (target?.context) {
|
|
190
|
+
datafileContent = applyContextToDatafile(datafileContent as DatafileContent, target.context);
|
|
167
191
|
}
|
|
168
192
|
|
|
169
193
|
if (cliOptions.pretty) {
|
|
@@ -178,10 +202,13 @@ export async function buildProject(deps: Dependencies, cliOptions: BuildCLIOptio
|
|
|
178
202
|
/**
|
|
179
203
|
* Regular build process that writes to disk.
|
|
180
204
|
*/
|
|
181
|
-
const {
|
|
205
|
+
const { environments } = projectConfig;
|
|
206
|
+
const targets = await resolveTargets(datasource, cliOptions.target);
|
|
182
207
|
|
|
183
208
|
const currentRevision = await datasource.readRevision();
|
|
184
|
-
console.log("
|
|
209
|
+
console.log("");
|
|
210
|
+
console.log(CLI_FORMAT_BOLD, "Building Featurevisor datafiles");
|
|
211
|
+
console.log(` Current revision: ${currentRevision}`);
|
|
185
212
|
|
|
186
213
|
const nextRevision =
|
|
187
214
|
(cliOptions.revision && cliOptions.revision.toString()) || getNextRevision(currentRevision);
|
|
@@ -194,33 +221,91 @@ export async function buildProject(deps: Dependencies, cliOptions: BuildCLIOptio
|
|
|
194
221
|
datasource,
|
|
195
222
|
nextRevision,
|
|
196
223
|
environment,
|
|
197
|
-
|
|
198
|
-
scopes,
|
|
224
|
+
targets,
|
|
199
225
|
cliOptions,
|
|
200
226
|
});
|
|
201
227
|
}
|
|
202
228
|
}
|
|
203
229
|
|
|
204
230
|
// no environment
|
|
205
|
-
if (environments
|
|
231
|
+
if (!Array.isArray(environments)) {
|
|
206
232
|
await buildForEnvironment({
|
|
207
233
|
projectConfig,
|
|
208
234
|
datasource,
|
|
209
235
|
nextRevision,
|
|
210
236
|
environment: false,
|
|
211
|
-
|
|
212
|
-
scopes,
|
|
237
|
+
targets,
|
|
213
238
|
cliOptions,
|
|
214
239
|
});
|
|
215
240
|
}
|
|
216
241
|
|
|
217
|
-
console.log("
|
|
242
|
+
console.log("");
|
|
243
|
+
console.log(CLI_FORMAT_GREEN, "Datafiles built");
|
|
244
|
+
console.log(CLI_FORMAT_BOLD, `Latest revision: ${nextRevision}`);
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
export async function buildProjectSets(deps: Dependencies, cliOptions: BuildCLIOptions = {}) {
|
|
248
|
+
const { projectConfig, datasource } = deps;
|
|
249
|
+
|
|
250
|
+
assertProjectSetJsonSelection(projectConfig, cliOptions.set, cliOptions.json);
|
|
251
|
+
|
|
252
|
+
const executions = await getProjectSetExecutions(projectConfig, datasource, cliOptions.set);
|
|
253
|
+
const currentRevision = await datasource.readRevision();
|
|
254
|
+
const nextRevision =
|
|
255
|
+
(cliOptions.revision && cliOptions.revision.toString()) || getNextRevision(currentRevision);
|
|
256
|
+
|
|
257
|
+
if (projectConfig.sets && !cliOptions.json) {
|
|
258
|
+
console.log("");
|
|
259
|
+
console.log(CLI_FORMAT_BOLD, "Building Featurevisor sets");
|
|
260
|
+
console.log(` Sets: ${executions.map((execution) => execution.set).join(", ")}`);
|
|
261
|
+
console.log(` Current project revision: ${currentRevision}`);
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
for (const execution of executions) {
|
|
265
|
+
printSetHeader(projectConfig, execution.set, cliOptions.json);
|
|
266
|
+
|
|
267
|
+
const executionCliOptions =
|
|
268
|
+
projectConfig.sets && cliOptions.datafilesDir
|
|
269
|
+
? {
|
|
270
|
+
...cliOptions,
|
|
271
|
+
datafilesDir: path.join(cliOptions.datafilesDir, execution.set),
|
|
272
|
+
}
|
|
273
|
+
: cliOptions;
|
|
274
|
+
|
|
275
|
+
await buildProject(
|
|
276
|
+
{
|
|
277
|
+
...deps,
|
|
278
|
+
projectConfig: execution.projectConfig,
|
|
279
|
+
datasource: execution.datasource,
|
|
280
|
+
},
|
|
281
|
+
{
|
|
282
|
+
...executionCliOptions,
|
|
283
|
+
revision: projectConfig.sets ? nextRevision : cliOptions.revision,
|
|
284
|
+
},
|
|
285
|
+
);
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
if (
|
|
289
|
+
projectConfig.sets &&
|
|
290
|
+
!cliOptions.json &&
|
|
291
|
+
(typeof cliOptions.stateFiles === "undefined" || cliOptions.stateFiles) &&
|
|
292
|
+
!cliOptions.revision
|
|
293
|
+
) {
|
|
294
|
+
await datasource.writeRevision(nextRevision);
|
|
295
|
+
console.log("");
|
|
296
|
+
console.log(CLI_FORMAT_GREEN, "Featurevisor sets built");
|
|
297
|
+
console.log(CLI_FORMAT_BOLD, `Latest project revision: ${nextRevision}`);
|
|
298
|
+
}
|
|
218
299
|
}
|
|
219
300
|
|
|
220
301
|
export const buildPlugin: Plugin = {
|
|
221
302
|
command: "build",
|
|
222
303
|
handler: async function ({ rootDirectoryPath, projectConfig, datasource, parsed }) {
|
|
223
|
-
|
|
304
|
+
if (parsed.print) {
|
|
305
|
+
parsed.json = true;
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
await buildProjectSets(
|
|
224
309
|
{
|
|
225
310
|
rootDirectoryPath,
|
|
226
311
|
projectConfig,
|
|
@@ -233,7 +318,7 @@ export const buildPlugin: Plugin = {
|
|
|
233
318
|
examples: [
|
|
234
319
|
{
|
|
235
320
|
command: "build",
|
|
236
|
-
description: "build datafiles for all environments and
|
|
321
|
+
description: "build datafiles for all environments and targets",
|
|
237
322
|
},
|
|
238
323
|
{
|
|
239
324
|
command: "build --revision=123",
|
|
@@ -244,7 +329,7 @@ export const buildPlugin: Plugin = {
|
|
|
244
329
|
description: "build datafiles for production environment",
|
|
245
330
|
},
|
|
246
331
|
{
|
|
247
|
-
command: "build --print --environment=production --feature=featureKey",
|
|
332
|
+
command: "build --print --environment=production --feature=featureKey --target=web",
|
|
248
333
|
description: "print datafile for a feature in production environment",
|
|
249
334
|
},
|
|
250
335
|
{
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import type { DatafileContent } from "@featurevisor/types";
|
|
2
|
+
|
|
3
|
+
import type { Dependencies } from "../dependencies";
|
|
4
|
+
import { resolveTargets } from "../targeting";
|
|
5
|
+
import { buildDatafile } from "./buildDatafile";
|
|
6
|
+
import { buildTargetDatafile } from "./buildProject";
|
|
7
|
+
|
|
8
|
+
export interface RuntimeDatafile {
|
|
9
|
+
target?: string;
|
|
10
|
+
datafile: DatafileContent;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export async function buildRuntimeDatafiles(
|
|
14
|
+
deps: Dependencies,
|
|
15
|
+
options: {
|
|
16
|
+
environment: string | false;
|
|
17
|
+
target?: string | string[];
|
|
18
|
+
revision: string;
|
|
19
|
+
inflate?: number;
|
|
20
|
+
},
|
|
21
|
+
): Promise<RuntimeDatafile[]> {
|
|
22
|
+
const { projectConfig, datasource } = deps;
|
|
23
|
+
const existingState = await datasource.readState(options.environment);
|
|
24
|
+
const targets = await resolveTargets(datasource, options.target, {
|
|
25
|
+
defaultToAll: false,
|
|
26
|
+
requireTargets: false,
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
if (targets.length === 0) {
|
|
30
|
+
const datafile = await buildDatafile(
|
|
31
|
+
projectConfig,
|
|
32
|
+
datasource,
|
|
33
|
+
{
|
|
34
|
+
revision: options.revision,
|
|
35
|
+
environment: options.environment,
|
|
36
|
+
inflate: options.inflate,
|
|
37
|
+
},
|
|
38
|
+
existingState,
|
|
39
|
+
);
|
|
40
|
+
return [{ datafile }];
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
return Promise.all(
|
|
44
|
+
targets.map(async (target) => ({
|
|
45
|
+
target: target.key,
|
|
46
|
+
datafile: await buildTargetDatafile({
|
|
47
|
+
projectConfig,
|
|
48
|
+
datasource,
|
|
49
|
+
target,
|
|
50
|
+
environment: options.environment,
|
|
51
|
+
existingState,
|
|
52
|
+
revision: options.revision,
|
|
53
|
+
inflate: options.inflate,
|
|
54
|
+
}),
|
|
55
|
+
})),
|
|
56
|
+
);
|
|
57
|
+
}
|
package/src/builder/index.ts
CHANGED
package/src/cli/cli.ts
CHANGED
|
@@ -51,11 +51,6 @@ export async function runCLI(runnerOptions: RunnerOptions) {
|
|
|
51
51
|
y = y.command({
|
|
52
52
|
command: plugin.command,
|
|
53
53
|
handler: async function (parsed: ParsedOptions) {
|
|
54
|
-
// @NOTE: in future, allow yargs options to be defined via plugins
|
|
55
|
-
if (parsed.schemaVersion && typeof parsed.schemaVersion !== "string") {
|
|
56
|
-
parsed.schemaVersion = parsed.schemaVersion.toString();
|
|
57
|
-
}
|
|
58
|
-
|
|
59
54
|
try {
|
|
60
55
|
const result = await plugin.handler({
|
|
61
56
|
rootDirectoryPath,
|
package/src/cli/plugins.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { Plugin } from "./cli";
|
|
2
|
+
import { createCatalogPlugin } from "@featurevisor/catalog";
|
|
2
3
|
|
|
3
4
|
import { initPlugin } from "../init";
|
|
4
5
|
import { lintPlugin } from "../linter";
|
|
@@ -13,7 +14,8 @@ import { evaluatePlugin } from "../evaluate";
|
|
|
13
14
|
import { assessDistributionPlugin } from "../assess-distribution";
|
|
14
15
|
import { infoPlugin } from "../info";
|
|
15
16
|
import { listPlugin } from "../list";
|
|
16
|
-
import {
|
|
17
|
+
import { promotePlugin } from "../promoter";
|
|
18
|
+
import { getProjectSetExecutions } from "../sets";
|
|
17
19
|
|
|
18
20
|
// that do not require an existing project
|
|
19
21
|
export const nonProjectPlugins: Plugin[] = [initPlugin];
|
|
@@ -32,7 +34,10 @@ export const projectBasedPlugins: Plugin[] = [
|
|
|
32
34
|
assessDistributionPlugin,
|
|
33
35
|
infoPlugin,
|
|
34
36
|
listPlugin,
|
|
35
|
-
|
|
37
|
+
promotePlugin,
|
|
38
|
+
createCatalogPlugin({
|
|
39
|
+
getProjectSetExecutions,
|
|
40
|
+
}),
|
|
36
41
|
];
|
|
37
42
|
|
|
38
43
|
export const commonPlugins: Plugin[] = [];
|
|
@@ -2,7 +2,12 @@ import * as fs from "fs";
|
|
|
2
2
|
import * as os from "os";
|
|
3
3
|
import * as path from "path";
|
|
4
4
|
|
|
5
|
-
import {
|
|
5
|
+
import {
|
|
6
|
+
getProjectConfig,
|
|
7
|
+
getProjectConfigForSet,
|
|
8
|
+
SETS_DIRECTORY_NAME,
|
|
9
|
+
TARGETS_DIRECTORY_NAME,
|
|
10
|
+
} from "./projectConfig";
|
|
6
11
|
|
|
7
12
|
function createTempProject(configBody: string) {
|
|
8
13
|
const tempRoot = fs.mkdtempSync(path.join(os.tmpdir(), "featurevisor-project-config-"));
|
|
@@ -11,21 +16,179 @@ function createTempProject(configBody: string) {
|
|
|
11
16
|
}
|
|
12
17
|
|
|
13
18
|
describe("core: projectConfig", () => {
|
|
14
|
-
it("sets
|
|
19
|
+
it("sets project defaults", () => {
|
|
15
20
|
const root = createTempProject("module.exports = {};");
|
|
16
21
|
const config = getProjectConfig(root);
|
|
17
22
|
|
|
18
|
-
expect(config.
|
|
19
|
-
expect(config.
|
|
23
|
+
expect(config.environments).toBeUndefined();
|
|
24
|
+
expect(config.namespaceCharacter).toBe(".");
|
|
25
|
+
expect(config.sets).toBe(false);
|
|
26
|
+
expect(config.promotionFlows).toBeUndefined();
|
|
27
|
+
expect(config.setsDirectoryPath).toBe(path.join(root, SETS_DIRECTORY_NAME));
|
|
28
|
+
expect(config.targetsDirectoryPath).toBe(path.join(root, TARGETS_DIRECTORY_NAME));
|
|
29
|
+
expect("scopes" in config).toBe(false);
|
|
30
|
+
expect("siteExportDirectoryPath" in config).toBe(false);
|
|
20
31
|
});
|
|
21
32
|
|
|
22
|
-
it("
|
|
33
|
+
it("silently ignores obsolete scopes configuration", () => {
|
|
23
34
|
const root = createTempProject(
|
|
24
|
-
|
|
35
|
+
'module.exports = { scopes: [{ name: "web", context: { platform: "web" } }] };',
|
|
25
36
|
);
|
|
37
|
+
const config = getProjectConfig(root);
|
|
38
|
+
|
|
39
|
+
expect("scopes" in config).toBe(false);
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
it("throws when sets is not boolean", () => {
|
|
43
|
+
const root = createTempProject("module.exports = { sets: 'yes' };");
|
|
44
|
+
|
|
45
|
+
expect(() => getProjectConfig(root)).toThrow("Invalid sets: yes. It must be a boolean.");
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
it("accepts environments when it is an array of strings", () => {
|
|
49
|
+
const root = createTempProject('module.exports = { environments: ["staging", "production"] };');
|
|
50
|
+
const config = getProjectConfig(root);
|
|
51
|
+
|
|
52
|
+
expect(config.environments).toEqual(["staging", "production"]);
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
it("throws when environments is present but not an array of strings", () => {
|
|
56
|
+
const cases = [
|
|
57
|
+
{
|
|
58
|
+
config: "module.exports = { environments: false };",
|
|
59
|
+
message: "Invalid environments: false. It must be an array of strings when defined.",
|
|
60
|
+
},
|
|
61
|
+
{
|
|
62
|
+
config: 'module.exports = { environments: "production" };',
|
|
63
|
+
message: "Invalid environments: production. It must be an array of strings when defined.",
|
|
64
|
+
},
|
|
65
|
+
{
|
|
66
|
+
config: "module.exports = { environments: { production: true } };",
|
|
67
|
+
message:
|
|
68
|
+
"Invalid environments: [object Object]. It must be an array of strings when defined.",
|
|
69
|
+
},
|
|
70
|
+
{
|
|
71
|
+
config: 'module.exports = { environments: ["production", 1] };',
|
|
72
|
+
message: "Invalid environments[1]: 1. It must be a string.",
|
|
73
|
+
},
|
|
74
|
+
];
|
|
75
|
+
|
|
76
|
+
for (const testCase of cases) {
|
|
77
|
+
const root = createTempProject(testCase.config);
|
|
78
|
+
|
|
79
|
+
expect(() => getProjectConfig(root)).toThrow(testCase.message);
|
|
80
|
+
}
|
|
81
|
+
});
|
|
82
|
+
|
|
83
|
+
it("accepts custom namespaceCharacter values including slash", () => {
|
|
84
|
+
const root = createTempProject('module.exports = { namespaceCharacter: "/" };');
|
|
85
|
+
const config = getProjectConfig(root);
|
|
86
|
+
|
|
87
|
+
expect(config.namespaceCharacter).toBe("/");
|
|
88
|
+
});
|
|
89
|
+
|
|
90
|
+
it("throws when namespaceCharacter is not a non-empty string", () => {
|
|
91
|
+
const cases = [
|
|
92
|
+
{
|
|
93
|
+
config: "module.exports = { namespaceCharacter: '' };",
|
|
94
|
+
message: "Invalid namespaceCharacter: . It must be a non-empty string.",
|
|
95
|
+
},
|
|
96
|
+
{
|
|
97
|
+
config: "module.exports = { namespaceCharacter: 1 };",
|
|
98
|
+
message: "Invalid namespaceCharacter: 1. It must be a non-empty string.",
|
|
99
|
+
},
|
|
100
|
+
];
|
|
101
|
+
|
|
102
|
+
for (const testCase of cases) {
|
|
103
|
+
const root = createTempProject(testCase.config);
|
|
26
104
|
|
|
27
|
-
|
|
28
|
-
|
|
105
|
+
expect(() => getProjectConfig(root)).toThrow(testCase.message);
|
|
106
|
+
}
|
|
107
|
+
});
|
|
108
|
+
|
|
109
|
+
it("accepts valid promotionFlows object rules", () => {
|
|
110
|
+
const root = createTempProject(
|
|
111
|
+
[
|
|
112
|
+
"module.exports = {",
|
|
113
|
+
" promotionFlows: [",
|
|
114
|
+
' { from: "dev", to: "staging" },',
|
|
115
|
+
' { from: "staging", to: "production" },',
|
|
116
|
+
" ],",
|
|
117
|
+
"};",
|
|
118
|
+
"",
|
|
119
|
+
].join("\n"),
|
|
120
|
+
);
|
|
121
|
+
|
|
122
|
+
const config = getProjectConfig(root);
|
|
123
|
+
|
|
124
|
+
expect(config.promotionFlows).toEqual([
|
|
125
|
+
{ from: "dev", to: "staging" },
|
|
126
|
+
{ from: "staging", to: "production" },
|
|
127
|
+
]);
|
|
128
|
+
});
|
|
129
|
+
|
|
130
|
+
it("rejects invalid promotionFlows shapes", () => {
|
|
131
|
+
const cases = [
|
|
132
|
+
{
|
|
133
|
+
config: "module.exports = { promotionFlows: true };",
|
|
134
|
+
message: "Invalid promotionFlows: true. It must be an array.",
|
|
135
|
+
},
|
|
136
|
+
{
|
|
137
|
+
config: 'module.exports = { promotionFlows: ["dev"] };',
|
|
138
|
+
message:
|
|
139
|
+
'Invalid promotionFlows[0]: dev. Each entry must be an object with exactly "from" and "to" string fields.',
|
|
140
|
+
},
|
|
141
|
+
{
|
|
142
|
+
config: 'module.exports = { promotionFlows: [{ from: "dev" }] };',
|
|
143
|
+
message:
|
|
144
|
+
'Invalid promotionFlows[0]: {"from":"dev"}. Each entry must contain exactly "from" and "to".',
|
|
145
|
+
},
|
|
146
|
+
{
|
|
147
|
+
config:
|
|
148
|
+
'module.exports = { promotionFlows: [{ from: "dev", to: "staging", note: true }] };',
|
|
149
|
+
message:
|
|
150
|
+
'Invalid promotionFlows[0]: {"from":"dev","to":"staging","note":true}. Each entry must contain exactly "from" and "to".',
|
|
151
|
+
},
|
|
152
|
+
{
|
|
153
|
+
config: 'module.exports = { promotionFlows: [{ from: "dev", to: 1 }] };',
|
|
154
|
+
message:
|
|
155
|
+
'Invalid promotionFlows[0]: {"from":"dev","to":1}. "from" and "to" must be strings.',
|
|
156
|
+
},
|
|
157
|
+
];
|
|
158
|
+
|
|
159
|
+
for (const testCase of cases) {
|
|
160
|
+
const root = createTempProject(testCase.config);
|
|
161
|
+
|
|
162
|
+
expect(() => getProjectConfig(root)).toThrow(testCase.message);
|
|
163
|
+
}
|
|
164
|
+
});
|
|
165
|
+
|
|
166
|
+
it("remaps project config paths for a set", () => {
|
|
167
|
+
const root = createTempProject("module.exports = { sets: true };");
|
|
168
|
+
const config = getProjectConfig(root);
|
|
169
|
+
const setConfig = getProjectConfigForSet(config, "staging");
|
|
170
|
+
const setRoot = path.join(root, "sets", "staging");
|
|
171
|
+
|
|
172
|
+
expect(setConfig.featuresDirectoryPath).toBe(path.join(setRoot, "features"));
|
|
173
|
+
expect(setConfig.environments).toBeUndefined();
|
|
174
|
+
expect(setConfig.namespaceCharacter).toBe(".");
|
|
175
|
+
expect(setConfig.segmentsDirectoryPath).toBe(path.join(setRoot, "segments"));
|
|
176
|
+
expect(setConfig.attributesDirectoryPath).toBe(path.join(setRoot, "attributes"));
|
|
177
|
+
expect(setConfig.groupsDirectoryPath).toBe(path.join(setRoot, "groups"));
|
|
178
|
+
expect(setConfig.schemasDirectoryPath).toBe(path.join(setRoot, "schemas"));
|
|
179
|
+
expect(setConfig.targetsDirectoryPath).toBe(path.join(setRoot, "targets"));
|
|
180
|
+
expect(setConfig.testsDirectoryPath).toBe(path.join(setRoot, "tests"));
|
|
181
|
+
expect(setConfig.stateDirectoryPath).toBe(path.join(root, ".featurevisor", "sets", "staging"));
|
|
182
|
+
expect(setConfig.datafilesDirectoryPath).toBe(path.join(root, "datafiles", "staging"));
|
|
183
|
+
});
|
|
184
|
+
|
|
185
|
+
it("preserves configured environments when remapping project config for a set", () => {
|
|
186
|
+
const root = createTempProject(
|
|
187
|
+
'module.exports = { sets: true, environments: ["staging", "production"] };',
|
|
29
188
|
);
|
|
189
|
+
const config = getProjectConfig(root);
|
|
190
|
+
const setConfig = getProjectConfigForSet(config, "staging");
|
|
191
|
+
|
|
192
|
+
expect(setConfig.environments).toEqual(["staging", "production"]);
|
|
30
193
|
});
|
|
31
194
|
});
|