diff --git a/CHANGELOG.md b/CHANGELOG.md index 01958c2c45409..f7a0c9b128d23 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,8 @@ Breaking Changes: - [json] replaced `@theia/json` Theia extension with `vscode.json-language-features` VS Code extension [#7972](https://github.com/eclipse-theia/theia/pull/7972) - You can register JSON validations at application startup by implementing `JsonSchemaContribution` Theia contribution point. - Alternatively you can provide JSON validations using VS Code [contributes.jsonValidation](https://code.visualstudio.com/api/references/contribution-points#contributes.jsonValidation) contribution point. +- [user-storage] settings URI must be an absolute to satisfy expectations of `vscode.json-language-features` [#7972](https://github.com/eclipse-theia/theia/pull/7972) + - If you imlpement a custom user storage make sure to check old relaitve locations, otherwise it can cause user data loss. ## v1.3.0 diff --git a/packages/keymaps/src/browser/keymaps-service.ts b/packages/keymaps/src/browser/keymaps-service.ts index 05e79690912e6..9661add59ce96 100644 --- a/packages/keymaps/src/browser/keymaps-service.ts +++ b/packages/keymaps/src/browser/keymaps-service.ts @@ -46,7 +46,7 @@ export class KeymapsService { */ @postConstruct() protected async init(): Promise { - this.resource = await this.resourceProvider(new URI().withScheme(UserStorageUri.SCHEME).withPath('keymaps.json')); + this.resource = await this.resourceProvider(new URI().withScheme(UserStorageUri.SCHEME).withPath('/keymaps.json')); this.reconcile(); if (this.resource.onDidChangeContents) { this.resource.onDidChangeContents(() => this.reconcile()); diff --git a/packages/preferences/src/browser/user-configs-preference-provider.ts b/packages/preferences/src/browser/user-configs-preference-provider.ts index de7998de62f17..af5c3922be658 100644 --- a/packages/preferences/src/browser/user-configs-preference-provider.ts +++ b/packages/preferences/src/browser/user-configs-preference-provider.ts @@ -52,7 +52,7 @@ export class UserConfigsPreferenceProvider extends PreferenceProvider { protected createProviders(): void { for (const configName of [...this.configurations.getSectionNames(), this.configurations.getConfigName()]) { - const sectionUri = USER_PREFERENCE_FOLDER.withPath(configName + '.json'); + const sectionUri = USER_PREFERENCE_FOLDER.withPath('/' + configName + '.json'); const sectionKey = sectionUri.toString(); if (!this.providers.has(sectionKey)) { const provider = this.createProvider(sectionUri, configName); diff --git a/packages/preferences/src/browser/user-preference-provider.ts b/packages/preferences/src/browser/user-preference-provider.ts index 4e12f864e5c29..5acc9cb760cd6 100644 --- a/packages/preferences/src/browser/user-preference-provider.ts +++ b/packages/preferences/src/browser/user-preference-provider.ts @@ -20,7 +20,7 @@ import { UserStorageUri } from '@theia/userstorage/lib/browser'; import { PreferenceScope } from '@theia/core/lib/browser'; import { SectionPreferenceProvider } from './section-preference-provider'; -export const USER_PREFERENCE_URI = new URI().withScheme(UserStorageUri.SCHEME).withPath('settings.json'); +export const USER_PREFERENCE_URI = new URI().withScheme(UserStorageUri.SCHEME).withPath('/settings.json'); export const UserPreferenceProviderFactory = Symbol('UserPreferenceProviderFactory'); export interface UserPreferenceProviderFactory { diff --git a/packages/userstorage/src/browser/user-storage-resource.ts b/packages/userstorage/src/browser/user-storage-resource.ts index eaee791c2d7e1..b1d88cc543b5b 100644 --- a/packages/userstorage/src/browser/user-storage-resource.ts +++ b/packages/userstorage/src/browser/user-storage-resource.ts @@ -65,7 +65,7 @@ export class UserStorageResolver implements ResourceResolver { ) { } resolve(uri: URI): MaybePromise { - if (uri.scheme !== UserStorageUri.SCHEME) { + if (uri.scheme !== UserStorageUri.SCHEME || !uri.path.isAbsolute) { throw new Error('The given uri is not a user storage uri: ' + uri); } return new UserStorageResource(uri, this.service); diff --git a/packages/userstorage/src/browser/user-storage-service-filesystem.spec.ts b/packages/userstorage/src/browser/user-storage-service-filesystem.spec.ts index 9b9605a5bcd9c..c49ef86e74254 100644 --- a/packages/userstorage/src/browser/user-storage-service-filesystem.spec.ts +++ b/packages/userstorage/src/browser/user-storage-service-filesystem.spec.ts @@ -128,20 +128,20 @@ describe('User Storage Service (Filesystem implementation)', () => { it('Should return a user storage uri from a filesystem uri', () => { - const test = UserStorageServiceFilesystemImpl.toUserStorageUri(userStorageFolder, userStorageFolder.resolve(testFile)); + const test = UserStorageServiceFilesystemImpl.toUserStorageUri(userStorageFolder, userStorageFolder.resolve(testFile))!; expect(test.scheme).eq(UserStorageUri.SCHEME); - expect(test.toString()).eq(UserStorageUri.SCHEME + ':' + testFile); + expect(test.toString()).eq(UserStorageUri.SCHEME + ':/' + testFile); const testFragment = UserStorageServiceFilesystemImpl. - toUserStorageUri(userStorageFolder, userStorageFolder.resolve(testFile).withFragment('test')); + toUserStorageUri(userStorageFolder, userStorageFolder.resolve(testFile).withFragment('test'))!; expect(testFragment.fragment).eq('test'); const testQuery = UserStorageServiceFilesystemImpl. - toUserStorageUri(userStorageFolder, userStorageFolder.resolve(testFile).withQuery('test=1')); + toUserStorageUri(userStorageFolder, userStorageFolder.resolve(testFile).withQuery('test=1'))!; expect(testQuery.query).eq('test=1'); const testQueryAndFragment = UserStorageServiceFilesystemImpl. - toUserStorageUri(userStorageFolder, userStorageFolder.resolve(testFile).withQuery('test=1').withFragment('test')); + toUserStorageUri(userStorageFolder, userStorageFolder.resolve(testFile).withQuery('test=1').withFragment('test'))!; expect(testQueryAndFragment.fragment).eq('test'); expect(testQueryAndFragment.query).eq('test=1'); }); @@ -157,7 +157,7 @@ describe('User Storage Service (Filesystem implementation)', () => { userStorageService.onUserStorageChanged(event => { const userStorageUri = event.uris[0]; expect(userStorageUri.scheme).eq(UserStorageUri.SCHEME); - expect(userStorageUri.path.toString()).eq(testFile); + expect(userStorageUri.path.toString()).eq('/' + testFile); done(); }); @@ -173,7 +173,7 @@ describe('User Storage Service (Filesystem implementation)', () => { it('Should save the contents correctly using a user storage uri to a filesystem uri', async () => { const userStorageUri = UserStorageServiceFilesystemImpl. - toUserStorageUri(userStorageFolder, userStorageFolder.resolve(testFile)); + toUserStorageUri(userStorageFolder, userStorageFolder.resolve(testFile))!; await userStorageService.saveContents(userStorageUri, 'test content'); @@ -196,7 +196,7 @@ describe('User Storage Resource (Filesystem implementation)', () => { testFile = 'test.json'; userStorageService = testContainer.get(UserStorageService); const userStorageUriTest = UserStorageServiceFilesystemImpl. - toUserStorageUri(userStorageFolder, userStorageFolder.resolve(testFile)); + toUserStorageUri(userStorageFolder, userStorageFolder.resolve(testFile))!; userStorageResource = new UserStorageResource(userStorageUriTest, userStorageService); }); diff --git a/packages/userstorage/src/browser/user-storage-service-filesystem.ts b/packages/userstorage/src/browser/user-storage-service-filesystem.ts index ec0917e9370a7..2137cff52b1e4 100644 --- a/packages/userstorage/src/browser/user-storage-service-filesystem.ts +++ b/packages/userstorage/src/browser/user-storage-service-filesystem.ts @@ -59,8 +59,8 @@ export class UserStorageServiceFilesystemImpl implements UserStorageService { this.userStorageFolder.then(folder => { if (folder) { for (const change of event) { - if (folder.isEqualOrParent(change.uri)) { - const userStorageUri = UserStorageServiceFilesystemImpl.toUserStorageUri(folder, change.uri); + const userStorageUri = UserStorageServiceFilesystemImpl.toUserStorageUri(folder, change.uri); + if (userStorageUri) { uris.push(userStorageUri); } } @@ -108,20 +108,12 @@ export class UserStorageServiceFilesystemImpl implements UserStorageService { * @param userStorageFolderUri User storage folder URI * @param fsPath The filesystem URI */ - public static toUserStorageUri(userStorageFolderUri: URI, rawUri: URI): URI { - const userStorageRelativePath = this.getRelativeUserStoragePath(userStorageFolderUri, rawUri); - return new URI('').withScheme(UserStorageUri.SCHEME).withPath(userStorageRelativePath).withFragment(rawUri.fragment).withQuery(rawUri.query); - } - - /** - * Returns the path relative to the user storage filesystem uri i.e if the user storage root is - * 'file://home/user/.theia' and the fileUri is 'file://home/user.theia/keymaps.json' it will return 'keymaps.json' - * @param userStorageFolderUri User storage folder URI - * @param fileUri User storage - */ - private static getRelativeUserStoragePath(userStorageFolderUri: URI, fileUri: URI): string { - /* + 1 so that it removes the beginning slash i.e return keymaps.json and not /keymaps.json */ - return fileUri.toString().slice(userStorageFolderUri.toString().length + 1); + public static toUserStorageUri(userStorageFolderUri: URI, rawUri: URI): URI | undefined { + const relativePath = userStorageFolderUri.relative(rawUri); + if (relativePath) { + return rawUri.withScheme(UserStorageUri.SCHEME).withPath('/' + relativePath); + } + return undefined; } /** @@ -130,6 +122,6 @@ export class UserStorageServiceFilesystemImpl implements UserStorageService { * @param userStorageUri User storage URI to be converted in filesystem URI */ public static toFilesystemURI(userStorageFolderUri: URI, userStorageUri: URI): URI { - return userStorageFolderUri.withPath(userStorageFolderUri.path.join(userStorageUri.path.toString())); + return userStorageFolderUri.resolve(userStorageUri.path).normalizePath(); } }