mirror of
https://github.com/antebudimir/feishin.git
synced 2025-12-31 10:03:33 +00:00
reorganize global types to shared directory
This commit is contained in:
parent
26c02e03c5
commit
9db2e51d2d
17 changed files with 160 additions and 144 deletions
|
|
@ -28,6 +28,7 @@ export default tseslint.config(
|
||||||
...eslintPluginReactHooks.configs.recommended.rules,
|
...eslintPluginReactHooks.configs.recommended.rules,
|
||||||
...eslintPluginReactRefresh.configs.vite.rules,
|
...eslintPluginReactRefresh.configs.vite.rules,
|
||||||
'@typescript-eslint/explicit-function-return-type': 'off',
|
'@typescript-eslint/explicit-function-return-type': 'off',
|
||||||
|
'@typescript-eslint/no-duplicate-enum-values': 'off',
|
||||||
'@typescript-eslint/no-unused-vars': 'warn',
|
'@typescript-eslint/no-unused-vars': 'warn',
|
||||||
curly: ['error', 'all'],
|
curly: ['error', 'all'],
|
||||||
indent: [
|
indent: [
|
||||||
|
|
|
||||||
|
|
@ -1,34 +1,6 @@
|
||||||
import { AxiosHeaders } from 'axios';
|
import { toast } from '/@/renderer/components';
|
||||||
import isElectron from 'is-electron';
|
|
||||||
import semverCoerce from 'semver/functions/coerce';
|
|
||||||
import semverGte from 'semver/functions/gte';
|
|
||||||
import { z } from 'zod';
|
|
||||||
|
|
||||||
import { ServerFeature } from '/@/renderer/api/features-types';
|
|
||||||
import { ServerListItem } from '/@/renderer/api/types';
|
|
||||||
import { toast } from '/@/renderer/components/toast';
|
|
||||||
import { useAuthStore } from '/@/renderer/store';
|
import { useAuthStore } from '/@/renderer/store';
|
||||||
|
import { ServerListItem } from '/@/shared/types/types';
|
||||||
// Since ts-rest client returns a strict response type, we need to add the headers to the body object
|
|
||||||
export const resultWithHeaders = <ItemType extends z.ZodTypeAny>(itemSchema: ItemType) => {
|
|
||||||
return z.object({
|
|
||||||
data: itemSchema,
|
|
||||||
headers: z.instanceof(AxiosHeaders),
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
export const resultSubsonicBaseResponse = <ItemType extends z.ZodRawShape>(
|
|
||||||
itemSchema: ItemType,
|
|
||||||
) => {
|
|
||||||
return z.object({
|
|
||||||
'subsonic-response': z
|
|
||||||
.object({
|
|
||||||
status: z.string(),
|
|
||||||
version: z.string(),
|
|
||||||
})
|
|
||||||
.extend(itemSchema),
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
export const authenticationFailure = (currentServer: null | ServerListItem) => {
|
export const authenticationFailure = (currentServer: null | ServerListItem) => {
|
||||||
toast.error({
|
toast.error({
|
||||||
|
|
@ -43,87 +15,3 @@ export const authenticationFailure = (currentServer: null | ServerListItem) => {
|
||||||
useAuthStore.getState().actions.setCurrentServer(null);
|
useAuthStore.getState().actions.setCurrentServer(null);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
export const hasFeature = (server: null | ServerListItem, feature: ServerFeature): boolean => {
|
|
||||||
if (!server || !server.features) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return (server.features[feature]?.length || 0) > 0;
|
|
||||||
};
|
|
||||||
|
|
||||||
export type VersionInfo = ReadonlyArray<[string, Record<string, readonly number[]>]>;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the available server features given the version string.
|
|
||||||
* @param versionInfo a list, in DECREASING VERSION order, of the features supported by the server.
|
|
||||||
* The first version match will automatically consider the rest matched.
|
|
||||||
* @example
|
|
||||||
* ```
|
|
||||||
* // The CORRECT way to order
|
|
||||||
* const VERSION_INFO: VersionInfo = [
|
|
||||||
* ['0.49.3', { [ServerFeature.SHARING_ALBUM_SONG]: [1] }],
|
|
||||||
* ['0.48.0', { [ServerFeature.PLAYLISTS_SMART]: [1] }],
|
|
||||||
* ];
|
|
||||||
* // INCORRECT way to order
|
|
||||||
* const VERSION_INFO: VersionInfo = [
|
|
||||||
* ['0.48.0', { [ServerFeature.PLAYLISTS_SMART]: [1] }],
|
|
||||||
* ['0.49.3', { [ServerFeature.SHARING_ALBUM_SONG]: [1] }],
|
|
||||||
* ];
|
|
||||||
* ```
|
|
||||||
* @param version the version string (SemVer)
|
|
||||||
* @returns a Record containing the matched features (if any) and their versions
|
|
||||||
*/
|
|
||||||
export const getFeatures = (
|
|
||||||
versionInfo: VersionInfo,
|
|
||||||
version: string,
|
|
||||||
): Record<string, number[]> => {
|
|
||||||
const cleanVersion = semverCoerce(version);
|
|
||||||
const features: Record<string, number[]> = {};
|
|
||||||
let matched = cleanVersion === null;
|
|
||||||
|
|
||||||
for (const [version, supportedFeatures] of versionInfo) {
|
|
||||||
if (!matched) {
|
|
||||||
matched = semverGte(cleanVersion!, version);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (matched) {
|
|
||||||
for (const [feature, feat] of Object.entries(supportedFeatures)) {
|
|
||||||
if (feature in features) {
|
|
||||||
features[feature].push(...feat);
|
|
||||||
} else {
|
|
||||||
features[feature] = [...feat];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return features;
|
|
||||||
};
|
|
||||||
|
|
||||||
export const getClientType = (): string => {
|
|
||||||
if (isElectron()) {
|
|
||||||
return 'Desktop Client';
|
|
||||||
}
|
|
||||||
const agent = navigator.userAgent;
|
|
||||||
switch (true) {
|
|
||||||
case agent.toLowerCase().indexOf('edge') > -1:
|
|
||||||
return 'Microsoft Edge';
|
|
||||||
case agent.toLowerCase().indexOf('edg/') > -1:
|
|
||||||
return 'Edge Chromium'; // Match also / to avoid matching for the older Edge
|
|
||||||
case agent.toLowerCase().indexOf('opr') > -1:
|
|
||||||
return 'Opera';
|
|
||||||
case agent.toLowerCase().indexOf('chrome') > -1:
|
|
||||||
return 'Chrome';
|
|
||||||
case agent.toLowerCase().indexOf('trident') > -1:
|
|
||||||
return 'Internet Explorer';
|
|
||||||
case agent.toLowerCase().indexOf('firefox') > -1:
|
|
||||||
return 'Firefox';
|
|
||||||
case agent.toLowerCase().indexOf('safari') > -1:
|
|
||||||
return 'Safari';
|
|
||||||
default:
|
|
||||||
return 'PC';
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
export const SEPARATOR_STRING = ' · ';
|
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,8 @@
|
||||||
import { nanoid } from 'nanoid';
|
import { nanoid } from 'nanoid';
|
||||||
import { z } from 'zod';
|
import { z } from 'zod';
|
||||||
|
|
||||||
import { JFAlbum, JFGenre, JFMusicFolder, JFPlaylist } from '/@/renderer/api/jellyfin.types';
|
import { JFAlbum, JFGenre, JFMusicFolder, JFPlaylist } from '/@/shared/api/jellyfin.types';
|
||||||
import { jfType } from '/@/renderer/api/jellyfin/jellyfin-types';
|
import { jfType } from '/@/shared/api/jellyfin/jellyfin-types';
|
||||||
import {
|
import {
|
||||||
Album,
|
Album,
|
||||||
AlbumArtist,
|
AlbumArtist,
|
||||||
|
|
@ -11,10 +11,9 @@ import {
|
||||||
MusicFolder,
|
MusicFolder,
|
||||||
Playlist,
|
Playlist,
|
||||||
RelatedArtist,
|
RelatedArtist,
|
||||||
ServerListItem,
|
|
||||||
ServerType,
|
|
||||||
Song,
|
Song,
|
||||||
} from '/@/renderer/api/types';
|
} from '/@/shared/types/domain-types';
|
||||||
|
import { ServerListItem, ServerType } from '/@/shared/types/types';
|
||||||
|
|
||||||
const getStreamUrl = (args: {
|
const getStreamUrl = (args: {
|
||||||
container?: string;
|
container?: string;
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
import { SSArtistInfo } from '/@/renderer/api/subsonic.types';
|
import { SSArtistInfo } from '/@/shared/api/subsonic.types';
|
||||||
|
|
||||||
export enum NDAlbumArtistListSort {
|
export enum NDAlbumArtistListSort {
|
||||||
ALBUM_COUNT = 'albumCount',
|
ALBUM_COUNT = 'albumCount',
|
||||||
|
|
@ -197,7 +197,7 @@ export type NDCreatePlaylistParams = {
|
||||||
comment?: string;
|
comment?: string;
|
||||||
name: string;
|
name: string;
|
||||||
public?: boolean;
|
public?: boolean;
|
||||||
rules?: null | Record<string, any>;
|
rules?: null | Record<string, unknown>;
|
||||||
};
|
};
|
||||||
|
|
||||||
export type NDCreatePlaylistResponse = {
|
export type NDCreatePlaylistResponse = {
|
||||||
|
|
@ -247,7 +247,7 @@ export type NDPlaylist = {
|
||||||
ownerName: string;
|
ownerName: string;
|
||||||
path: string;
|
path: string;
|
||||||
public: boolean;
|
public: boolean;
|
||||||
rules: null | Record<string, any>;
|
rules: null | Record<string, unknown>;
|
||||||
size: number;
|
size: number;
|
||||||
songCount: number;
|
songCount: number;
|
||||||
sync: boolean;
|
sync: boolean;
|
||||||
|
|
@ -1,10 +1,9 @@
|
||||||
import { nanoid } from 'nanoid';
|
import { nanoid } from 'nanoid';
|
||||||
import z from 'zod';
|
import z from 'zod';
|
||||||
|
|
||||||
import { ndType } from './navidrome-types';
|
import { NDGenre } from '/@/shared/api/navidrome.types';
|
||||||
|
import { ndType } from '/@/shared/api/navidrome/navidrome-types';
|
||||||
import { NDGenre } from '/@/renderer/api/navidrome.types';
|
import { ssType } from '/@/shared/api/subsonic/subsonic-types';
|
||||||
import { ssType } from '/@/renderer/api/subsonic/subsonic-types';
|
|
||||||
import {
|
import {
|
||||||
Album,
|
Album,
|
||||||
AlbumArtist,
|
AlbumArtist,
|
||||||
|
|
@ -12,11 +11,10 @@ import {
|
||||||
LibraryItem,
|
LibraryItem,
|
||||||
Playlist,
|
Playlist,
|
||||||
RelatedArtist,
|
RelatedArtist,
|
||||||
ServerListItem,
|
|
||||||
ServerType,
|
|
||||||
Song,
|
Song,
|
||||||
User,
|
User,
|
||||||
} from '/@/renderer/api/types';
|
} from '/@/shared/types/domain-types';
|
||||||
|
import { ServerListItem, ServerType } from '/@/shared/types/types';
|
||||||
|
|
||||||
const getImageUrl = (args: { url: null | string }) => {
|
const getImageUrl = (args: { url: null | string }) => {
|
||||||
const { url } = args;
|
const { url } = args;
|
||||||
|
|
@ -5,7 +5,7 @@ import {
|
||||||
NDAlbumListSort,
|
NDAlbumListSort,
|
||||||
NDPlaylistListSort,
|
NDPlaylistListSort,
|
||||||
NDSongListSort,
|
NDSongListSort,
|
||||||
} from '/@/renderer/api/navidrome.types';
|
} from '/@/shared/api/navidrome.types';
|
||||||
|
|
||||||
const sortOrderValues = ['ASC', 'DESC'] as const;
|
const sortOrderValues = ['ASC', 'DESC'] as const;
|
||||||
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
import { nanoid } from 'nanoid';
|
import { nanoid } from 'nanoid';
|
||||||
import { z } from 'zod';
|
import { z } from 'zod';
|
||||||
|
|
||||||
import { ssType } from '/@/renderer/api/subsonic/subsonic-types';
|
import { ssType } from '/@/shared/api/subsonic/subsonic-types';
|
||||||
import {
|
import {
|
||||||
Album,
|
Album,
|
||||||
AlbumArtist,
|
AlbumArtist,
|
||||||
|
|
@ -12,7 +12,7 @@ import {
|
||||||
RelatedArtist,
|
RelatedArtist,
|
||||||
ServerListItem,
|
ServerListItem,
|
||||||
ServerType,
|
ServerType,
|
||||||
} from '/@/renderer/api/types';
|
} from '/@/shared/types/domain-types';
|
||||||
|
|
||||||
const getCoverArtUrl = (args: {
|
const getCoverArtUrl = (args: {
|
||||||
baseUrl: string | undefined;
|
baseUrl: string | undefined;
|
||||||
113
src/shared/api/utils.ts
Normal file
113
src/shared/api/utils.ts
Normal file
|
|
@ -0,0 +1,113 @@
|
||||||
|
import { AxiosHeaders } from 'axios';
|
||||||
|
import isElectron from 'is-electron';
|
||||||
|
import semverCoerce from 'semver/functions/coerce';
|
||||||
|
import semverGte from 'semver/functions/gte';
|
||||||
|
import { z } from 'zod';
|
||||||
|
|
||||||
|
import { ServerListItem } from '/@/shared/types/domain-types';
|
||||||
|
import { ServerFeature } from '/@/shared/types/features-types';
|
||||||
|
|
||||||
|
// Since ts-rest client returns a strict response type, we need to add the headers to the body object
|
||||||
|
export const resultWithHeaders = <ItemType extends z.ZodTypeAny>(itemSchema: ItemType) => {
|
||||||
|
return z.object({
|
||||||
|
data: itemSchema,
|
||||||
|
headers: z.instanceof(AxiosHeaders),
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
export const resultSubsonicBaseResponse = <ItemType extends z.ZodRawShape>(
|
||||||
|
itemSchema: ItemType,
|
||||||
|
) => {
|
||||||
|
return z.object({
|
||||||
|
'subsonic-response': z
|
||||||
|
.object({
|
||||||
|
status: z.string(),
|
||||||
|
version: z.string(),
|
||||||
|
})
|
||||||
|
.extend(itemSchema),
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
export const hasFeature = (server: null | ServerListItem, feature: ServerFeature): boolean => {
|
||||||
|
if (!server || !server.features) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (server.features[feature]?.length || 0) > 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type VersionInfo = ReadonlyArray<[string, Record<string, readonly number[]>]>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the available server features given the version string.
|
||||||
|
* @param versionInfo a list, in DECREASING VERSION order, of the features supported by the server.
|
||||||
|
* The first version match will automatically consider the rest matched.
|
||||||
|
* @example
|
||||||
|
* ```
|
||||||
|
* // The CORRECT way to order
|
||||||
|
* const VERSION_INFO: VersionInfo = [
|
||||||
|
* ['0.49.3', { [ServerFeature.SHARING_ALBUM_SONG]: [1] }],
|
||||||
|
* ['0.48.0', { [ServerFeature.PLAYLISTS_SMART]: [1] }],
|
||||||
|
* ];
|
||||||
|
* // INCORRECT way to order
|
||||||
|
* const VERSION_INFO: VersionInfo = [
|
||||||
|
* ['0.48.0', { [ServerFeature.PLAYLISTS_SMART]: [1] }],
|
||||||
|
* ['0.49.3', { [ServerFeature.SHARING_ALBUM_SONG]: [1] }],
|
||||||
|
* ];
|
||||||
|
* ```
|
||||||
|
* @param version the version string (SemVer)
|
||||||
|
* @returns a Record containing the matched features (if any) and their versions
|
||||||
|
*/
|
||||||
|
export const getFeatures = (
|
||||||
|
versionInfo: VersionInfo,
|
||||||
|
version: string,
|
||||||
|
): Record<string, number[]> => {
|
||||||
|
const cleanVersion = semverCoerce(version);
|
||||||
|
const features: Record<string, number[]> = {};
|
||||||
|
let matched = cleanVersion === null;
|
||||||
|
|
||||||
|
for (const [version, supportedFeatures] of versionInfo) {
|
||||||
|
if (!matched) {
|
||||||
|
matched = semverGte(cleanVersion!, version);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (matched) {
|
||||||
|
for (const [feature, feat] of Object.entries(supportedFeatures)) {
|
||||||
|
if (feature in features) {
|
||||||
|
features[feature].push(...feat);
|
||||||
|
} else {
|
||||||
|
features[feature] = [...feat];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return features;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const getClientType = (): string => {
|
||||||
|
if (isElectron()) {
|
||||||
|
return 'Desktop Client';
|
||||||
|
}
|
||||||
|
const agent = navigator.userAgent;
|
||||||
|
switch (true) {
|
||||||
|
case agent.toLowerCase().indexOf('edge') > -1:
|
||||||
|
return 'Microsoft Edge';
|
||||||
|
case agent.toLowerCase().indexOf('edg/') > -1:
|
||||||
|
return 'Edge Chromium'; // Match also / to avoid matching for the older Edge
|
||||||
|
case agent.toLowerCase().indexOf('opr') > -1:
|
||||||
|
return 'Opera';
|
||||||
|
case agent.toLowerCase().indexOf('chrome') > -1:
|
||||||
|
return 'Chrome';
|
||||||
|
case agent.toLowerCase().indexOf('trident') > -1:
|
||||||
|
return 'Internet Explorer';
|
||||||
|
case agent.toLowerCase().indexOf('firefox') > -1:
|
||||||
|
return 'Firefox';
|
||||||
|
case agent.toLowerCase().indexOf('safari') > -1:
|
||||||
|
return 'Safari';
|
||||||
|
default:
|
||||||
|
return 'PC';
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
export const SEPARATOR_STRING = ' · ';
|
||||||
|
|
@ -3,7 +3,8 @@ import reverse from 'lodash/reverse';
|
||||||
import shuffle from 'lodash/shuffle';
|
import shuffle from 'lodash/shuffle';
|
||||||
import { z } from 'zod';
|
import { z } from 'zod';
|
||||||
|
|
||||||
import { ServerFeatures } from './features-types';
|
import { jfType } from '../../renderer/api/jellyfin/jellyfin-types';
|
||||||
|
import { ndType } from '../api/navidrome/navidrome-types';
|
||||||
import {
|
import {
|
||||||
JFAlbumArtistListSort,
|
JFAlbumArtistListSort,
|
||||||
JFAlbumListSort,
|
JFAlbumListSort,
|
||||||
|
|
@ -12,8 +13,7 @@ import {
|
||||||
JFPlaylistListSort,
|
JFPlaylistListSort,
|
||||||
JFSongListSort,
|
JFSongListSort,
|
||||||
JFSortOrder,
|
JFSortOrder,
|
||||||
} from './jellyfin.types';
|
} from '../renderer/api/jellyfin.types';
|
||||||
import { jfType } from './jellyfin/jellyfin-types';
|
|
||||||
import {
|
import {
|
||||||
NDAlbumArtistListSort,
|
NDAlbumArtistListSort,
|
||||||
NDAlbumListSort,
|
NDAlbumListSort,
|
||||||
|
|
@ -23,8 +23,8 @@ import {
|
||||||
NDSongListSort,
|
NDSongListSort,
|
||||||
NDSortOrder,
|
NDSortOrder,
|
||||||
NDUserListSort,
|
NDUserListSort,
|
||||||
} from './navidrome.types';
|
} from '../renderer/api/navidrome.types';
|
||||||
import { ndType } from './navidrome/navidrome-types';
|
import { ServerFeatures } from './features-types';
|
||||||
|
|
||||||
export enum LibraryItem {
|
export enum LibraryItem {
|
||||||
ALBUM = 'album',
|
ALBUM = 'album',
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
|
import { AppRoute } from '@ts-rest/core';
|
||||||
import { ReactNode } from 'react';
|
import { ReactNode } from 'react';
|
||||||
|
import { Song } from 'src/main/features/core/lyrics/netease';
|
||||||
|
|
||||||
import { ServerFeatures } from '/@/renderer/api/features-types';
|
|
||||||
import {
|
import {
|
||||||
Album,
|
Album,
|
||||||
AlbumArtist,
|
AlbumArtist,
|
||||||
|
|
@ -8,9 +9,8 @@ import {
|
||||||
LibraryItem,
|
LibraryItem,
|
||||||
Playlist,
|
Playlist,
|
||||||
QueueSong,
|
QueueSong,
|
||||||
Song,
|
} from '/@/shared/types/domain-types';
|
||||||
} from '/@/renderer/api/types';
|
import { ServerFeatures } from '/@/shared/types/features-types';
|
||||||
import { AppRoute } from '/@/renderer/router/routes';
|
|
||||||
|
|
||||||
export enum ListDisplayType {
|
export enum ListDisplayType {
|
||||||
CARD = 'card',
|
CARD = 'card',
|
||||||
|
|
@ -1,8 +1,24 @@
|
||||||
{
|
{
|
||||||
"extends": "@electron-toolkit/tsconfig/tsconfig.node.json",
|
"extends": "@electron-toolkit/tsconfig/tsconfig.node.json",
|
||||||
"include": ["electron.vite.config.*", "src/main/**/*", "src/preload/**/*", "src/i18n/**/*"],
|
"include": ["electron.vite.config.*", "src/main/**/*", "src/preload/**/*", "src/i18n/**/*", "src/types/**/*", "src/shared/**/*", "src/renderer/api/jellyfin/jellyfin-controller.ts", "src/renderer/api/jellyfin/jellyfin-api.ts", "src/renderer/api/navidrome/navidrome-api.ts", "src/renderer/api/navidrome/navidrome-controller.ts", "src/renderer/api/subsonic/subsonic-api.ts", "src/renderer/api/subsonic/subsonic-controller.ts"],
|
||||||
"compilerOptions": {
|
"compilerOptions": {
|
||||||
"composite": true,
|
"composite": true,
|
||||||
"types": ["electron-vite/node"]
|
"types": ["electron-vite/node"],
|
||||||
|
"esModuleInterop": true,
|
||||||
|
"baseUrl": ".",
|
||||||
|
"paths": {
|
||||||
|
"/@/renderer/*": [
|
||||||
|
"src/renderer/*"
|
||||||
|
],
|
||||||
|
"/@/main/*": [
|
||||||
|
"src/main/src/*"
|
||||||
|
],
|
||||||
|
"/@/preload/*": [
|
||||||
|
"src/preload/*"
|
||||||
|
],
|
||||||
|
"/@/shared/*": [
|
||||||
|
"src/shared/*"
|
||||||
|
],
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -6,6 +6,7 @@
|
||||||
"src/renderer/**/*.tsx",
|
"src/renderer/**/*.tsx",
|
||||||
"src/preload/*.d.ts",
|
"src/preload/*.d.ts",
|
||||||
"src/i18n/**/*",
|
"src/i18n/**/*",
|
||||||
|
"src/shared/**/*",
|
||||||
"package.json"
|
"package.json"
|
||||||
],
|
],
|
||||||
"compilerOptions": {
|
"compilerOptions": {
|
||||||
|
|
@ -21,7 +22,7 @@
|
||||||
"src/main/src/*"
|
"src/main/src/*"
|
||||||
],
|
],
|
||||||
"/@/shared/*": [
|
"/@/shared/*": [
|
||||||
"src/shared/src/*"
|
"src/shared/*"
|
||||||
],
|
],
|
||||||
"/@/i18n/*": [
|
"/@/i18n/*": [
|
||||||
"src/i18n/*"
|
"src/i18n/*"
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue