settingsMerge.ts ×19

Frontier kind: Code frontier

unlabeled · c_a6bd5527a091

419 tests · 10745 LOC · 47 files · introduces 0 tests · 77 LOC · 2 files

Introduces — evidence that enters the hierarchy at this concept

Code
22 ranges77 lines · 2 files
Tests
0 tests

Contains — complete concept membership

All code (extent)
1124 ranges10745 lines · 47 files · Browse complete extent
All tests (intent)
419 testsBrowse complete intent

Neighbourhood graph

The orange circle is the focus. Violet and green circles are every ancestor and descendant, broader and narrower, at any distance; blue squares and pink diamonds are the introduced files and exact introduced tests of every visible concept, not only the focus's. Arrows point from broader to narrower concepts and bridge only concepts omitted from this view. Undirected links show source or test introduction. Concept and file size follows LOC; exact test nodes use test-count units.

Introduced files, introduced tests, and structurally relevant concept specialization

In the embedded map, ordinary wheel input scrolls the page; use the visible controls to zoom and drag to pan. Open the full-screen map for canvas navigation: wheel pans, Ctrl/Command plus wheel zooms, and arrow keys pan when this region is focused. On touch screens, open the full-screen map to pan or pinch. If JavaScript or WebGL is unavailable, use the native relationship evidence on this page.

Graph controls are ready.

Interactive rendering requires JavaScript and WebGL. Use the native relationship evidence on this page while the interactive map is unavailable.

Native relationship evidence

Every exact file and test below is linked only from the concept that introduces it.

Introduced tests

Every collected test enters the hierarchy at exactly one concept.

No tests are introduced at this concept. Its intent tests are introduced by other concepts.

Introduced code

Every collected source range enters the hierarchy at exactly one concept.

2 files ranked by introduced lines: 77 introduced LOC across 22 ranges. Expand a file to inspect source; the > gutter marks introduced lines.

src/vs/platform/userDataSync/common/settingsMerge.ts 62 introduced LOC · 19 ranges

Open complete file

