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 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 | 121x 121x 121x 34x 34x 136x 34x 27x 27x 7x 7x 14x 11x 9x 7x 59x 5x 18x 1x 4x 4x 2x 2x 1x 1x 11x 3x 8x 19x 5x 5x 5x 5x 5x 5x 3x 3x 3x 5x 5x 7x 7x 2x 5x 5x | import * as vscode from 'vscode';
import { getConfig } from '@src/utilities/vscode/config';
import { ConfigurationScope } from '@src/utilities/config-scope';
import { PRESET_STORES } from './default-stores';
import { SparqlConnection } from './sparql-connection';
import { TripleStoreConfig, SparqlQueryKind, TRIPLE_STORE_QUERY_KIND_PROPERTY } from './triple-store-config';
import { ITripleStoreConfigService } from './triple-store-config-service.interface';
/**
* Service responsible for store-type configuration: reading store configs from settings,
* resolving a config by id, answering capability questions (inference support,
* workspace identity), and resolving effective query templates.
*/
export class TripleStoreConfigService implements ITripleStoreConfigService {
/**
* VS Code settings key under which user-defined store configs are persisted.
*/
private readonly _storesConfigKey = 'sparql.stores';
/**
* The id of the internal, code-only in-memory workspace store.
*/
private readonly _workspaceStoreType = 'workspace';
/**
* The store type assumed for connections that do not specify one.
*/
readonly defaultStoreType = 'sparql';
/**
* Returns the available store configs: the built-in read-only presets followed by the
* user- and workspace-defined stores. Because `sparql.stores` is an array, VS Code does
* not merge it across scopes — the highest scope replaces the others — which would hide
* user-scope store types whenever a workspace value exists. We therefore union the user
* and workspace arrays (workspace overriding user by `id`) so every defined store type is
* selectable. Settings entries whose id collides with a preset are ignored: presets
* cannot be shadowed, and stale copies from the former first-run seeding stay hidden.
*
* Settings-defined stores are tagged with the transient `configScope` field so consumers
* (e.g. the connection editor) can enforce scope compatibility; presets stay untagged,
* meaning they are usable from any scope.
* @returns An array of store configs in display order (presets first).
*/
getStoreConfigs(): TripleStoreConfig[] {
const config = getConfig();
const inspected = config.inspect<TripleStoreConfig[]>(this._storesConfigKey);
const presetIds = new Set(PRESET_STORES.map(s => s.id));
// Fall back to the merged effective value when inspect is unavailable. The
// per-entry scope is unknowable here, so the entries stay untagged.
if (!inspected) {
const stores = config.get<TripleStoreConfig[]>(this._storesConfigKey) ?? [];
return [...PRESET_STORES, ...stores.filter(s => !presetIds.has(s.id))];
} else {
const merged = new Map<string, TripleStoreConfig>();
for (const [value, configScope] of [
[inspected.globalValue, ConfigurationScope.User],
[inspected.workspaceValue, ConfigurationScope.Workspace],
] as const) {
for (const store of value ?? []) {
if (!presetIds.has(store.id)) {
merged.set(store.id, { ...store, configScope });
}
}
}
return [...PRESET_STORES, ...merged.values()];
}
}
/**
* Resolves a store config by its id (store type).
* @param storeType The store-type id. Defaults to the generic SPARQL endpoint when `undefined`.
* @returns The matching store config, or `undefined` if no config has that id.
*/
getStoreConfig(storeType: string | undefined): TripleStoreConfig | undefined {
return this.getStoreConfigs().find(s => s.id === (storeType ?? this.defaultStoreType));
}
/**
* Returns where a store type is defined: a built-in preset, the user
* settings, the workspace settings, or nowhere (`undefined`). A store id
* defined in both settings scopes reports `workspace`, matching the
* resolution precedence of `getStoreConfigs`.
* @param storeType The store-type id to look up.
*/
getStoreConfigScope(storeType: string | undefined): 'preset' | 'user' | 'workspace' | undefined {
const id = storeType ?? this.defaultStoreType;
if (PRESET_STORES.some(s => s.id === id)) {
return 'preset';
}
const inspected = getConfig().inspect<TripleStoreConfig[]>(this._storesConfigKey);
if (inspected?.workspaceValue?.some(s => s.id === id)) {
return 'workspace';
}
if (inspected?.globalValue?.some(s => s.id === id)) {
return 'user';
}
return undefined;
}
/**
* Checks if the given connection supports inference toggling.
* The workspace connection always supports inference. For all other connections, support
* is determined by the store config's `inference.supported` flag.
* @param connection The SPARQL connection to check.
* @returns `true` if the connection supports inference, `false` otherwise.
*/
supportsInference(connection: SparqlConnection): boolean {
if (this.isWorkspaceConnectionId(connection.id) || connection.storeType === this._workspaceStoreType) {
return true;
} else {
return this.getStoreConfig(connection.storeType)?.inference?.supported ?? false;
}
}
/**
* Returns whether the connection targets the internal in-memory workspace store.
* @param connection The SPARQL connection to test.
* @returns `true` if the connection is the workspace store.
*/
isWorkspaceConnectionId(connectionId: string): boolean {
return connectionId === this._workspaceStoreType;
}
/**
* Cached `kind → mentor config key` map, built from package.json on first use.
*/
private _storeQueryConfigKeys: Map<string, string> | undefined;
/**
* Maps each {@link SparqlQueryKind} to the `mentor.*` config key (without the `mentor.` prefix) of
* the setting it overrides, by scanning the extension's package.json for properties carrying the
* {@link TRIPLE_STORE_QUERY_KIND_PROPERTY} marker. Result is cached for the session.
*/
private _getStoreQueryConfigKeys(): Map<string, string> {
Iif (this._storeQueryConfigKeys) {
return this._storeQueryConfigKeys;
} else {
const packageJSON = vscode.extensions.getExtension('faubulous.mentor')?.packageJSON;
const configuration = packageJSON?.contributes?.configuration?.[0];
const properties = (configuration?.properties ?? {}) as Record<string, Record<string, unknown>>;
const map = new Map<string, string>();
for (const [fullKey, prop] of Object.entries(properties)) {
const kind = prop[TRIPLE_STORE_QUERY_KIND_PROPERTY];
Eif (typeof kind === 'string') {
map.set(kind, fullKey.replace(/^mentor\./, ''));
}
}
this._storeQueryConfigKeys = map;
return map;
}
}
/**
* Resolves the effective SPARQL query template of the given kind for a connection.
* Resolution order: the store config's own query → global `mentor.sparql.*` fallback.
* @param connection The SPARQL connection.
* @param kind The kind of query template to resolve.
* @returns The resolved template, or `undefined` if none is configured at any level.
*/
getQueryTemplate(connection: SparqlConnection, kind: SparqlQueryKind): string | undefined {
const override = this.getStoreConfig(connection.storeType)?.queries?.[kind];
if (override) {
return override;
}
// The global fallback key is discovered from the setting marked with this kind in package.json,
// so package.json stays the single source of truth for which queries are store-overridable.
const key = this._getStoreQueryConfigKeys().get(kind);
return key ? getConfig().get<string>(key) : undefined;
}
}
|