-
Notifications
You must be signed in to change notification settings - Fork 61
/
Copy pathutils.ts
100 lines (92 loc) · 3.14 KB
/
utils.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
/*
* Copyright OpenSearch Contributors
* SPDX-License-Identifier: Apache-2.0
*/
import { Readable } from 'stream';
import { createSavedObjectsStreamFromNdJson } from '../../../../../../src/core/server/saved_objects/routes/utils';
import { IntegrationReader } from './integration_reader';
export async function tryParseNDJson(content: string): Promise<object[] | null> {
try {
const objects = await createSavedObjectsStreamFromNdJson(Readable.from(content));
return await objects.toArray();
} catch (err) {
return null;
}
}
/**
* Check IntegrationReader nested dependencies for validity,
* as a supplement to shallow config validation.
*
* @returns a Result indicating whether the integration is valid, holding the integration's config.
*/
export async function deepCheck(reader: IntegrationReader): Promise<Result<IntegrationConfig>> {
const configResult = await reader.getConfig();
if (!configResult.ok) {
return configResult;
}
// Deep checks not included in default config validation
const assets = await reader.getAssets();
// Check if there was an error retrieving assets
if (!assets.ok) {
return { ok: false, error: assets.error };
}
// Validate that at least one asset exists for the integration
if (assets.value.length === 0) {
return { ok: false, error: new Error('An integration must have at least one asset') };
}
return configResult;
}
/**
* Helper method: Convert an Array<Result<type>> to Result<Array<type>>.
*
* @param results The list of results to fold.
* @returns A single result object with values in an array, or an error result.
*/
export const foldResults = <T>(results: Array<Result<T>>) =>
results.reduce(
(result, currentValue) => {
if (!result.ok) {
return result;
}
if (!currentValue.ok) {
return currentValue;
}
result.value.push(currentValue.value);
return result;
},
{ ok: true, value: [] } as Result<T[]>
);
/**
* Remove all fields from SerializedIntegration not present in IntegrationConfig.
*
* @param rawConfig The raw config to prune
* @returns A config with all data fields removed
*/
export const pruneConfig = (
rawConfig: IntegrationConfig | SerializedIntegration
): IntegrationConfig => {
// Hacky workaround: we currently only need to prune 'data' fields, so just remove every 'data'.
// Lots of risky conversion in this method, so scope it to here and rewrite if more granular
// pruning is needed.
const prunePart = <T>(part: T): T => {
const result = {} as { [key: string]: unknown };
for (const [key, value] of Object.entries(part as { [key: string]: unknown })) {
if (key === 'data') {
continue;
} else if (Array.isArray(value)) {
result[key] = value.map((item) => {
if (item instanceof Object && item !== null) {
return prunePart(item);
}
return item;
});
} else if (value instanceof Object && value !== null) {
result[key] = prunePart(value as { [key: string]: unknown });
} else {
result[key] = value;
}
}
return (result as unknown) as T;
};
return prunePart(rawConfig);
};