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();
}
}