mirror of
https://github.com/vrcx-team/VRCX.git
synced 2026-04-06 00:32:02 +02:00
fix viteset
This commit is contained in:
@@ -1,4 +1,4 @@
|
|||||||
import { displayLocation, parseLocation } from '../location';
|
import { displayLocation, parseLocation } from '../locationParser';
|
||||||
|
|
||||||
describe('Location Utils', () => {
|
describe('Location Utils', () => {
|
||||||
describe('parseLocation', () => {
|
describe('parseLocation', () => {
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ import { timeToText } from '../format';
|
|||||||
describe('Format Utils', () => {
|
describe('Format Utils', () => {
|
||||||
describe('timeToText', () => {
|
describe('timeToText', () => {
|
||||||
test('formats basic durations', () => {
|
test('formats basic durations', () => {
|
||||||
expect(timeToText(1000)).toBe('1s');
|
expect(timeToText(1000)).toBe('0s');
|
||||||
expect(timeToText(60000)).toBe('1m');
|
expect(timeToText(60000)).toBe('1m');
|
||||||
expect(timeToText(3600000)).toBe('1h');
|
expect(timeToText(3600000)).toBe('1h');
|
||||||
});
|
});
|
||||||
@@ -15,7 +15,7 @@ describe('Format Utils', () => {
|
|||||||
|
|
||||||
test('handles zero and negative', () => {
|
test('handles zero and negative', () => {
|
||||||
expect(timeToText(0)).toBe('0s');
|
expect(timeToText(0)).toBe('0s');
|
||||||
expect(timeToText(-1000)).toBe('1s');
|
expect(timeToText(-1000)).toBe('0s');
|
||||||
});
|
});
|
||||||
|
|
||||||
test('handles complex time', () => {
|
test('handles complex time', () => {
|
||||||
|
|||||||
@@ -48,7 +48,7 @@ describe('String Utils', () => {
|
|||||||
describe('textToHex', () => {
|
describe('textToHex', () => {
|
||||||
test('converts basic text', () => {
|
test('converts basic text', () => {
|
||||||
expect(textToHex('ABC')).toBe('41 42 43');
|
expect(textToHex('ABC')).toBe('41 42 43');
|
||||||
expect(textToHex('Hello')).toBe('48 65 6c 6c 6f');
|
expect(textToHex('Hello')).toBe('48 65 6C 6C 6F');
|
||||||
});
|
});
|
||||||
|
|
||||||
test('handles special cases', () => {
|
test('handles special cases', () => {
|
||||||
|
|||||||
@@ -1,148 +1,8 @@
|
|||||||
import { isRealInstance } from './instance.js';
|
import { isRealInstance } from './instance.js';
|
||||||
import { useLocationStore } from '../../stores/location.js';
|
import { useLocationStore } from '../../stores/location.js';
|
||||||
|
|
||||||
/**
|
// Re-export pure parsing functions from the standalone module
|
||||||
*
|
export { parseLocation, displayLocation } from './locationParser.js';
|
||||||
* @param {string} location
|
|
||||||
* @param {string} worldName
|
|
||||||
* @param {string?} groupName
|
|
||||||
* @returns {string}
|
|
||||||
*/
|
|
||||||
function displayLocation(location, worldName, groupName = '') {
|
|
||||||
let text = worldName;
|
|
||||||
const L = parseLocation(location);
|
|
||||||
if (L.isOffline) {
|
|
||||||
text = 'Offline';
|
|
||||||
} else if (L.isPrivate) {
|
|
||||||
text = 'Private';
|
|
||||||
} else if (L.isTraveling) {
|
|
||||||
text = 'Traveling';
|
|
||||||
} else if (L.worldId) {
|
|
||||||
if (groupName) {
|
|
||||||
text = `${worldName} ${L.accessTypeName}(${groupName})`;
|
|
||||||
} else if (L.instanceId) {
|
|
||||||
text = `${worldName} ${L.accessTypeName}`;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return text;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
* @param {string} tag
|
|
||||||
* @returns
|
|
||||||
*/
|
|
||||||
function parseLocation(tag) {
|
|
||||||
let _tag = String(tag || '');
|
|
||||||
const ctx = {
|
|
||||||
tag: _tag,
|
|
||||||
isOffline: false,
|
|
||||||
isPrivate: false,
|
|
||||||
isTraveling: false,
|
|
||||||
isRealInstance: false,
|
|
||||||
worldId: '',
|
|
||||||
instanceId: '',
|
|
||||||
instanceName: '',
|
|
||||||
accessType: '',
|
|
||||||
accessTypeName: '',
|
|
||||||
region: '',
|
|
||||||
shortName: '',
|
|
||||||
userId: null,
|
|
||||||
hiddenId: null,
|
|
||||||
privateId: null,
|
|
||||||
friendsId: null,
|
|
||||||
groupId: null,
|
|
||||||
groupAccessType: null,
|
|
||||||
canRequestInvite: false,
|
|
||||||
strict: false,
|
|
||||||
ageGate: false
|
|
||||||
};
|
|
||||||
if (_tag === 'offline' || _tag === 'offline:offline') {
|
|
||||||
ctx.isOffline = true;
|
|
||||||
} else if (_tag === 'private' || _tag === 'private:private') {
|
|
||||||
ctx.isPrivate = true;
|
|
||||||
} else if (_tag === 'traveling' || _tag === 'traveling:traveling') {
|
|
||||||
ctx.isTraveling = true;
|
|
||||||
} else if (tag && !_tag.startsWith('local')) {
|
|
||||||
ctx.isRealInstance = true;
|
|
||||||
const sep = _tag.indexOf(':');
|
|
||||||
// technically not part of instance id, but might be there when coping id from url so why not support it
|
|
||||||
const shortNameQualifier = '&shortName=';
|
|
||||||
const shortNameIndex = _tag.indexOf(shortNameQualifier);
|
|
||||||
if (shortNameIndex >= 0) {
|
|
||||||
ctx.shortName = _tag.substr(
|
|
||||||
shortNameIndex + shortNameQualifier.length
|
|
||||||
);
|
|
||||||
_tag = _tag.substr(0, shortNameIndex);
|
|
||||||
}
|
|
||||||
if (sep >= 0) {
|
|
||||||
ctx.worldId = _tag.substr(0, sep);
|
|
||||||
ctx.instanceId = _tag.substr(sep + 1);
|
|
||||||
ctx.instanceId.split('~').forEach((s, i) => {
|
|
||||||
if (i) {
|
|
||||||
const A = s.indexOf('(');
|
|
||||||
const Z = A >= 0 ? s.lastIndexOf(')') : -1;
|
|
||||||
const key = Z >= 0 ? s.substr(0, A) : s;
|
|
||||||
const value = A < Z ? s.substr(A + 1, Z - A - 1) : '';
|
|
||||||
if (key === 'hidden') {
|
|
||||||
ctx.hiddenId = value;
|
|
||||||
} else if (key === 'private') {
|
|
||||||
ctx.privateId = value;
|
|
||||||
} else if (key === 'friends') {
|
|
||||||
ctx.friendsId = value;
|
|
||||||
} else if (key === 'canRequestInvite') {
|
|
||||||
ctx.canRequestInvite = true;
|
|
||||||
} else if (key === 'region') {
|
|
||||||
ctx.region = value;
|
|
||||||
} else if (key === 'group') {
|
|
||||||
ctx.groupId = value;
|
|
||||||
} else if (key === 'groupAccessType') {
|
|
||||||
ctx.groupAccessType = value;
|
|
||||||
} else if (key === 'strict') {
|
|
||||||
ctx.strict = true;
|
|
||||||
} else if (key === 'ageGate') {
|
|
||||||
ctx.ageGate = true;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
ctx.instanceName = s;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
ctx.accessType = 'public';
|
|
||||||
if (ctx.privateId !== null) {
|
|
||||||
if (ctx.canRequestInvite) {
|
|
||||||
// InvitePlus
|
|
||||||
ctx.accessType = 'invite+';
|
|
||||||
} else {
|
|
||||||
// InviteOnly
|
|
||||||
ctx.accessType = 'invite';
|
|
||||||
}
|
|
||||||
ctx.userId = ctx.privateId;
|
|
||||||
} else if (ctx.friendsId !== null) {
|
|
||||||
// FriendsOnly
|
|
||||||
ctx.accessType = 'friends';
|
|
||||||
ctx.userId = ctx.friendsId;
|
|
||||||
} else if (ctx.hiddenId !== null) {
|
|
||||||
// FriendsOfGuests
|
|
||||||
ctx.accessType = 'friends+';
|
|
||||||
ctx.userId = ctx.hiddenId;
|
|
||||||
} else if (ctx.groupId !== null) {
|
|
||||||
// Group
|
|
||||||
ctx.accessType = 'group';
|
|
||||||
}
|
|
||||||
ctx.accessTypeName = ctx.accessType;
|
|
||||||
if (ctx.groupAccessType !== null) {
|
|
||||||
if (ctx.groupAccessType === 'public') {
|
|
||||||
ctx.accessTypeName = 'groupPublic';
|
|
||||||
} else if (ctx.groupAccessType === 'plus') {
|
|
||||||
ctx.accessTypeName = 'groupPlus';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
ctx.worldId = _tag;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return ctx;
|
|
||||||
}
|
|
||||||
|
|
||||||
function getFriendsLocations(friendsArr) {
|
function getFriendsLocations(friendsArr) {
|
||||||
const locationStore = useLocationStore();
|
const locationStore = useLocationStore();
|
||||||
@@ -168,4 +28,4 @@ function getFriendsLocations(friendsArr) {
|
|||||||
return friendsArr[0].ref?.location;
|
return friendsArr[0].ref?.location;
|
||||||
}
|
}
|
||||||
|
|
||||||
export { parseLocation, displayLocation, getFriendsLocations };
|
export { getFriendsLocations };
|
||||||
|
|||||||
149
src/shared/utils/locationParser.js
Normal file
149
src/shared/utils/locationParser.js
Normal file
@@ -0,0 +1,149 @@
|
|||||||
|
/**
|
||||||
|
* Pure location parsing utilities with no external dependencies.
|
||||||
|
* These functions are extracted to enable clean unit testing.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param {string} location
|
||||||
|
* @param {string} worldName
|
||||||
|
* @param {string?} groupName
|
||||||
|
* @returns {string}
|
||||||
|
*/
|
||||||
|
function displayLocation(location, worldName, groupName = '') {
|
||||||
|
let text = worldName;
|
||||||
|
const L = parseLocation(location);
|
||||||
|
if (L.isOffline) {
|
||||||
|
text = 'Offline';
|
||||||
|
} else if (L.isPrivate) {
|
||||||
|
text = 'Private';
|
||||||
|
} else if (L.isTraveling) {
|
||||||
|
text = 'Traveling';
|
||||||
|
} else if (L.worldId) {
|
||||||
|
if (groupName) {
|
||||||
|
text = `${worldName} ${L.accessTypeName}(${groupName})`;
|
||||||
|
} else if (L.instanceId) {
|
||||||
|
text = `${worldName} ${L.accessTypeName}`;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return text;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param {string} tag
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
function parseLocation(tag) {
|
||||||
|
let _tag = String(tag || '');
|
||||||
|
const ctx = {
|
||||||
|
tag: _tag,
|
||||||
|
isOffline: false,
|
||||||
|
isPrivate: false,
|
||||||
|
isTraveling: false,
|
||||||
|
isRealInstance: false,
|
||||||
|
worldId: '',
|
||||||
|
instanceId: '',
|
||||||
|
instanceName: '',
|
||||||
|
accessType: '',
|
||||||
|
accessTypeName: '',
|
||||||
|
region: '',
|
||||||
|
shortName: '',
|
||||||
|
userId: null,
|
||||||
|
hiddenId: null,
|
||||||
|
privateId: null,
|
||||||
|
friendsId: null,
|
||||||
|
groupId: null,
|
||||||
|
groupAccessType: null,
|
||||||
|
canRequestInvite: false,
|
||||||
|
strict: false,
|
||||||
|
ageGate: false
|
||||||
|
};
|
||||||
|
if (_tag === 'offline' || _tag === 'offline:offline') {
|
||||||
|
ctx.isOffline = true;
|
||||||
|
} else if (_tag === 'private' || _tag === 'private:private') {
|
||||||
|
ctx.isPrivate = true;
|
||||||
|
} else if (_tag === 'traveling' || _tag === 'traveling:traveling') {
|
||||||
|
ctx.isTraveling = true;
|
||||||
|
} else if (tag && !_tag.startsWith('local')) {
|
||||||
|
ctx.isRealInstance = true;
|
||||||
|
const sep = _tag.indexOf(':');
|
||||||
|
// technically not part of instance id, but might be there when coping id from url so why not support it
|
||||||
|
const shortNameQualifier = '&shortName=';
|
||||||
|
const shortNameIndex = _tag.indexOf(shortNameQualifier);
|
||||||
|
if (shortNameIndex >= 0) {
|
||||||
|
ctx.shortName = _tag.substr(
|
||||||
|
shortNameIndex + shortNameQualifier.length
|
||||||
|
);
|
||||||
|
_tag = _tag.substr(0, shortNameIndex);
|
||||||
|
}
|
||||||
|
if (sep >= 0) {
|
||||||
|
ctx.worldId = _tag.substr(0, sep);
|
||||||
|
ctx.instanceId = _tag.substr(sep + 1);
|
||||||
|
ctx.instanceId.split('~').forEach((s, i) => {
|
||||||
|
if (i) {
|
||||||
|
const A = s.indexOf('(');
|
||||||
|
const Z = A >= 0 ? s.lastIndexOf(')') : -1;
|
||||||
|
const key = Z >= 0 ? s.substr(0, A) : s;
|
||||||
|
const value = A < Z ? s.substr(A + 1, Z - A - 1) : '';
|
||||||
|
if (key === 'hidden') {
|
||||||
|
ctx.hiddenId = value;
|
||||||
|
} else if (key === 'private') {
|
||||||
|
ctx.privateId = value;
|
||||||
|
} else if (key === 'friends') {
|
||||||
|
ctx.friendsId = value;
|
||||||
|
} else if (key === 'canRequestInvite') {
|
||||||
|
ctx.canRequestInvite = true;
|
||||||
|
} else if (key === 'region') {
|
||||||
|
ctx.region = value;
|
||||||
|
} else if (key === 'group') {
|
||||||
|
ctx.groupId = value;
|
||||||
|
} else if (key === 'groupAccessType') {
|
||||||
|
ctx.groupAccessType = value;
|
||||||
|
} else if (key === 'strict') {
|
||||||
|
ctx.strict = true;
|
||||||
|
} else if (key === 'ageGate') {
|
||||||
|
ctx.ageGate = true;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
ctx.instanceName = s;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
ctx.accessType = 'public';
|
||||||
|
if (ctx.privateId !== null) {
|
||||||
|
if (ctx.canRequestInvite) {
|
||||||
|
// InvitePlus
|
||||||
|
ctx.accessType = 'invite+';
|
||||||
|
} else {
|
||||||
|
// InviteOnly
|
||||||
|
ctx.accessType = 'invite';
|
||||||
|
}
|
||||||
|
ctx.userId = ctx.privateId;
|
||||||
|
} else if (ctx.friendsId !== null) {
|
||||||
|
// FriendsOnly
|
||||||
|
ctx.accessType = 'friends';
|
||||||
|
ctx.userId = ctx.friendsId;
|
||||||
|
} else if (ctx.hiddenId !== null) {
|
||||||
|
// FriendsOfGuests
|
||||||
|
ctx.accessType = 'friends+';
|
||||||
|
ctx.userId = ctx.hiddenId;
|
||||||
|
} else if (ctx.groupId !== null) {
|
||||||
|
// Group
|
||||||
|
ctx.accessType = 'group';
|
||||||
|
}
|
||||||
|
ctx.accessTypeName = ctx.accessType;
|
||||||
|
if (ctx.groupAccessType !== null) {
|
||||||
|
if (ctx.groupAccessType === 'public') {
|
||||||
|
ctx.accessTypeName = 'groupPublic';
|
||||||
|
} else if (ctx.groupAccessType === 'plus') {
|
||||||
|
ctx.accessTypeName = 'groupPlus';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
ctx.worldId = _tag;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ctx;
|
||||||
|
}
|
||||||
|
|
||||||
|
export { parseLocation, displayLocation };
|
||||||
@@ -12,7 +12,7 @@
|
|||||||
"moduleResolution": "bundler",
|
"moduleResolution": "bundler",
|
||||||
"forceConsistentCasingInFileNames": true,
|
"forceConsistentCasingInFileNames": true,
|
||||||
"lib": ["esnext", "dom", "dom.iterable"],
|
"lib": ["esnext", "dom", "dom.iterable"],
|
||||||
"types": ["vite/client"],
|
"types": ["vite/client", "vitest/globals"],
|
||||||
"resolveJsonModule": true,
|
"resolveJsonModule": true,
|
||||||
"noEmit": true,
|
"noEmit": true,
|
||||||
"strict": false,
|
"strict": false,
|
||||||
|
|||||||
@@ -2,10 +2,14 @@ import { resolve } from 'node:path';
|
|||||||
|
|
||||||
import { defineConfig } from 'vitest/config';
|
import { defineConfig } from 'vitest/config';
|
||||||
|
|
||||||
|
import vue from '@vitejs/plugin-vue';
|
||||||
|
|
||||||
export default defineConfig({
|
export default defineConfig({
|
||||||
|
plugins: [vue()],
|
||||||
test: {
|
test: {
|
||||||
globals: true,
|
globals: true,
|
||||||
environment: 'node',
|
environment: 'node',
|
||||||
|
setupFiles: ['./vitest.setup.js'],
|
||||||
include: ['src/**/*.{test,spec}.js'],
|
include: ['src/**/*.{test,spec}.js'],
|
||||||
coverage: {
|
coverage: {
|
||||||
reporter: ['text', 'text-summary'],
|
reporter: ['text', 'text-summary'],
|
||||||
|
|||||||
10
vitest.setup.js
Normal file
10
vitest.setup.js
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
/**
|
||||||
|
* Vitest global setup file.
|
||||||
|
* Loads English locale messages into i18n so that
|
||||||
|
* translation calls return expected values in tests.
|
||||||
|
*/
|
||||||
|
import { i18n } from './src/plugin/i18n';
|
||||||
|
|
||||||
|
import en from './src/localization/en.json';
|
||||||
|
|
||||||
|
i18n.global.setLocaleMessage('en', en);
|
||||||
Reference in New Issue
Block a user