Press n or j to go to the next uncovered block, b, p or k for the previous block.
| 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 | 6x 6x 6x 6x 6x 6x 6x 6x 6x 6x 3x 1x 2x 2x 1x 4x 6x 6x 5x 5x 5x 5x 3x 2x 1x 1x 2x 2x 4x 4x | import * as vscode from 'vscode';
import { SettingsFileStore, WorkspaceReference } from '@src/services/core';
import { UserUri } from '@src/providers/user-uri';
import { WorkspaceIdentity, workspaceIdentity } from '@src/utilities/vscode/workspace';
import { ShaclProfileSettingsService } from './shacl-profile-settings-service';
import { getAllReferencedShapeUris } from './shacl-validation-configuration';
/**
* Keeps the cross-workspace reference registry of user shape files up to date.
*
* `mentor.shacl.validation` profiles carry no workspace identity, so a user shape
* referenced only by *another* workspace's workspace-scoped profile is invisible
* to that other workspace's orphan detection and could be deleted by accident.
* This service records, in the synced `mentor.files` entry, the workspaces whose
* workspace-scoped profiles reference each file, keyed by a stable, rename-proof
* workspace id, so the shape is protected everywhere (see
* {@link ShapeGraphService.getUnreferencedUserShapeFiles}).
*
* User-scope profiles are global and already visible everywhere, so they are not
* recorded here — only the current workspace's workspace-scoped references are.
*/
export class ShapeReferenceRegistryService implements vscode.Disposable {
private readonly _disposables: vscode.Disposable[] = [];
constructor(
private readonly _fileStore: SettingsFileStore,
private readonly _profileSettings: ShaclProfileSettingsService,
private readonly _workspace: WorkspaceIdentity = workspaceIdentity
) {
// A profile save writes mentor.shacl.validation, so this keeps the current
// workspace's contribution to the registry accurate as profiles change.
this._disposables.push(vscode.workspace.onDidChangeConfiguration(e => {
if (e.affectsConfiguration('mentor.shacl.validation')) {
void this.reconcile();
}
}));
}
dispose(): void {
for (const disposable of this._disposables) {
disposable.dispose();
}
}
/**
* Reconciles this workspace's entry into (or out of) the `references` of every
* user shape file, based on which files its workspace-scoped profiles currently
* reference. Other workspaces' entries are left untouched. The stable workspace
* id is generated (and persisted) only when this workspace actually references
* a user shape, so workspaces that use none never get an id written. A no-op
* when there is nothing to record and no id exists yet.
*/
async reconcile(): Promise<void> {
const referenced = new Set(getAllReferencedShapeUris(this._profileSettings.getSettings('workspace')));
const keys = this._fileStore.keys();
const referencesAny = keys.some(key => referenced.has(UserUri.forPath(key)));
let id = this._workspace.getId();
if (!id) {
// No id yet: only worth generating one if this workspace references a
// shape. If it references none, there is nothing to add or remove.
if (!referencesAny) {
return;
}
id = await this._workspace.ensureId();
if (!id) {
return;
}
}
const name = this._workspace.getName() ?? id;
const updates: Record<string, WorkspaceReference[]> = {};
for (const key of keys) {
const isReferenced = referenced.has(UserUri.forPath(key));
const current = this._fileStore.getReferences(key);
const index = current.findIndex(ref => ref.id === id);
if (isReferenced) {
if (index === -1) {
updates[key] = [...current, { id, name }].sort((a, b) => a.id.localeCompare(b.id));
} else Eif (current[index].name !== name) {
// Keep the id stable, refresh the display name (e.g. after a rename).
updates[key] = current.map(ref => ref.id === id ? { id, name } : ref);
}
} else if (index !== -1) {
updates[key] = current.filter(ref => ref.id !== id);
}
}
Eif (Object.keys(updates).length > 0) {
await this._fileStore.setReferences(updates);
}
}
}
|