chore(deps): update dependency eslint-plugin-unicorn to v73 (#30844)

Co-authored-by: Daniel Dietzler <mail@ddietzler.dev>
This commit is contained in:
renovate[bot]
2026-08-18 12:00:16 +02:00
committed by GitHub
co-authored by Daniel Dietzler
parent 225ca9ab8d
commit 11755e5a53
36 changed files with 309 additions and 115 deletions
+1 -1
View File
@@ -40,7 +40,7 @@
"eslint": "^10.0.0",
"eslint-config-prettier": "^10.1.8",
"eslint-plugin-prettier": "^5.1.3",
"eslint-plugin-unicorn": "^72.0.0",
"eslint-plugin-unicorn": "^73.0.0",
"exiftool-vendored": "^35.0.0",
"globals": "^17.0.0",
"luxon": "^3.4.4",
+3 -1
View File
@@ -29,7 +29,9 @@ describe('/users', () => {
});
describe('PUT /users/me', () => {
/** @deprecated */
/**
@deprecated
*/
it('should allow a user to change their password (deprecated)', async () => {
const user = await getMyUser({ headers: asBearerAuth(nonAdmin.accessToken) });
+1 -1
View File
@@ -33,7 +33,7 @@
"eslint": "^10.0.0",
"eslint-config-prettier": "^10.1.8",
"eslint-plugin-prettier": "^5.1.3",
"eslint-plugin-unicorn": "^72.0.0",
"eslint-plugin-unicorn": "^73.0.0",
"globals": "^17.0.0",
"mock-fs": "^5.2.0",
"prettier": "^3.7.4",
+11 -11
View File
@@ -157,8 +157,8 @@ importers:
specifier: ^5.1.3
version: 5.5.6(@types/eslint@9.6.1)(eslint-config-prettier@10.1.8(eslint@10.8.0(jiti@2.7.0)(supports-color@8.1.1)))(eslint@10.8.0(jiti@2.7.0)(supports-color@8.1.1))(prettier@3.9.6)
eslint-plugin-unicorn:
specifier: ^72.0.0
version: 72.0.0(eslint@10.8.0(jiti@2.7.0)(supports-color@8.1.1))
specifier: ^73.0.0
version: 73.0.0(eslint@10.8.0(jiti@2.7.0)(supports-color@8.1.1))
exiftool-vendored:
specifier: ^35.0.0
version: 35.21.0
@@ -269,8 +269,8 @@ importers:
specifier: ^5.1.3
version: 5.5.6(@types/eslint@9.6.1)(eslint-config-prettier@10.1.8(eslint@10.8.0(jiti@2.7.0)(supports-color@8.1.1)))(eslint@10.8.0(jiti@2.7.0)(supports-color@8.1.1))(prettier@3.9.6)
eslint-plugin-unicorn:
specifier: ^72.0.0
version: 72.0.0(eslint@10.8.0(jiti@2.7.0)(supports-color@8.1.1))
specifier: ^73.0.0
version: 73.0.0(eslint@10.8.0(jiti@2.7.0)(supports-color@8.1.1))
globals:
specifier: ^17.0.0
version: 17.9.0
@@ -741,8 +741,8 @@ importers:
specifier: ^5.1.3
version: 5.5.6(@types/eslint@9.6.1)(eslint-config-prettier@10.1.8(eslint@10.8.0(jiti@2.7.0)(supports-color@8.1.1)))(eslint@10.8.0(jiti@2.7.0)(supports-color@8.1.1))(prettier@3.9.6)
eslint-plugin-unicorn:
specifier: ^72.0.0
version: 72.0.0(eslint@10.8.0(jiti@2.7.0)(supports-color@8.1.1))
specifier: ^73.0.0
version: 73.0.0(eslint@10.8.0(jiti@2.7.0)(supports-color@8.1.1))
globals:
specifier: ^17.0.0
version: 17.9.0
@@ -1006,8 +1006,8 @@ importers:
specifier: ^3.12.4
version: 3.22.0(eslint@10.8.0(jiti@2.7.0)(supports-color@8.1.1))(svelte@5.56.8(@typescript-eslint/types@8.66.0))
eslint-plugin-unicorn:
specifier: ^72.0.0
version: 72.0.0(eslint@10.8.0(jiti@2.7.0)(supports-color@8.1.1))
specifier: ^73.0.0
version: 73.0.0(eslint@10.8.0(jiti@2.7.0)(supports-color@8.1.1))
factory.ts:
specifier: ^1.4.1
version: 1.4.2
@@ -7582,8 +7582,8 @@ packages:
svelte:
optional: true
eslint-plugin-unicorn@72.0.0:
resolution: {integrity: sha512-hqO6ksoOHO+ZhdseTuKRVQbx9U7PRO/cv8qAR1mctwzdVO2hYud8uS9luAhp43RJgziYgHAph8eHyipT8GL0ng==}
eslint-plugin-unicorn@73.0.0:
resolution: {integrity: sha512-V0YatLe9nkGhXEXKe2Qljb1EY0sJHwDV0HUF1NKFwtsHh/fU7qGHDgv+6fchzZcgU2/7noHo2gdjnmo0P2uDPw==}
engines: {node: '>=22'}
peerDependencies:
eslint: '>=10.4'
@@ -20606,7 +20606,7 @@ snapshots:
transitivePeerDependencies:
- ts-node
eslint-plugin-unicorn@72.0.0(eslint@10.8.0(jiti@2.7.0)(supports-color@8.1.1)):
eslint-plugin-unicorn@73.0.0(eslint@10.8.0(jiti@2.7.0)(supports-color@8.1.1)):
dependencies:
'@eslint-community/eslint-utils': 4.10.1(eslint@10.8.0(jiti@2.7.0)(supports-color@8.1.1))
'@eslint/css-tree': 4.0.5
+1 -1
View File
@@ -151,7 +151,7 @@
"eslint": "^10.0.0",
"eslint-config-prettier": "^10.1.8",
"eslint-plugin-prettier": "^5.1.3",
"eslint-plugin-unicorn": "^72.0.0",
"eslint-plugin-unicorn": "^73.0.0",
"globals": "^17.0.0",
"mock-fs": "^5.2.0",
"pngjs": "^7.0.0",
@@ -7,7 +7,9 @@ import request from 'supertest';
import { errorDto } from 'test/medium/responses';
import { ControllerContext, controllerSetup, mockBaseService } from 'test/utils';
/** Returns a full config that passes Zod validation (required URLs and min lengths). */
/**
Returns a full config that passes Zod validation (required URLs and min lengths).
*/
function validConfig() {
const config = _.cloneDeep(defaults) as typeof defaults & {
oauth: { mobileRedirectUri: string };
+15 -5
View File
@@ -136,16 +136,24 @@ export interface GenerateSqlQueries {
export const Telemetry = (options: { enabled?: boolean }) =>
SetMetadata(MetadataKey.TelemetryEnabled, options?.enabled ?? true);
/** Decorator to enable versioning/tracking of generated Sql */
/**
Decorator to enable versioning/tracking of generated Sql
*/
export const GenerateSql = (...options: GenerateSqlQueries[]) => SetMetadata(GENERATE_SQL_KEY, options);
export type EventConfig = {
name: EmitEvent;
/** handle socket.io server events as well */
/**
handle socket.io server events as well
*/
server?: boolean;
/** lower value has higher priority, defaults to 0 */
/**
lower value has higher priority, defaults to 0
*/
priority?: number;
/** register events for these workers, defaults to all workers */
/**
register events for these workers, defaults to all workers
*/
workers?: ImmichWorker[];
};
export const OnEvent = (config: EventConfig) => SetMetadata(MetadataKey.EventConfig, config);
@@ -183,7 +191,9 @@ type HistoryEntry = {
};
type DeprecatedOptions = {
/** replacement operationId */
/**
replacement operationId
*/
replacementId?: string;
};
+9 -3
View File
@@ -1,7 +1,9 @@
import { createZodDto } from 'nestjs-zod';
import z from 'zod';
/** @deprecated Use `BulkIdResponseDto` instead */
/**
@deprecated Use `BulkIdResponseDto` instead
*/
export enum AssetIdErrorReason {
DUPLICATE = 'duplicate',
NO_PERMISSION = 'no_permission',
@@ -13,7 +15,9 @@ const AssetIdErrorReasonSchema = z
.describe('Error reason if failed')
.meta({ id: 'AssetIdErrorReason' });
/** @deprecated Use `BulkIdResponseDto` instead */
/**
@deprecated Use `BulkIdResponseDto` instead
*/
const AssetIdsResponseSchema = z
.object({
assetId: z.uuidv4().describe('Asset ID'),
@@ -50,7 +54,9 @@ const BulkIdResponseSchema = z
})
.meta({ id: 'BulkIdResponseDto' });
/** @deprecated Use `BulkIdResponseDto` instead */
/**
@deprecated Use `BulkIdResponseDto` instead
*/
export class AssetIdsResponseDto extends createZodDto(AssetIdsResponseSchema) {}
export class BulkIdsDto extends createZodDto(BulkIdsSchema) {}
export class BulkIdResponseDto extends createZodDto(BulkIdResponseSchema) {}
+3 -1
View File
@@ -40,7 +40,9 @@ const AssetMediaBaseSchema = z.object({
fileModifiedAt: isoDatetimeToDate.describe('File modification date'),
duration: z.coerce.number().int().min(0).optional().describe('Duration in milliseconds (for videos)'),
filename: z.string().optional().describe('Filename'),
/** The properties below are added to correctly generate the API docs and client SDKs. Validation should be handled in the controller. */
/**
The properties below are added to correctly generate the API docs and client SDKs. Validation should be handled in the controller.
*/
[UploadFieldName.ASSET_DATA]: z.any().describe('Asset file data').meta({ type: 'string', format: 'binary' }),
});
+3 -1
View File
@@ -23,7 +23,9 @@ import {
} from 'src/enum';
import z from 'zod';
/** Coerces 'true'/'false' strings to boolean, but also allows booleans. */
/**
Coerces 'true'/'false' strings to boolean, but also allows booleans.
*/
const configBool = z
.preprocess((val) => {
if (val === 'true') {
+78 -26
View File
@@ -45,9 +45,13 @@ export enum AssetType {
export const AssetTypeSchema = z.enum(AssetType).describe('Asset type').meta({ id: 'AssetTypeEnum' });
export enum ChecksumAlgorithm {
/** sha1 checksum of the whole file contents */
/**
sha1 checksum of the whole file contents
*/
sha1File = 'sha1',
/** sha1 checksum of "path:" plus the file path, currently used in external libraries, deprecated */
/**
sha1 checksum of "path:" plus the file path, currently used in external libraries, deprecated
*/
sha1Path = 'sha1-path',
}
@@ -85,7 +89,9 @@ export enum AssetOrderBy {
export const AssetOrderBySchema = z.enum(AssetOrderBy).describe('Asset sorting property').meta({ id: 'AssetOrderBy' });
export enum MemoryType {
/** pictures taken on this day X years ago */
/**
pictures taken on this day X years ago
*/
OnThisDay = 'on_this_day',
}
@@ -95,7 +101,9 @@ export enum AssetOrderWithRandom {
// Include existing values
Asc = AssetOrder.Asc,
Desc = AssetOrder.Desc,
/** Randomly Ordered */
/**
Randomly Ordered
*/
Random = 'random',
}
@@ -642,7 +650,9 @@ export enum ExifOrientation {
Rotate270CW = 8,
}
/** ITU-T H.273 colour primaries codes. */
/**
ITU-T H.273 colour primaries codes.
*/
export enum ColorPrimaries {
Reserved = 0,
Bt709 = 1,
@@ -659,7 +669,9 @@ export enum ColorPrimaries {
Ebu3213 = 22,
}
/** ITU-T H.273 transfer characteristics codes. */
/**
ITU-T H.273 transfer characteristics codes.
*/
export enum ColorTransfer {
Reserved = 0,
Bt709 = 1,
@@ -681,7 +693,9 @@ export enum ColorTransfer {
AribStdB67 = 18,
}
/** ITU-T H.273 matrix coefficients codes. */
/**
ITU-T H.273 matrix coefficients codes.
*/
export enum ColorMatrix {
Gbr = 0,
Bt709 = 1,
@@ -700,7 +714,9 @@ export enum ColorMatrix {
Ictcp = 14,
}
/** H.264 `profile_idc` values. */
/**
H.264 `profile_idc` values.
*/
// H.264 has a few profiles that have the same value but different names, included so lookup by name works
export enum H264Profile {
ConstrainedBaseline = 66,
@@ -718,7 +734,9 @@ export enum H264Profile {
High444Predictive = 244,
}
/** HEVC `profile_idc` values. */
/**
HEVC `profile_idc` values.
*/
export enum HevcProfile {
Main = 1,
Main10 = 2,
@@ -726,14 +744,18 @@ export enum HevcProfile {
Rext = 4,
}
/** AV1 `seq_profile` values. */
/**
AV1 `seq_profile` values.
*/
export enum Av1Profile {
Main = 0,
High = 1,
Professional = 2,
}
/** MPEG-4 Audio Object Type values for AAC. */
/**
MPEG-4 Audio Object Type values for AAC.
*/
export enum AacProfile {
Main = 1,
Lc = 2,
@@ -746,7 +768,9 @@ export enum AacProfile {
XheAac = 42,
}
/** Dolby Vision bitstream profile numbers from the DOVI configuration record. */
/**
Dolby Vision bitstream profile numbers from the DOVI configuration record.
*/
export enum DvProfile {
Dvhe03 = 3,
Dvhe04 = 4,
@@ -922,13 +946,21 @@ export const JobNameSchema = z.enum(JobName).describe('Job name').meta({ id: 'Jo
export enum QueueCommand {
Start = 'start',
/** @deprecated Use `updateQueue` instead */
/**
@deprecated Use `updateQueue` instead
*/
Pause = 'pause',
/** @deprecated Use `updateQueue` instead */
/**
@deprecated Use `updateQueue` instead
*/
Resume = 'resume',
/** @deprecated Use `emptyQueue` instead */
/**
@deprecated Use `emptyQueue` instead
*/
Empty = 'empty',
/** @deprecated Use `emptyQueue` instead */
/**
@deprecated Use `emptyQueue` instead
*/
ClearFailed = 'clear-failed',
}
@@ -993,11 +1025,15 @@ export enum SyncRequestType {
AlbumsV2 = 'AlbumsV2',
AlbumUsersV1 = 'AlbumUsersV1',
AlbumToAssetsV1 = 'AlbumToAssetsV1',
/** @deprecated */
/**
@deprecated
*/
AlbumAssetsV1 = 'AlbumAssetsV1',
AlbumAssetsV2 = 'AlbumAssetsV2',
AlbumAssetExifsV1 = 'AlbumAssetExifsV1',
/** @deprecated */
/**
@deprecated
*/
AssetsV1 = 'AssetsV1',
AssetsV2 = 'AssetsV2',
AssetExifsV1 = 'AssetExifsV1',
@@ -1008,7 +1044,9 @@ export enum SyncRequestType {
MemoriesV1 = 'MemoriesV1',
MemoryToAssetsV1 = 'MemoryToAssetsV1',
PartnersV1 = 'PartnersV1',
/** @deprecated */
/**
@deprecated
*/
PartnerAssetsV1 = 'PartnerAssetsV1',
PartnerAssetsV2 = 'PartnerAssetsV2',
PartnerAssetExifsV1 = 'PartnerAssetExifsV1',
@@ -1016,7 +1054,9 @@ export enum SyncRequestType {
StacksV1 = 'StacksV1',
UsersV1 = 'UsersV1',
PeopleV1 = 'PeopleV1',
/** @deprecated */
/**
@deprecated
*/
AssetFacesV1 = 'AssetFacesV1',
AssetFacesV2 = 'AssetFacesV2',
UserMetadataV1 = 'UserMetadataV1',
@@ -1033,7 +1073,9 @@ export enum SyncEntityType {
UserV1 = 'UserV1',
UserDeleteV1 = 'UserDeleteV1',
/** @deprecated */
/**
@deprecated
*/
AssetV1 = 'AssetV1',
AssetV2 = 'AssetV2',
AssetDeleteV1 = 'AssetDeleteV1',
@@ -1048,10 +1090,14 @@ export enum SyncEntityType {
PartnerV1 = 'PartnerV1',
PartnerDeleteV1 = 'PartnerDeleteV1',
/** @deprecated */
/**
@deprecated
*/
PartnerAssetV1 = 'PartnerAssetV1',
PartnerAssetV2 = 'PartnerAssetV2',
/** @deprecated */
/**
@deprecated
*/
PartnerAssetBackfillV1 = 'PartnerAssetBackfillV1',
PartnerAssetBackfillV2 = 'PartnerAssetBackfillV2',
PartnerAssetDeleteV1 = 'PartnerAssetDeleteV1',
@@ -1069,13 +1115,19 @@ export enum SyncEntityType {
AlbumUserBackfillV1 = 'AlbumUserBackfillV1',
AlbumUserDeleteV1 = 'AlbumUserDeleteV1',
/** @deprecated */
/**
@deprecated
*/
AlbumAssetCreateV1 = 'AlbumAssetCreateV1',
AlbumAssetCreateV2 = 'AlbumAssetCreateV2',
/** @deprecated */
/**
@deprecated
*/
AlbumAssetUpdateV1 = 'AlbumAssetUpdateV1',
AlbumAssetUpdateV2 = 'AlbumAssetUpdateV2',
/** @deprecated */
/**
@deprecated
*/
AlbumAssetBackfillV1 = 'AlbumAssetBackfillV1',
AlbumAssetBackfillV2 = 'AlbumAssetBackfillV2',
AlbumAssetExifCreateV1 = 'AlbumAssetExifCreateV1',
+3 -1
View File
@@ -25,7 +25,9 @@ export type AuthenticatedOptions = AuthorizedRoute | PublicRoute;
type ReflectorTarget = Parameters<Reflector['get']>[1];
/** Resolves the `@Authenticated()` options of a route handler, with the defaults applied. */
/**
Resolves the `@Authenticated()` options of a route handler, with the defaults applied.
*/
export const getAuthenticatedOptions = (reflector: Reflector, target: ReflectorTarget) => {
const options = reflector.getAllAndOverride<AuthenticatedOptions | undefined>(MetadataKey.AuthRoute, [target]);
return options && { sharedLink: false, admin: false, public: false, setup: false, ...options };
+21 -7
View File
@@ -56,15 +56,25 @@ type EventMap = {
AssetDeleteAll: [{ assetIds: string[]; userId: string }];
AssetRestoreAll: [{ assetIds: string[]; userId: string }];
/** a worker receives a job and emits this event to run it */
/**
a worker receives a job and emits this event to run it
*/
JobRun: [QueueName, JobItem];
/** job pre-hook */
/**
job pre-hook
*/
JobStart: [QueueName, JobItem];
/** job post-hook */
/**
job post-hook
*/
JobComplete: [QueueName, JobItem];
/** job finishes without error */
/**
job finishes without error
*/
JobSuccess: [JobSuccessEvent];
/** job finishes with error */
/**
job finishes with error
*/
JobError: [JobErrorEvent];
// queue events
@@ -84,9 +94,13 @@ type EventMap = {
// user events
UserSignup: [{ notify: boolean; id: string; password?: string }];
UserCreate: [UserEvent];
/** user is soft deleted */
/**
user is soft deleted
*/
UserTrash: [UserEvent];
/** user is permanently deleted */
/**
user is permanently deleted
*/
UserDelete: [UserEvent];
UserRestore: [UserEvent];
+3 -1
View File
@@ -287,7 +287,9 @@ export class JobRepository {
return this.moduleRef.get<Queue>(getQueueToken(queue), { strict: false });
}
/** @deprecated */
/**
@deprecated
*/
// todo: remove this when asset notifications no longer need it.
public async removeJob(name: JobName, jobID: string): Promise<void> {
const existingJob = await this.getQueue(this.getQueueName(name)).getJob(jobID);
+3 -1
View File
@@ -464,7 +464,9 @@ export class MediaRepository {
return value ? ((enumObj[pascalCase(value)] as Extract<E[keyof E], number> | undefined) ?? null) : null;
}
/** Parse a rational like "60000/1001" or "1/600" into `{ num, den }`. */
/**
Parse a rational like "60000/1001" or "1/600" into `{ num, den }`.
*/
private parseRational(value: string | undefined): { num: number; den: number } | null {
if (value) {
const [num, den = 1] = value.split('/').map(Number);
+3 -1
View File
@@ -135,7 +135,9 @@ export type AssetSearchBuilderOptions = Omit<AssetSearchOptions, 'orderDirection
export interface AssetSearchBuilderV3Options {
filter?: SearchFilter;
/** Server-derived ownership scope. Never client-controlled. */
/**
Server-derived ownership scope. Never client-controlled.
*/
userIds?: string[];
withExif?: boolean;
withFaces?: boolean;
+9 -3
View File
@@ -45,15 +45,21 @@ export class MemoryTable {
@Column({ type: 'jsonb' })
data!: Record<string, unknown>;
/** unless set to true, will be automatically deleted in the future */
/**
unless set to true, will be automatically deleted in the future
*/
@Column({ type: 'boolean', default: false })
isSaved!: Generated<boolean>;
/** memories are sorted in ascending order by this value */
/**
memories are sorted in ascending order by this value
*/
@Column({ type: 'timestamp with time zone' })
memoryAt!: Timestamp;
/** when the user last viewed the memory */
/**
when the user last viewed the memory
*/
@Column({ type: 'timestamp with time zone', nullable: true })
seenAt!: Timestamp | null;
+3 -1
View File
@@ -48,7 +48,9 @@ export type ValidateRequest = {
metadata: {
sharedLinkRoute: boolean;
adminRoute: boolean;
/** `false` explicitly means no permission is required, which otherwise defaults to `all` */
/**
`false` explicitly means no permission is required, which otherwise defaults to `all`
*/
permission?: Permission | false;
uri: string;
};
+3 -1
View File
@@ -42,7 +42,9 @@ import { Tasks } from 'src/utils/tasks';
const POSTGRES_INT_MAX = 2_147_483_647;
const POSTGRES_INT_MIN = -2_147_483_648;
/** look for a date from these tags (in order) */
/**
look for a date from these tags (in order)
*/
const EXIF_DATE_TAGS: Array<keyof ImmichTags> = [
'SubSecDateTimeOriginal',
'SubSecCreateDate',
+30 -10
View File
@@ -105,19 +105,33 @@ export interface AudioStreamInfo {
bitrate: number;
}
/** Packet-derived video data needed for accurate HLS playlists. */
/**
Packet-derived video data needed for accurate HLS playlists.
*/
export interface VideoPacketInfo {
/** Sum of source packet duration across all packets (includes discard). */
/**
Sum of source packet duration across all packets (includes discard).
*/
totalDuration: number;
/** Post-discard packet count. */
/**
Post-discard packet count.
*/
packetCount: number;
/** Output CFR frame count at `packetCount / format.duration`. */
/**
Output CFR frame count at `packetCount / format.duration`.
*/
outputFrames: number;
/** All keyframe PTS in source ticks, including pre-roll discard keyframes. */
/**
All keyframe PTS in source ticks, including pre-roll discard keyframes.
*/
keyframePts: number[];
/** Cumulative packet duration through each keyframe, inclusive. */
/**
Cumulative packet duration through each keyframe, inclusive.
*/
keyframeAccDuration: number[];
/** Each keyframe's own packet duration (needed for VFR). */
/**
Each keyframe's own packet duration (needed for VFR).
*/
keyframeOwnDuration: number[];
}
@@ -210,7 +224,9 @@ export interface IBaseJob {
}
export interface IDelayedJob extends IBaseJob {
/** The minimum time to wait to execute this job, in milliseconds. */
/**
The minimum time to wait to execute this job, in milliseconds.
*/
delay?: number;
}
@@ -452,7 +468,9 @@ export interface ExtensionVersion {
export interface ImmichFile extends Express.Multer.File {
uuid: string;
/** sha1 hash of file */
/**
sha1 hash of file
*/
checksum: Buffer;
}
@@ -522,7 +540,9 @@ export type SystemFlags = { mountChecks: Record<StorageFolder, boolean> };
export type MaintenanceModeState =
{ isMaintenanceMode: true; secret: string; action?: SetMaintenanceModeDto } | { isMaintenanceMode: false };
export type MemoriesState = {
/** memories have already been created through this date */
/**
memories have already been created through this date
*/
lastOnThisDayDate: string;
};
export type MediaLocation = { location: string };
+3 -1
View File
@@ -113,7 +113,9 @@ export const removeAssets = async (
export type PartnerIdOptions = {
userId: string;
repository: PartnerRepository;
/** only include partners with `inTimeline: true` */
/**
only include partners with `inTimeline: true`
*/
timelineEnabled?: boolean;
};
export const getMyPartnerIds = async ({ userId, repository, timelineEnabled }: PartnerIdOptions) => {
+3 -1
View File
@@ -391,7 +391,9 @@ export function withEdits(eb: ExpressionBuilder<DB, 'asset'>): AliasedEditAction
}
const joinDeduplicationPlugin = new DeduplicateJoinsPlugin();
/** TODO: This should only be used for search-related queries, not as a general purpose query builder */
/**
TODO: This should only be used for search-related queries, not as a general purpose query builder
*/
export function searchAssetBuilderLegacy(kysely: Kysely<DB>, options: AssetSearchBuilderOptions) {
options.withDeleted ||= !!(options.trashedAfter || options.trashedBefore || options.isOffline);
+3 -1
View File
@@ -164,7 +164,9 @@ export const mimeTypes = {
transparentCapableExtensions.has(getFilenameExtension(filename).toLowerCase()),
isRaw: (filename: string) => isType(filename, raw),
lookup,
/** return an extension (including a leading `.`) for a mime-type */
/**
return an extension (including a leading `.`) for a mime-type
*/
toExtension,
assetType: (filename: string) => {
const contentType = lookup(filename);
+3 -1
View File
@@ -12,7 +12,9 @@ export const triggerMap: Record<WorkflowTrigger, WorkflowType[]> = {
export const getWorkflowTriggers = () =>
Object.entries(triggerMap).map(([trigger, types]) => ({ trigger: trigger as WorkflowTrigger, types }));
/** some types extend other types and have implied compatibility */
/**
some types extend other types and have implied compatibility
*/
const inferredMap: Record<WorkflowType, WorkflowType[]> = {
[WorkflowType.AssetV1]: [],
// [WorkflowType.AssetPersonV1]: [WorkflowType.AssetV1],
+3 -1
View File
@@ -48,7 +48,9 @@ const probeStubDefault: VideoInfo = {
audioStreams: probeStubDefaultAudioStream,
};
/** Fixtures in the shape `mediaRepository.probe()` returns (arrays of streams, raw ffprobe format). */
/**
Fixtures in the shape `mediaRepository.probe()` returns (arrays of streams, raw ffprobe format).
*/
export const videoInfoStub = {
noVideoStreams: Object.freeze<VideoInfo>({ ...probeStubDefault, videoStreams: [] }),
noAudioStreams: Object.freeze<VideoInfo>({ ...probeStubDefault, audioStreams: [] }),
-2
View File
@@ -541,10 +541,8 @@ export const mockDuplex =
if (error) {
duplex.destroy(error as Error);
} else if (exitCode === 0) {
/* eslint-disable unicorn/prefer-single-call */
duplex.push(stdout);
duplex.push(null);
/* eslint-enable unicorn/prefer-single-call */
} else {
duplex.destroy(new Error(`${command} non-zero exit code (${exitCode})\n${stderr}`));
}
+1 -1
View File
@@ -98,7 +98,7 @@
"eslint-plugin-better-tailwindcss": "^4.5.0",
"eslint-plugin-compat": "^7.0.0",
"eslint-plugin-svelte": "^3.12.4",
"eslint-plugin-unicorn": "^72.0.0",
"eslint-plugin-unicorn": "^73.0.0",
"factory.ts": "^1.4.1",
"globals": "^17.0.0",
"happy-dom": "^20.0.0",
+3 -1
View File
@@ -1,4 +1,6 @@
/** Focus the given element when it is mounted. */
/**
Focus the given element when it is mounted.
*/
export const initInput = (element: HTMLInputElement) => {
element.focus();
};
@@ -55,7 +55,9 @@
}
const groupOptions: AlbumGroupOption = {
/** No grouping */
/**
No grouping
*/
[AlbumGroupBy.None]: (order, albums): AlbumGroup[] => {
return [
{
@@ -66,7 +68,9 @@
];
},
/** Group by year */
/**
Group by year
*/
[AlbumGroupBy.Year]: (order, albums): AlbumGroup[] => {
const unknownYear = $t('unknown_year');
const useStartDate = userSettings.sortBy === AlbumSortBy.OldestPhoto;
@@ -92,7 +96,9 @@
}));
},
/** Group by owner */
/**
Group by owner
*/
[AlbumGroupBy.Owner]: (order, albums): AlbumGroup[] => {
const currentUserId = authManager.user.id;
const groupedByOwnerIds = groupBy(albums, (album) => album.albumUsers[0].user.id);
@@ -108,7 +108,9 @@
updateOcrBoxes(ocrManager.showOverlay, ocrManager.data);
});
/** Use updateOnly=true on zoom, pan, or resize. */
/**
Use updateOnly=true on zoom, pan, or resize.
*/
const updateOcrBoxes = (showOverlay: boolean, ocrData: OcrBoundingBox[], updateOnly = false) => {
if (!viewer || !viewer.state.textureData || !viewer.getPlugin(MarkersPlugin)) {
return;
+36 -12
View File
@@ -11,30 +11,54 @@
import { fade, fly } from 'svelte/transition';
interface Props {
/** Offset from the top of the timeline (e.g., for headers) */
/**
Offset from the top of the timeline (e.g., for headers)
*/
timelineTopOffset?: number;
/** Offset from the bottom of the timeline (e.g., for footers) */
/**
Offset from the bottom of the timeline (e.g., for footers)
*/
timelineBottomOffset?: number;
/** Total height of the scrubber component */
/**
Total height of the scrubber component
*/
height?: number;
/** Timeline manager instance that controls the timeline state */
/**
Timeline manager instance that controls the timeline state
*/
timelineManager: TimelineManager;
/** Overall scroll percentage through the entire timeline (0-1), used when no specific month is targeted */
/**
Overall scroll percentage through the entire timeline (0-1), used when no specific month is targeted
*/
timelineScrollPercent?: number;
/** The percentage of scroll through the month that is currently intersecting the top boundary of the viewport */
/**
The percentage of scroll through the month that is currently intersecting the top boundary of the viewport
*/
viewportTopMonthScrollPercent?: number;
/** The year/month of the timeline month at the top of the viewport */
/**
The year/month of the timeline month at the top of the viewport
*/
viewportTopMonth?: ViewportTopMonth;
/** Width of the scrubber component in pixels (bindable for parent component margin adjustments) */
/**
Width of the scrubber component in pixels (bindable for parent component margin adjustments)
*/
scrubberWidth?: number;
/** Callback fired when user interacts with the scrubber to navigate */
/**
Callback fired when user interacts with the scrubber to navigate
*/
onScrub?: ScrubberListener;
/** Callback fired when keyboard events occur on the scrubber */
/**
Callback fired when keyboard events occur on the scrubber
*/
onScrubKeyDown?: (event: KeyboardEvent, element: HTMLElement) => void;
/** Callback fired when scrubbing starts */
/**
Callback fired when scrubbing starts
*/
startScrub?: ScrubberListener;
/** Callback fired when scrubbing stops */
/**
Callback fired when scrubbing stops
*/
stopScrub?: ScrubberListener;
}
+18 -6
View File
@@ -223,34 +223,46 @@ export const stringToSortOrder = (order: string) => {
};
const sortOptions: AlbumSortOption = {
/** Sort by album title */
/**
Sort by album title
*/
[AlbumSortBy.Title]: (order, albums) => {
const sortSign = order === SortOrder.Desc ? -1 : 1;
return albums.slice().sort((a, b) => a.albumName.localeCompare(b.albumName, get(locale)) * sortSign);
},
/** Sort by asset count */
/**
Sort by asset count
*/
[AlbumSortBy.ItemCount]: (order, albums) => {
return orderBy(albums, 'assetCount', [order]);
},
/** Sort by last modified */
/**
Sort by last modified
*/
[AlbumSortBy.DateModified]: (order, albums) => {
return orderBy(albums, [({ updatedAt }) => new Date(updatedAt)], [order]);
},
/** Sort by creation date */
/**
Sort by creation date
*/
[AlbumSortBy.DateCreated]: (order, albums) => {
return orderBy(albums, [({ createdAt }) => new Date(createdAt)], [order]);
},
/** Sort by the most recent photo date */
/**
Sort by the most recent photo date
*/
[AlbumSortBy.MostRecentPhoto]: (order, albums) => {
albums = orderBy(albums, [({ endDate }) => (endDate ? new Date(endDate) : '')], [order]);
return albums.sort(sortUnknownYearAlbums);
},
/** Sort by the oldest photo date */
/**
Sort by the oldest photo date
*/
[AlbumSortBy.OldestPhoto]: (order, albums) => {
albums = orderBy(albums, [({ startDate }) => (startDate ? new Date(startDate) : '')], [order]);
return albums.sort(sortUnknownYearAlbums);
+6 -2
View File
@@ -6,9 +6,13 @@ import { handleError } from '$lib/utils/handle-error';
* and allowing operations to check if they're still valid.
*/
export class InvocationTracker {
/** Counter for the number of invocations that have been started */
/**
Counter for the number of invocations that have been started
*/
invocationsStarted = 0;
/** Counter for the number of invocations that have been completed */
/**
Counter for the number of invocations that have been completed
*/
invocationsEnded = 0;
constructor() {}
+3 -1
View File
@@ -92,7 +92,9 @@ interface AssetGridRoute extends Route {
type ImmichRoute = AssetRoute | AssetGridRoute;
type NavOptions = {
/* navigate even if url is the same */
/*
navigate even if url is the same
*/
forceNavigate?: boolean | undefined;
replaceState?: boolean | undefined;
noScroll?: boolean | undefined;
+3 -1
View File
@@ -1,7 +1,9 @@
import type { ParamMatcher } from '@sveltejs/kit';
import { UUID_REGEX } from '$lib/constants';
/* Returns true if the given param matches UUID format */
/*
Returns true if the given param matches UUID format
*/
export const match: ParamMatcher = (param: string) => {
return UUID_REGEX.test(param);
};
@@ -33,7 +33,9 @@
}
const groupOptions: PlacesGroupOption = {
/** No grouping */
/**
No grouping
*/
[PlacesGroupBy.None]: (places): PlacesGroup[] => {
return [
{
@@ -44,7 +46,9 @@
];
},
/** Group by year */
/**
Group by year
*/
[PlacesGroupBy.Country]: (places): PlacesGroup[] => {
const unknownCountry = $t('unknown_country');