1 > /*--------------------------------------------------------------------------------------------- settingsMerge.ts
2 > * Copyright (c) Microsoft Corporation. All rights reserved.
3 > * Licensed under the MIT License. See License.txt in the project root for license information.
4 > *--------------------------------------------------------------------------------------------*/
5 >
6 > import { distinct } from '../../../base/common/arrays.js';
7 > import { IStringDictionary } from '../../../base/common/collections.js';
8 > import { JSONVisitor, parse, visit } from '../../../base/common/json.js';
9 > import { applyEdits, setProperty, withFormatting } from '../../../base/common/jsonEdit.js';
10 > import { Edit, FormattingOptions, getEOL } from '../../../base/common/jsonFormatter.js';
11 > import * as objects from '../../../base/common/objects.js';
12 > import { IConfigurationService } from '../../configuration/common/configuration.js';
13 > import * as contentUtil from './content.js';
14 > import { getDisallowedIgnoredSettings, IConflictSetting } from './userDataSync.js';
15 >
16 > export interface IMergeResult {
17 > localContent: string | null;
18 > remoteContent: string | null;
19 > hasConflicts: boolean;
20 > conflictsSettings: IConflictSetting[];
21 > }
22 >
23 > export function getIgnoredSettings(defaultIgnoredSettings: string[], configurationService: IConfigurationService, settingsContent?: string): string[] {
24 let value: ReadonlyArray<string> = [];
25 if (settingsContent) {
40 return distinct([...defaultIgnoredSettings, ...added,].filter(setting => !removed.includes(setting)));
41 }
43 function getIgnoredSettingsFromConfig(configurationService: IConfigurationService): ReadonlyArray<string> {
44 let userValue = configurationService.inspect<string[]>('settingsSync.ignoredSettings').userValue;
52 return configurationService.getValue<string[]>('settingsSync.ignoredSettings') || [];
53 }
55 function getIgnoredSettingsFromContent(settingsContent: string): string[] {
56 const parsed = parse(settingsContent);
57 return parsed ? parsed['settingsSync.ignoredSettings'] || parsed['sync.ignoredSettings'] || [] : [];
58 }
60 > export function removeComments(content: string, formattingOptions: FormattingOptions): string {
61 const source = parse(content) || {};
62 let result = '{}';
67 return result;
68 }
70 > export function updateIgnoredSettings(targetContent: string, sourceContent: string, ignoredSettings: string[], formattingOptions: FormattingOptions): string {
71 if (ignoredSettings.length) {
72 const sourceTree = parseSettings(sourceContent);
101 return targetContent;
102 }
104 > export function merge(originalLocalContent: string, originalRemoteContent: string, baseContent: string | null, ignoredSettings: string[], resolvedConflicts: { key: string; value: any | undefined }[], formattingOptions: FormattingOptions): IMergeResult {
105
106 const localContentWithoutIgnoredSettings = updateIgnoredSettings(originalLocalContent, originalRemoteContent, ignoredSettings, formattingOptions);
250 return { localContent: hasLocalChanged ? localContent : null, remoteContent: hasRemoteChanged ? remoteContent : null, conflictsSettings: [...conflicts.values()], hasConflicts };
251 }
253 function areSame(localContent: string, remoteContent: string, ignoredSettings: string[]): boolean {
254 if (localContent === remoteContent) {
287 return true;
288 }
290 > export function isEmpty(content: string): boolean {
291 if (content) {
292 const nodes = parseSettings(content);
295 return true;
296 }
298 function compare(from: IStringDictionary<any> | null, to: IStringDictionary<any>, ignored: Set<string>): { added: Set<string>; removed: Set<string>; updated: Set<string> } {
299 const fromKeys = from ? Object.keys(from).filter(key => !ignored.has(key)) : [];
318 return { added, removed, updated };
319 }
321 > export function addSetting(key: string, sourceContent: string, targetContent: string, formattingOptions: FormattingOptions): string {
322 const source = parse(sourceContent);
323 const sourceTree = parseSettings(sourceContent);
326 return insertAtLocation(targetContent, key, source[key], insertLocation, targetTree, formattingOptions);
327 }
329 > interface InsertLocation {
330 > index: number;
331 > insertAfter: boolean;
332 > }
333 >
334 function getInsertLocation(key: string, sourceTree: INode[], targetTree: INode[]): InsertLocation {
335
438 return { index: targetTree.length - 1, insertAfter: true };
439 }
441 function insertAtLocation(content: string, key: string, value: any, location: InsertLocation, tree: INode[], formattingOptions: FormattingOptions): string {
442 let edits: Edit[];
449 return applyEdits(content, edits);
450 }
452 function getEditToInsertAtLocation(content: string, key: string, value: any, location: InsertLocation, tree: INode[], formattingOptions: FormattingOptions): Edit[] {
453 const newProperty = `${JSON.stringify(key)}: ${JSON.stringify(value)}`;
504
505 }
507 function findSettingNode(key: string, tree: INode[]): INode | undefined {
508 return tree.filter(node => node.setting?.key === key)[0];
509 }
511 function findPreviousSettingNode(index: number, tree: INode[]): INode | undefined {
512 for (let i = index - 1; i >= 0; i--) {
517 return undefined;
518 }
520 function findNextSettingNode(index: number, tree: INode[]): INode | undefined {
521 for (let i = index + 1; i < tree.length; i++) {
526 return undefined;
527 }
529 function findNodesBetween(nodes: INode[], from: INode, till: INode): INode[] {
530 const fromIndex = nodes.indexOf(from);
532 return nodes.filter((node, index) => fromIndex < index && index < tillIndex);
533 }
535 function findLastMatchingTargetCommentNode(sourceComments: INode[], targetComments: INode[]): INode | undefined {
536 if (sourceComments.length && targetComments.length) {
545 return undefined;
546 }
548 > interface INode {
549 > readonly startOffset: number;
550 > readonly endOffset: number;
551 > readonly value: string;
552 > readonly setting?: {
553 > readonly key: string;
554 > readonly commaOffset: number | undefined;
555 > };
556 > readonly comment?: string;
557 > }
558 >
559 function parseSettings(content: string): INode[] {
560 const nodes: INode[] = [];
src/vs/platform/userDataSync/common/content.ts 15 introduced LOC · 3 ranges

Open complete file

1 > /*--------------------------------------------------------------------------------------------- content.ts
2 > * Copyright (c) Microsoft Corporation. All rights reserved.
3 > * Licensed under the MIT License. See License.txt in the project root for license information.
4 > *--------------------------------------------------------------------------------------------*/
5 >
6 > import { JSONPath } from '../../../base/common/json.js';
7 > import { setProperty } from '../../../base/common/jsonEdit.js';
8 > import { FormattingOptions } from '../../../base/common/jsonFormatter.js';
9 >
10 >
11 > export function edit(content: string, originalPath: JSONPath, value: unknown, formattingOptions: FormattingOptions): string {
12 const edit = setProperty(content, originalPath, value, formattingOptions)[0];
13 if (edit) {
16 return content;
17 }
18 > content.ts
19 > export function getLineStartOffset(content: string, eol: string, atOffset: number): number {
20 let lineStartingOffset = atOffset;
21 while (lineStartingOffset >= 0) {
34 return 0;
35 }
36 > content.ts
37 > export function getLineEndOffset(content: string, eol: string, atOffset: number): number {
38 let lineEndOffset = atOffset;
39 while (lineEndOffset >= 0) {