Co-authored-by: spalger <spalger@users.noreply.github.com> Co-authored-by: Spencer <email@spalger.com> Co-authored-by: spalger <spalger@users.noreply.github.com>
This commit is contained in:
parent
36c02ae31c
commit
fd17b5975e
|
@ -8,7 +8,7 @@
|
||||||
|
|
||||||
export interface ManagedConfigKey {
|
export interface ManagedConfigKey {
|
||||||
key: string;
|
key: string;
|
||||||
value: Record<string, any>;
|
value: string | Record<string, any>;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -37,4 +37,9 @@ export const MANAGED_CONFIG_KEYS: ManagedConfigKey[] = [
|
||||||
['**/packages/kbn-pm/dist/index.js']: true,
|
['**/packages/kbn-pm/dist/index.js']: true,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
key: 'typescript.tsdk',
|
||||||
|
// we use a relative path here so that it works with remote vscode connections
|
||||||
|
value: './node_modules/typescript/lib',
|
||||||
|
},
|
||||||
];
|
];
|
||||||
|
|
|
@ -22,6 +22,10 @@ const TEST_KEYS: ManagedConfigKey[] = [
|
||||||
world: [1, 2, 3],
|
world: [1, 2, 3],
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
key: 'stringKey',
|
||||||
|
value: 'foo',
|
||||||
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
const run = (json?: string) => updateVscodeConfig(TEST_KEYS, '', json);
|
const run = (json?: string) => updateVscodeConfig(TEST_KEYS, '', json);
|
||||||
|
@ -35,7 +39,9 @@ it('updates the passed JSON with the managed settings', () => {
|
||||||
"hello": true,
|
"hello": true,
|
||||||
// @managed
|
// @managed
|
||||||
"world": [1, 2, 3]
|
"world": [1, 2, 3]
|
||||||
}
|
},
|
||||||
|
// @managed
|
||||||
|
"stringKey": "foo"
|
||||||
}
|
}
|
||||||
|
|
||||||
`);
|
`);
|
||||||
|
@ -50,7 +56,9 @@ it('initialized empty or undefined json values', () => {
|
||||||
"hello": true,
|
"hello": true,
|
||||||
// @managed
|
// @managed
|
||||||
"world": [1, 2, 3]
|
"world": [1, 2, 3]
|
||||||
}
|
},
|
||||||
|
// @managed
|
||||||
|
"stringKey": "foo"
|
||||||
}
|
}
|
||||||
|
|
||||||
`);
|
`);
|
||||||
|
@ -63,14 +71,16 @@ it('initialized empty or undefined json values', () => {
|
||||||
"hello": true,
|
"hello": true,
|
||||||
// @managed
|
// @managed
|
||||||
"world": [1, 2, 3]
|
"world": [1, 2, 3]
|
||||||
}
|
},
|
||||||
|
// @managed
|
||||||
|
"stringKey": "foo"
|
||||||
}
|
}
|
||||||
|
|
||||||
`);
|
`);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('replaces conflicting managed keys which do not have object values', () => {
|
it('replaces conflicting managed keys which do not have matching value types', () => {
|
||||||
expect(run(`{ "key": false }`)).toMatchInlineSnapshot(`
|
expect(run(`{ "key": false, "stringKey": { "a": "B" } }`)).toMatchInlineSnapshot(`
|
||||||
// @managed
|
// @managed
|
||||||
{
|
{
|
||||||
"key": {
|
"key": {
|
||||||
|
@ -78,7 +88,9 @@ it('replaces conflicting managed keys which do not have object values', () => {
|
||||||
"hello": true,
|
"hello": true,
|
||||||
// @managed
|
// @managed
|
||||||
"world": [1, 2, 3]
|
"world": [1, 2, 3]
|
||||||
}
|
},
|
||||||
|
// @managed
|
||||||
|
"stringKey": "foo"
|
||||||
}
|
}
|
||||||
|
|
||||||
`);
|
`);
|
||||||
|
@ -122,7 +134,9 @@ it('persists comments in the original file', () => {
|
||||||
"hello": true,
|
"hello": true,
|
||||||
// @managed
|
// @managed
|
||||||
"world": [1, 2, 3]
|
"world": [1, 2, 3]
|
||||||
}
|
},
|
||||||
|
// @managed
|
||||||
|
"stringKey": "foo"
|
||||||
}
|
}
|
||||||
|
|
||||||
`);
|
`);
|
||||||
|
@ -148,7 +162,9 @@ it('overrides old values for managed keys', () => {
|
||||||
"hello": true,
|
"hello": true,
|
||||||
// @managed
|
// @managed
|
||||||
"world": [1, 2, 3]
|
"world": [1, 2, 3]
|
||||||
}
|
},
|
||||||
|
// @managed
|
||||||
|
"stringKey": "foo"
|
||||||
}
|
}
|
||||||
|
|
||||||
`);
|
`);
|
||||||
|
@ -176,7 +192,9 @@ it('does not modify properties with leading `// self managed` comment', () => {
|
||||||
// self managed
|
// self managed
|
||||||
"key": {
|
"key": {
|
||||||
"world": [5]
|
"world": [5]
|
||||||
}
|
},
|
||||||
|
// self managed
|
||||||
|
"stringKey": "--"
|
||||||
}
|
}
|
||||||
`);
|
`);
|
||||||
|
|
||||||
|
@ -186,7 +204,9 @@ it('does not modify properties with leading `// self managed` comment', () => {
|
||||||
// self managed
|
// self managed
|
||||||
"key": {
|
"key": {
|
||||||
"world": [5]
|
"world": [5]
|
||||||
}
|
},
|
||||||
|
// self managed
|
||||||
|
"stringKey": "--"
|
||||||
}
|
}
|
||||||
|
|
||||||
`);
|
`);
|
||||||
|
@ -210,7 +230,9 @@ it('does not modify child properties with leading `// self managed` comment', ()
|
||||||
"world": [5],
|
"world": [5],
|
||||||
// @managed
|
// @managed
|
||||||
"hello": true
|
"hello": true
|
||||||
}
|
},
|
||||||
|
// @managed
|
||||||
|
"stringKey": "foo"
|
||||||
}
|
}
|
||||||
|
|
||||||
`);
|
`);
|
||||||
|
@ -236,7 +258,9 @@ it('does not modify unknown child properties', () => {
|
||||||
"world": [5],
|
"world": [5],
|
||||||
// @managed
|
// @managed
|
||||||
"hello": true
|
"hello": true
|
||||||
}
|
},
|
||||||
|
// @managed
|
||||||
|
"stringKey": "foo"
|
||||||
}
|
}
|
||||||
|
|
||||||
`);
|
`);
|
||||||
|
@ -262,7 +286,9 @@ it('removes managed properties which are no longer managed', () => {
|
||||||
"world": [5],
|
"world": [5],
|
||||||
// @managed
|
// @managed
|
||||||
"hello": true
|
"hello": true
|
||||||
}
|
},
|
||||||
|
// @managed
|
||||||
|
"stringKey": "foo"
|
||||||
}
|
}
|
||||||
|
|
||||||
`);
|
`);
|
||||||
|
@ -286,7 +312,9 @@ it('wipes out child keys which conflict with newly managed child keys', () => {
|
||||||
"hello": true,
|
"hello": true,
|
||||||
// @managed
|
// @managed
|
||||||
"world": [1, 2, 3]
|
"world": [1, 2, 3]
|
||||||
}
|
},
|
||||||
|
// @managed
|
||||||
|
"stringKey": "foo"
|
||||||
}
|
}
|
||||||
|
|
||||||
`);
|
`);
|
||||||
|
@ -308,7 +336,9 @@ it('correctly formats info text when specified', () => {
|
||||||
"hello": true,
|
"hello": true,
|
||||||
// @managed
|
// @managed
|
||||||
"world": [1, 2, 3]
|
"world": [1, 2, 3]
|
||||||
}
|
},
|
||||||
|
// @managed
|
||||||
|
"stringKey": "foo"
|
||||||
}
|
}
|
||||||
|
|
||||||
`);
|
`);
|
||||||
|
@ -321,7 +351,10 @@ it('allows "// self managed" comments conflicting with "// @managed" comments to
|
||||||
// @managed
|
// @managed
|
||||||
// self managed
|
// self managed
|
||||||
"hello": ["world"]
|
"hello": ["world"]
|
||||||
}
|
},
|
||||||
|
// @managed
|
||||||
|
// self managed
|
||||||
|
"stringKey": 12345
|
||||||
}
|
}
|
||||||
`);
|
`);
|
||||||
|
|
||||||
|
@ -333,7 +366,9 @@ it('allows "// self managed" comments conflicting with "// @managed" comments to
|
||||||
"hello": ["world"],
|
"hello": ["world"],
|
||||||
// @managed
|
// @managed
|
||||||
"world": [1, 2, 3]
|
"world": [1, 2, 3]
|
||||||
}
|
},
|
||||||
|
// self managed
|
||||||
|
"stringKey": 12345
|
||||||
}
|
}
|
||||||
|
|
||||||
`);
|
`);
|
||||||
|
|
|
@ -25,11 +25,20 @@ const isManaged = (node?: t.Node) =>
|
||||||
(c) => c.type === 'CommentLine' && c.value.trim().toLocaleLowerCase() === '@managed'
|
(c) => c.type === 'CommentLine' && c.value.trim().toLocaleLowerCase() === '@managed'
|
||||||
);
|
);
|
||||||
|
|
||||||
const isSelfManaged = (node?: t.Node) =>
|
const isSelfManaged = (node?: t.Node) => {
|
||||||
!!node?.leadingComments?.some(
|
const result = !!node?.leadingComments?.some(
|
||||||
(c) => c.type === 'CommentLine' && c.value.trim().toLocaleLowerCase() === 'self managed'
|
(c) => c.type === 'CommentLine' && c.value.trim().toLocaleLowerCase() === 'self managed'
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// if we find a node which is both managed and self managed remove the managed comment
|
||||||
|
if (result && node && isManaged(node)) {
|
||||||
|
node.leadingComments =
|
||||||
|
node.leadingComments?.filter((c) => c.value.trim() !== '@managed') ?? null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
};
|
||||||
|
|
||||||
const remove = <T>(arr: T[], value: T) => {
|
const remove = <T>(arr: T[], value: T) => {
|
||||||
const index = arr.indexOf(value);
|
const index = arr.indexOf(value);
|
||||||
if (index > -1) {
|
if (index > -1) {
|
||||||
|
@ -37,16 +46,16 @@ const remove = <T>(arr: T[], value: T) => {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const createManagedChildProp = (key: string, value: any) => {
|
const createManagedProp = (key: string, value: any) => {
|
||||||
const childProp = t.objectProperty(t.stringLiteral(key), parseExpression(JSON.stringify(value)));
|
const childProp = t.objectProperty(t.stringLiteral(key), parseExpression(JSON.stringify(value)));
|
||||||
t.addComment(childProp, 'leading', ' @managed', true);
|
t.addComment(childProp, 'leading', ' @managed', true);
|
||||||
return childProp;
|
return childProp;
|
||||||
};
|
};
|
||||||
|
|
||||||
const createManagedProp = (key: string, value: Record<string, any>) => {
|
const createObjectPropOfManagedValues = (key: string, value: Record<string, any>) => {
|
||||||
return t.objectProperty(
|
return t.objectProperty(
|
||||||
t.stringLiteral(key),
|
t.stringLiteral(key),
|
||||||
t.objectExpression(Object.entries(value).map(([k, v]) => createManagedChildProp(k, v)))
|
t.objectExpression(Object.entries(value).map(([k, v]) => createManagedProp(k, v)))
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -57,8 +66,16 @@ const createManagedProp = (key: string, value: Record<string, any>) => {
|
||||||
* @param key the key name to add
|
* @param key the key name to add
|
||||||
* @param value managed value which should be set at `key`
|
* @param value managed value which should be set at `key`
|
||||||
*/
|
*/
|
||||||
const addManagedProp = (ast: t.ObjectExpression, key: string, value: Record<string, any>) => {
|
const addManagedProp = (
|
||||||
ast.properties.push(createManagedProp(key, value));
|
ast: t.ObjectExpression,
|
||||||
|
key: string,
|
||||||
|
value: string | Record<string, any>
|
||||||
|
) => {
|
||||||
|
ast.properties.push(
|
||||||
|
typeof value === 'string'
|
||||||
|
? createManagedProp(key, value)
|
||||||
|
: createObjectPropOfManagedValues(key, value)
|
||||||
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -72,7 +89,7 @@ const addManagedProp = (ast: t.ObjectExpression, key: string, value: Record<stri
|
||||||
const replaceManagedProp = (
|
const replaceManagedProp = (
|
||||||
ast: t.ObjectExpression,
|
ast: t.ObjectExpression,
|
||||||
existing: BasicObjectProp,
|
existing: BasicObjectProp,
|
||||||
value: Record<string, any>
|
value: string | Record<string, any>
|
||||||
) => {
|
) => {
|
||||||
remove(ast.properties, existing);
|
remove(ast.properties, existing);
|
||||||
addManagedProp(ast, existing.key.value, value);
|
addManagedProp(ast, existing.key.value, value);
|
||||||
|
@ -98,15 +115,11 @@ const mergeManagedProperties = (
|
||||||
|
|
||||||
if (!existing) {
|
if (!existing) {
|
||||||
// add the new managed prop
|
// add the new managed prop
|
||||||
properties.push(createManagedChildProp(key, value));
|
properties.push(createManagedProp(key, value));
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isSelfManaged(existing)) {
|
if (isSelfManaged(existing)) {
|
||||||
// strip "// @managed" comment if conflicting with "// self managed"
|
|
||||||
existing.leadingComments = (existing.leadingComments ?? []).filter(
|
|
||||||
(c) => c.value.trim() !== '@managed'
|
|
||||||
);
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -119,7 +132,7 @@ const mergeManagedProperties = (
|
||||||
// take over the unmanaged child prop by deleting the previous prop and replacing it
|
// take over the unmanaged child prop by deleting the previous prop and replacing it
|
||||||
// with a brand new one
|
// with a brand new one
|
||||||
remove(properties, existing);
|
remove(properties, existing);
|
||||||
properties.push(createManagedChildProp(key, value));
|
properties.push(createManagedProp(key, value));
|
||||||
}
|
}
|
||||||
|
|
||||||
// iterate through the props to find "// @managed" props which are no longer in
|
// iterate through the props to find "// @managed" props which are no longer in
|
||||||
|
@ -170,20 +183,29 @@ export function updateVscodeConfig(keys: ManagedConfigKey[], infoText: string, j
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (existingProp && existingProp.value.type === 'ObjectExpression') {
|
if (typeof value === 'object') {
|
||||||
// setting exists and is an object so merge properties of `value` with it
|
if (existingProp && existingProp.value.type === 'ObjectExpression') {
|
||||||
mergeManagedProperties(existingProp.value.properties, value);
|
// setting exists and is an object so merge properties of `value` with it
|
||||||
|
mergeManagedProperties(existingProp.value.properties, value);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (existingProp) {
|
||||||
|
// setting exists but its value is not an object expression so replace it
|
||||||
|
replaceManagedProp(ast, existingProp, value);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// setting isn't in config file so create it
|
||||||
|
addManagedProp(ast, key, value);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (existingProp) {
|
if (existingProp) {
|
||||||
// setting exists but its value is not an object expression so replace it
|
|
||||||
replaceManagedProp(ast, existingProp, value);
|
replaceManagedProp(ast, existingProp, value);
|
||||||
continue;
|
} else {
|
||||||
|
addManagedProp(ast, key, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
// setting isn't in config file so create it
|
|
||||||
addManagedProp(ast, key, value);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ast.leadingComments = [
|
ast.leadingComments = [
|
||||||
|
|
Loading…
Reference in a new issue