@featurevisor/core 0.53.3 → 0.53.5

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 (73) hide show
  1. package/.eslintcache +1 -1
  2. package/CHANGELOG.md +16 -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/traffic.js.html +1 -1
  8. package/coverage/lcov-report/src/builder/allocator.ts.html +1 -1
  9. package/coverage/lcov-report/src/builder/index.html +1 -1
  10. package/coverage/lcov-report/src/builder/traffic.ts.html +1 -1
  11. package/lib/builder/buildProject.d.ts +2 -2
  12. package/lib/builder/buildProject.js +23 -33
  13. package/lib/builder/buildProject.js.map +1 -1
  14. package/lib/datasource/datasource.d.ts +8 -2
  15. package/lib/datasource/datasource.js +43 -2
  16. package/lib/datasource/datasource.js.map +1 -1
  17. package/lib/datasource/parsers.js +2 -2
  18. package/lib/datasource/parsers.js.map +1 -1
  19. package/lib/dependencies.d.ts +11 -0
  20. package/lib/dependencies.js +3 -0
  21. package/lib/dependencies.js.map +1 -0
  22. package/lib/find-duplicate-segments/index.d.ts +2 -2
  23. package/lib/find-duplicate-segments/index.js +2 -3
  24. package/lib/find-duplicate-segments/index.js.map +1 -1
  25. package/lib/generate-code/index.d.ts +2 -2
  26. package/lib/generate-code/index.js +4 -5
  27. package/lib/generate-code/index.js.map +1 -1
  28. package/lib/generate-code/typescript.d.ts +2 -3
  29. package/lib/generate-code/typescript.js +3 -2
  30. package/lib/generate-code/typescript.js.map +1 -1
  31. package/lib/index.d.ts +2 -0
  32. package/lib/index.js +2 -0
  33. package/lib/index.js.map +1 -1
  34. package/lib/linter/lintProject.d.ts +2 -2
  35. package/lib/linter/lintProject.js +5 -11
  36. package/lib/linter/lintProject.js.map +1 -1
  37. package/lib/restore.d.ts +2 -2
  38. package/lib/restore.js +3 -2
  39. package/lib/restore.js.map +1 -1
  40. package/lib/site/exportSite.d.ts +2 -2
  41. package/lib/site/exportSite.js +4 -3
  42. package/lib/site/exportSite.js.map +1 -1
  43. package/lib/site/generateSiteSearchIndex.d.ts +2 -2
  44. package/lib/site/generateSiteSearchIndex.js +3 -4
  45. package/lib/site/generateSiteSearchIndex.js.map +1 -1
  46. package/lib/site/serveSite.d.ts +2 -2
  47. package/lib/site/serveSite.js +2 -2
  48. package/lib/site/serveSite.js.map +1 -1
  49. package/lib/tester/testFeature.js +6 -4
  50. package/lib/tester/testFeature.js.map +1 -1
  51. package/lib/tester/testProject.d.ts +2 -2
  52. package/lib/tester/testProject.js +3 -4
  53. package/lib/tester/testProject.js.map +1 -1
  54. package/lib/utils.d.ts +0 -2
  55. package/lib/utils.js +1 -15
  56. package/lib/utils.js.map +1 -1
  57. package/package.json +2 -2
  58. package/src/builder/buildProject.ts +6 -29
  59. package/src/datasource/datasource.ts +55 -2
  60. package/src/datasource/parsers.ts +2 -2
  61. package/src/dependencies.ts +13 -0
  62. package/src/find-duplicate-segments/index.ts +3 -8
  63. package/src/generate-code/index.ts +5 -12
  64. package/src/generate-code/typescript.ts +4 -8
  65. package/src/index.ts +2 -0
  66. package/src/linter/lintProject.ts +39 -47
  67. package/src/restore.ts +4 -2
  68. package/src/site/exportSite.ts +5 -9
  69. package/src/site/generateSiteSearchIndex.ts +4 -5
  70. package/src/site/serveSite.ts +4 -6
  71. package/src/tester/testFeature.ts +4 -7
  72. package/src/tester/testProject.ts +4 -8
  73. package/src/utils.ts +0 -18
@@ -1,13 +1,31 @@
1
1
  import * as path from "path";
2
2
  import * as fs from "fs";
3
3
 
4
- import { ParsedFeature, Segment, Attribute, Group, FeatureKey, Test } from "@featurevisor/types";
4
+ import * as mkdirp from "mkdirp";
5
+
6
+ import {
7
+ ParsedFeature,
8
+ Segment,
9
+ Attribute,
10
+ Group,
11
+ FeatureKey,
12
+ Test,
13
+ EnvironmentKey,
14
+ ExistingState,
15
+ } from "@featurevisor/types";
5
16
 
6
17
  import { ProjectConfig } from "../config";
7
18
  import { parsers } from "./parsers";
8
19
 
9
20
  export type EntityType = "feature" | "group" | "segment" | "attribute" | "test";
10
21
 
22
+ export function getExistingStateFilePath(
23
+ projectConfig: ProjectConfig,
24
+ environment: EnvironmentKey,
25
+ ): string {
26
+ return path.join(projectConfig.stateDirectoryPath, `existing-state-${environment}.json`);
27
+ }
28
+
11
29
  export class Datasource {
12
30
  private extension;
13
31
  private parse;
@@ -43,11 +61,15 @@ export class Datasource {
43
61
  }
44
62
 
45
63
  /**
46
- * Common methods
64
+ * Common methods for entities
47
65
  */
48
66
  async listEntities(entityType: EntityType): Promise<string[]> {
49
67
  const directoryPath = this.getEntityDirectoryPath(entityType);
50
68
 
69
+ if (!fs.existsSync(directoryPath)) {
70
+ return [];
71
+ }
72
+
51
73
  return fs
52
74
  .readdirSync(directoryPath)
53
75
  .filter((fileName) => fileName.endsWith(`.${this.extension}`))
@@ -92,6 +114,37 @@ export class Datasource {
92
114
  return this.parse(entityContent) as T;
93
115
  }
94
116
 
117
+ /**
118
+ * State
119
+ */
120
+ async readState(environment: EnvironmentKey): Promise<ExistingState> {
121
+ const filePath = getExistingStateFilePath(this.config, environment);
122
+
123
+ if (!fs.existsSync(filePath)) {
124
+ return {
125
+ features: {},
126
+ };
127
+ }
128
+
129
+ return require(filePath);
130
+ }
131
+
132
+ async writeState(environment: EnvironmentKey, existingState: ExistingState) {
133
+ const filePath = getExistingStateFilePath(this.config, environment);
134
+
135
+ if (!fs.existsSync(this.config.stateDirectoryPath)) {
136
+ mkdirp.sync(this.config.stateDirectoryPath);
137
+ }
138
+ fs.writeFileSync(
139
+ filePath,
140
+ this.config.prettyState
141
+ ? JSON.stringify(existingState, null, 2)
142
+ : JSON.stringify(existingState),
143
+ );
144
+
145
+ fs.writeFileSync(filePath, JSON.stringify(existingState, null, 2));
146
+ }
147
+
95
148
  /**
96
149
  * Entity specific methods
97
150
  */
@@ -1,4 +1,4 @@
1
- import { parseYaml } from "../utils";
1
+ import * as YAML from "js-yaml";
2
2
 
3
3
  /**
4
4
  * If we want to add more built-in parsers,
@@ -8,7 +8,7 @@ import { parseYaml } from "../utils";
8
8
  export const parsers = {
9
9
  // extension => function
10
10
  yml(content: string) {
11
- return parseYaml(content);
11
+ return YAML.load(content);
12
12
  },
13
13
 
14
14
  json(content: string) {
@@ -0,0 +1,13 @@
1
+ import { ProjectConfig } from "./config";
2
+ import { Datasource } from "./datasource";
3
+
4
+ export interface Options {
5
+ [key: string]: any;
6
+ }
7
+
8
+ export interface Dependencies {
9
+ rootDirectoryPath: string;
10
+ projectConfig: ProjectConfig;
11
+ datasource: Datasource;
12
+ options: Options;
13
+ }
@@ -1,13 +1,8 @@
1
- import { Datasource } from "../datasource";
2
- import { ProjectConfig } from "../config";
3
-
4
1
  import { findDuplicateSegments } from "./findDuplicateSegments";
2
+ import { Dependencies } from "../dependencies";
5
3
 
6
- export async function findDuplicateSegmentsInProject(
7
- rootDirectoryPath,
8
- projectConfig: ProjectConfig,
9
- ) {
10
- const datasource = new Datasource(projectConfig);
4
+ export async function findDuplicateSegmentsInProject(deps: Dependencies) {
5
+ const { datasource } = deps;
11
6
 
12
7
  const duplicates = await findDuplicateSegments(datasource);
13
8
 
@@ -3,9 +3,8 @@ import * as path from "path";
3
3
 
4
4
  import * as mkdirp from "mkdirp";
5
5
 
6
- import { ProjectConfig } from "../config";
7
- import { Datasource } from "../datasource";
8
6
  import { generateTypeScriptCodeForProject } from "./typescript";
7
+ import { Dependencies } from "../dependencies";
9
8
 
10
9
  export const ALLOWED_LANGUAGES_FOR_CODE_GENERATION = ["typescript"];
11
10
 
@@ -15,10 +14,11 @@ export interface GenerateCodeCLIOptions {
15
14
  }
16
15
 
17
16
  export async function generateCodeForProject(
18
- rootDirectoryPath,
19
- projectConfig: ProjectConfig,
17
+ deps: Dependencies,
20
18
  cliOptions: GenerateCodeCLIOptions,
21
19
  ) {
20
+ const { rootDirectoryPath } = deps;
21
+
22
22
  if (!cliOptions.language) {
23
23
  throw new Error("Option `--language` is required");
24
24
  }
@@ -27,8 +27,6 @@ export async function generateCodeForProject(
27
27
  throw new Error("Option `--out-dir` is required");
28
28
  }
29
29
 
30
- const datasource = new Datasource(projectConfig);
31
-
32
30
  const absolutePath = path.resolve(rootDirectoryPath, cliOptions.outDir);
33
31
 
34
32
  if (!fs.existsSync(absolutePath)) {
@@ -47,12 +45,7 @@ export async function generateCodeForProject(
47
45
  }
48
46
 
49
47
  if (cliOptions.language === "typescript") {
50
- return await generateTypeScriptCodeForProject(
51
- rootDirectoryPath,
52
- projectConfig,
53
- datasource,
54
- absolutePath,
55
- );
48
+ return await generateTypeScriptCodeForProject(deps, absolutePath);
56
49
  }
57
50
 
58
51
  throw new Error(`Language ${cliOptions.language} is not supported`);
@@ -1,9 +1,8 @@
1
1
  import * as fs from "fs";
2
2
  import * as path from "path";
3
3
 
4
- import { ProjectConfig } from "../config";
5
- import { Datasource } from "../datasource";
6
4
  import { Attribute } from "@featurevisor/types";
5
+ import { Dependencies } from "../dependencies";
7
6
 
8
7
  function convertFeaturevisorTypeToTypeScriptType(featurevisorType: string) {
9
8
  switch (featurevisorType) {
@@ -87,12 +86,9 @@ export function getInstance(): FeaturevisorInstance {
87
86
  }
88
87
  `.trimStart();
89
88
 
90
- export async function generateTypeScriptCodeForProject(
91
- rootDirectoryPath: string,
92
- projectConfig: ProjectConfig,
93
- datasource: Datasource,
94
- outputPath: string,
95
- ) {
89
+ export async function generateTypeScriptCodeForProject(deps: Dependencies, outputPath: string) {
90
+ const { rootDirectoryPath, datasource } = deps;
91
+
96
92
  console.log("\nGenerating TypeScript code...\n");
97
93
 
98
94
  // instance
package/src/index.ts CHANGED
@@ -7,3 +7,5 @@ export * from "./site";
7
7
  export * from "./generate-code";
8
8
  export * from "./restore";
9
9
  export * from "./find-duplicate-segments";
10
+ export * from "./dependencies";
11
+ export * from "./datasource";
@@ -1,11 +1,6 @@
1
1
  // for use in node only
2
- import * as fs from "fs";
3
-
4
2
  import * as Joi from "joi";
5
3
 
6
- import { Datasource } from "../datasource";
7
- import { ProjectConfig } from "../config";
8
-
9
4
  import { getAttributeJoiSchema } from "./attributeSchema";
10
5
  import { getConditionsJoiSchema } from "./conditionSchema";
11
6
  import { getSegmentJoiSchema } from "./segmentSchema";
@@ -15,10 +10,12 @@ import { getTestsJoiSchema } from "./testSchema";
15
10
 
16
11
  import { checkForCircularDependencyInRequired } from "./checkCircularDependency";
17
12
  import { printJoiError } from "./printJoiError";
13
+ import { Dependencies } from "../dependencies";
14
+
15
+ export async function lintProject(deps: Dependencies): Promise<boolean> {
16
+ const { projectConfig, datasource } = deps;
18
17
 
19
- export async function lintProject(projectConfig: ProjectConfig): Promise<boolean> {
20
18
  let hasError = false;
21
- const datasource = new Datasource(projectConfig);
22
19
 
23
20
  const availableAttributeKeys: string[] = [];
24
21
  const availableSegmentKeys: string[] = [];
@@ -116,62 +113,57 @@ export async function lintProject(projectConfig: ProjectConfig): Promise<boolean
116
113
  }
117
114
 
118
115
  // lint groups
116
+ const groups = await datasource.listGroups();
117
+ console.log(`\nLinting ${groups.length} groups...\n`);
119
118
 
120
- if (fs.existsSync(projectConfig.groupsDirectoryPath)) {
121
- const groups = await datasource.listGroups();
122
- console.log(`\nLinting ${groups.length} groups...\n`);
119
+ // @TODO: feature it slots can be from availableFeatureKeys only
120
+ const groupJoiSchema = getGroupJoiSchema(projectConfig, datasource, availableFeatureKeys);
123
121
 
124
- // @TODO: feature it slots can be from availableFeatureKeys only
125
- const groupJoiSchema = getGroupJoiSchema(projectConfig, datasource, availableFeatureKeys);
122
+ for (const key of groups) {
123
+ const parsed = await datasource.readGroup(key);
126
124
 
127
- for (const key of groups) {
128
- const parsed = await datasource.readGroup(key);
129
-
130
- try {
131
- await groupJoiSchema.validateAsync(parsed);
132
- } catch (e) {
133
- console.log(" =>", key);
134
-
135
- if (e instanceof Joi.ValidationError) {
136
- printJoiError(e);
137
- } else {
138
- console.log(e);
139
- }
125
+ try {
126
+ await groupJoiSchema.validateAsync(parsed);
127
+ } catch (e) {
128
+ console.log(" =>", key);
140
129
 
141
- hasError = true;
130
+ if (e instanceof Joi.ValidationError) {
131
+ printJoiError(e);
132
+ } else {
133
+ console.log(e);
142
134
  }
135
+
136
+ hasError = true;
143
137
  }
144
138
  }
145
139
 
146
140
  // @TODO: feature cannot exist in multiple groups
147
141
 
148
142
  // lint tests
149
- if (fs.existsSync(projectConfig.testsDirectoryPath)) {
150
- const tests = await datasource.listTests();
151
- console.log(`\nLinting ${tests.length} tests...\n`);
143
+ const tests = await datasource.listTests();
144
+ console.log(`\nLinting ${tests.length} tests...\n`);
152
145
 
153
- const testsJoiSchema = getTestsJoiSchema(
154
- projectConfig,
155
- availableFeatureKeys,
156
- availableSegmentKeys,
157
- );
146
+ const testsJoiSchema = getTestsJoiSchema(
147
+ projectConfig,
148
+ availableFeatureKeys,
149
+ availableSegmentKeys,
150
+ );
158
151
 
159
- for (const key of tests) {
160
- const parsed = await datasource.readTest(key);
152
+ for (const key of tests) {
153
+ const parsed = await datasource.readTest(key);
161
154
 
162
- try {
163
- await testsJoiSchema.validateAsync(parsed);
164
- } catch (e) {
165
- console.log(" =>", key);
166
-
167
- if (e instanceof Joi.ValidationError) {
168
- printJoiError(e);
169
- } else {
170
- console.log(e);
171
- }
155
+ try {
156
+ await testsJoiSchema.validateAsync(parsed);
157
+ } catch (e) {
158
+ console.log(" =>", key);
172
159
 
173
- hasError = true;
160
+ if (e instanceof Joi.ValidationError) {
161
+ printJoiError(e);
162
+ } else {
163
+ console.log(e);
174
164
  }
165
+
166
+ hasError = true;
175
167
  }
176
168
  }
177
169
 
package/src/restore.ts CHANGED
@@ -1,9 +1,11 @@
1
1
  import * as path from "path";
2
2
  import { execSync } from "child_process";
3
3
 
4
- import { ProjectConfig } from "./config";
4
+ import { Dependencies } from "./dependencies";
5
+
6
+ export async function restoreProject(deps: Dependencies) {
7
+ const { rootDirectoryPath, projectConfig } = deps;
5
8
 
6
- export async function restoreProject(rootDirectoryPath, projectConfig: ProjectConfig) {
7
9
  const relativeStateDirPath = path.relative(rootDirectoryPath, projectConfig.stateDirectoryPath);
8
10
  const cmd = `git checkout -- ${relativeStateDirPath}${path.sep}`;
9
11
 
@@ -3,13 +3,14 @@ import * as path from "path";
3
3
 
4
4
  import * as mkdirp from "mkdirp";
5
5
 
6
- import { ProjectConfig } from "../config";
7
-
8
6
  import { generateHistory } from "./generateHistory";
9
7
  import { getRepoDetails } from "./getRepoDetails";
10
8
  import { generateSiteSearchIndex } from "./generateSiteSearchIndex";
9
+ import { Dependencies } from "../dependencies";
10
+
11
+ export async function exportSite(deps: Dependencies) {
12
+ const { rootDirectoryPath, projectConfig } = deps;
11
13
 
12
- export async function exportSite(rootDirectoryPath: string, projectConfig: ProjectConfig) {
13
14
  const hasError = false;
14
15
 
15
16
  mkdirp.sync(projectConfig.siteExportDirectoryPath);
@@ -30,12 +31,7 @@ export async function exportSite(rootDirectoryPath: string, projectConfig: Proje
30
31
 
31
32
  // site search index
32
33
  const repoDetails = getRepoDetails();
33
- const searchIndex = await generateSiteSearchIndex(
34
- rootDirectoryPath,
35
- projectConfig,
36
- fullHistory,
37
- repoDetails,
38
- );
34
+ const searchIndex = await generateSiteSearchIndex(deps, fullHistory, repoDetails);
39
35
  const searchIndexFilePath = path.join(projectConfig.siteExportDirectoryPath, "search-index.json");
40
36
  fs.writeFileSync(searchIndexFilePath, JSON.stringify(searchIndex));
41
37
  console.log(`Site search index written at: ${searchIndexFilePath}`);
@@ -7,20 +7,20 @@ import {
7
7
  Condition,
8
8
  } from "@featurevisor/types";
9
9
 
10
- import { Datasource } from "../datasource";
11
- import { ProjectConfig } from "../config";
12
10
  import { extractAttributeKeysFromConditions, extractSegmentKeysFromGroupSegments } from "../utils";
13
11
 
14
12
  import { getRelativePaths } from "./getRelativePaths";
15
13
  import { getLastModifiedFromHistory } from "./getLastModifiedFromHistory";
16
14
  import { RepoDetails } from "./getRepoDetails";
15
+ import { Dependencies } from "../dependencies";
17
16
 
18
17
  export async function generateSiteSearchIndex(
19
- rootDirectoryPath: string,
20
- projectConfig: ProjectConfig,
18
+ deps: Dependencies,
21
19
  fullHistory: HistoryEntry[],
22
20
  repoDetails: RepoDetails | undefined,
23
21
  ): Promise<SearchIndex> {
22
+ const { rootDirectoryPath, projectConfig, datasource } = deps;
23
+
24
24
  const result: SearchIndex = {
25
25
  links: undefined,
26
26
  entities: {
@@ -29,7 +29,6 @@ export async function generateSiteSearchIndex(
29
29
  features: [],
30
30
  },
31
31
  };
32
- const datasource = new Datasource(projectConfig);
33
32
 
34
33
  /**
35
34
  * Links
@@ -2,13 +2,11 @@ import * as fs from "fs";
2
2
  import * as path from "path";
3
3
  import * as http from "http";
4
4
 
5
- import { ProjectConfig } from "../config";
5
+ import { Dependencies } from "../dependencies";
6
+
7
+ export function serveSite(deps: Dependencies) {
8
+ const { projectConfig, options } = deps;
6
9
 
7
- export function serveSite(
8
- rootDirectoryPath: string,
9
- projectConfig: ProjectConfig,
10
- options: any = {},
11
- ) {
12
10
  const port = options.p || 3000;
13
11
 
14
12
  http
@@ -1,11 +1,9 @@
1
- import * as fs from "fs";
2
-
3
- import { TestFeature, ExistingState } from "@featurevisor/types";
1
+ import { TestFeature } from "@featurevisor/types";
4
2
  import { createInstance, MAX_BUCKETED_NUMBER } from "@featurevisor/sdk";
5
3
 
6
4
  import { Datasource } from "../datasource";
7
5
  import { ProjectConfig } from "../config";
8
- import { buildDatafile, getExistingStateFilePath } from "../builder";
6
+ import { buildDatafile } from "../builder";
9
7
  import { SCHEMA_VERSION } from "../config";
10
8
 
11
9
  import { checkIfArraysAreEqual } from "./checkIfArraysAreEqual";
@@ -31,6 +29,7 @@ export async function testFeature(
31
29
  const requiredChain = await datasource.getRequiredFeaturesChain(test.feature);
32
30
  const featuresToInclude = Array.from(requiredChain);
33
31
 
32
+ const existingState = await datasource.readState(assertion.environment);
34
33
  const datafileContent = await buildDatafile(
35
34
  projectConfig,
36
35
  datasource,
@@ -40,9 +39,7 @@ export async function testFeature(
40
39
  environment: assertion.environment,
41
40
  features: featuresToInclude,
42
41
  },
43
- JSON.parse(
44
- fs.readFileSync(getExistingStateFilePath(projectConfig, assertion.environment), "utf8"),
45
- ) as ExistingState,
42
+ existingState,
46
43
  );
47
44
 
48
45
  const sdk = createInstance({
@@ -2,19 +2,15 @@ import * as fs from "fs";
2
2
 
3
3
  import { TestSegment, TestFeature } from "@featurevisor/types";
4
4
 
5
- import { ProjectConfig } from "../config";
6
- import { Datasource } from "../datasource";
7
-
8
5
  import { testSegment } from "./testSegment";
9
6
  import { testFeature } from "./testFeature";
10
7
  import { CLI_FORMAT_BOLD, CLI_FORMAT_GREEN, CLI_FORMAT_RED } from "./cliFormat";
8
+ import { Dependencies } from "../dependencies";
9
+
10
+ export async function testProject(deps: Dependencies): Promise<boolean> {
11
+ const { rootDirectoryPath, projectConfig, datasource } = deps;
11
12
 
12
- export async function testProject(
13
- rootDirectoryPath: string,
14
- projectConfig: ProjectConfig,
15
- ): Promise<boolean> {
16
13
  let hasError = false;
17
- const datasource = new Datasource(projectConfig);
18
14
 
19
15
  if (!fs.existsSync(projectConfig.testsDirectoryPath)) {
20
16
  console.error(`Tests directory does not exist: ${projectConfig.testsDirectoryPath}`);
package/src/utils.ts CHANGED
@@ -1,23 +1,5 @@
1
- import * as fs from "fs";
2
- import * as path from "path";
3
-
4
- import * as yaml from "js-yaml";
5
-
6
1
  import { Condition, AttributeKey, GroupSegment, SegmentKey } from "@featurevisor/types";
7
2
 
8
- export function getYAMLFiles(directoryPath: string) {
9
- const files = fs.readdirSync(directoryPath);
10
- const yamlFiles = files.filter((file) => file.endsWith(".yml"));
11
-
12
- return yamlFiles.map((file) => path.join(directoryPath, file));
13
- }
14
-
15
- export function parseYaml(content: string) {
16
- const parsed = yaml.load(content);
17
-
18
- return parsed;
19
- }
20
-
21
3
  export function extractSegmentKeysFromGroupSegments(
22
4
  segments: GroupSegment | GroupSegment[],
23
5
  ): Set<SegmentKey> {