From bfffc3cc314bd7bc9d62b21cdd145a663d73c4c2 Mon Sep 17 00:00:00 2001 From: Mike Huang Date: Sun, 12 Nov 2023 12:42:56 +0800 Subject: [PATCH] fix: linting --- src/app/app.component.ts | 29 ++- .../blog-archives-posts-resolve.ts | 6 +- .../blog-archives/blog-archives.component.ts | 2 +- .../blog-categories-posts-resolve.ts | 4 +- .../blog-categories-resolve.ts | 3 +- .../blog-post/blog-content-resolve.ts | 4 +- .../blog-post/blog-post-toc.component.ts | 28 +-- .../blog-post/blog-post.component.ts | 2 +- .../blog/blog-tags/blog-tags-posts-resolve.ts | 7 +- src/app/blog/blog-tags/blog-tags-resolve.ts | 6 +- src/app/layout/layout.component.ts | 2 +- .../blog-post-subtitle.component.ts | 6 +- src/app/site-common/pagination.component.ts | 2 +- src/app/site-common/platform.service.ts | 2 +- src/app/site-common/route-utils.ts | 2 + src/app/site-common/search-posts.ts | 168 ++++++++++++------ .../trailing-slash-url-serializer.ts | 2 +- 17 files changed, 164 insertions(+), 111 deletions(-) diff --git a/src/app/app.component.ts b/src/app/app.component.ts index 6fadc82cde..8881cbb558 100644 --- a/src/app/app.component.ts +++ b/src/app/app.component.ts @@ -1,4 +1,9 @@ -import { ChangeDetectionStrategy, Component, inject } from '@angular/core'; +import { + ChangeDetectionStrategy, + Component, + inject, + OnInit, +} from '@angular/core'; import { NavigationEnd, NavigationStart, Router } from '@angular/router'; import { PlatformService } from 'src/app/site-common/platform.service'; import { environment } from '../environments/environment'; @@ -7,18 +12,20 @@ import { SiteMetaService } from './site-common/site-meta.service'; import { TrackService } from './site-common/track.service'; import { filter, pairwise, startWith } from 'rxjs'; -declare let gtag: Function; +declare const gtag: ( + command: string, + action: string, + config: { page_path: string } +) => void; @Component({ standalone: true, selector: 'app-root', - imports: [ - LayoutComponent, - ], + imports: [LayoutComponent], template: ``, changeDetection: ChangeDetectionStrategy.OnPush, }) -export class AppComponent { +export class AppComponent implements OnInit { private router = inject(Router); private platformService = inject(PlatformService); private siteMetaService = inject(SiteMetaService); @@ -42,10 +49,14 @@ export class AppComponent { startWith(null), pairwise() ) - .subscribe((events: [any, any]) => { + .subscribe((events) => { if (!this.platformService.isServer && environment.production) { - this.trackService.sendTrack(events[0]?.url || ''); - gtag('event', 'page_view', { page_path: events[1].url }); + this.trackService.sendTrack( + (events[0] as NavigationEnd | null)?.url || '' + ); + gtag('event', 'page_view', { + page_path: (events[1] as NavigationEnd | null)?.url || '', + }); } }); } diff --git a/src/app/blog/blog-archives/blog-archives-posts-resolve.ts b/src/app/blog/blog-archives/blog-archives-posts-resolve.ts index f9b374e771..f9538d2819 100644 --- a/src/app/blog/blog-archives/blog-archives-posts-resolve.ts +++ b/src/app/blog/blog-archives/blog-archives-posts-resolve.ts @@ -1,5 +1,4 @@ import { Injectable, inject } from '@angular/core'; -import { ActivatedRouteSnapshot, RouterStateSnapshot } from '@angular/router'; import { Observable } from 'rxjs'; import { PostMetaWithSlug } from '../../site-common/post-meta.interface'; import { SitePostService } from '../../site-common/site-post.service'; @@ -10,10 +9,7 @@ import { SitePostService } from '../../site-common/site-post.service'; export class BlogArchivesPostsResolve { private sitePostService = inject(SitePostService); - resolve( - route: ActivatedRouteSnapshot, - state: RouterStateSnapshot - ): Observable { + resolve(): Observable { return this.sitePostService.postsMetaWithSlugAndSortDesc$; } } diff --git a/src/app/blog/blog-archives/blog-archives.component.ts b/src/app/blog/blog-archives/blog-archives.component.ts index 02260f49d1..cd304dc30a 100644 --- a/src/app/blog/blog-archives/blog-archives.component.ts +++ b/src/app/blog/blog-archives/blog-archives.component.ts @@ -105,7 +105,7 @@ export class BlogArchivesComponent { return pagePosts.reduce((prev, curr) => { const year = curr.date.slice(0, 4); - let yearPosts = prev.find((item) => item.year === year); + const yearPosts = prev.find((item) => item.year === year); if (!yearPosts) { prev.push({ year, diff --git a/src/app/blog/blog-categories/blog-categories-posts-resolve.ts b/src/app/blog/blog-categories/blog-categories-posts-resolve.ts index 9a43461aa5..8657488a99 100644 --- a/src/app/blog/blog-categories/blog-categories-posts-resolve.ts +++ b/src/app/blog/blog-categories/blog-categories-posts-resolve.ts @@ -1,5 +1,5 @@ import { Injectable, inject } from '@angular/core'; -import { ActivatedRouteSnapshot, RouterStateSnapshot } from '@angular/router'; +import { ActivatedRouteSnapshot } from '@angular/router'; import { descend, prop, sortWith } from 'ramda'; import { Observable, map } from 'rxjs'; import { PostMetaWithSlug } from '../../site-common/post-meta.interface'; @@ -12,7 +12,7 @@ import { findPosts } from '../find-posts'; export class BlogCategoriesPostsResolve { private sitePostService = inject(SitePostService); - resolve(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable { + resolve(route: ActivatedRouteSnapshot): Observable { const categorySlug = route.paramMap.get('category-slug') as string; return this.sitePostService.categoriesAndPosts$ diff --git a/src/app/blog/blog-categories/blog-categories-resolve.ts b/src/app/blog/blog-categories/blog-categories-resolve.ts index 698a09183d..bfef7d9c0c 100644 --- a/src/app/blog/blog-categories/blog-categories-resolve.ts +++ b/src/app/blog/blog-categories/blog-categories-resolve.ts @@ -1,5 +1,4 @@ import { Injectable, inject } from '@angular/core'; -import { ActivatedRouteSnapshot, RouterStateSnapshot } from '@angular/router'; import { Observable } from 'rxjs'; import { PostMetaWithSlug } from '../../site-common/post-meta.interface'; import { SitePostService } from '../../site-common/site-post.service'; @@ -10,7 +9,7 @@ import { SitePostService } from '../../site-common/site-post.service'; export class BlogCategoriesResolve { private sitePostService = inject(SitePostService); - resolve(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<{ [key:string] :PostMetaWithSlug[]}> { + resolve(): Observable<{ [key:string] :PostMetaWithSlug[]}> { return this.sitePostService.categoriesAndPosts$; } } diff --git a/src/app/blog/blog-posts/blog-post/blog-content-resolve.ts b/src/app/blog/blog-posts/blog-post/blog-content-resolve.ts index 07df9d0693..27d0170a76 100644 --- a/src/app/blog/blog-posts/blog-post/blog-content-resolve.ts +++ b/src/app/blog/blog-posts/blog-post/blog-content-resolve.ts @@ -1,6 +1,6 @@ import { HttpClient } from '@angular/common/http'; import { Injectable, TransferState, inject, makeStateKey } from '@angular/core'; -import { ActivatedRouteSnapshot, RouterStateSnapshot } from '@angular/router'; +import { ActivatedRouteSnapshot } from '@angular/router'; import { Observable, catchError, map, of, tap, timeout } from 'rxjs'; import { MarkdownMeta, parseMarkdownMeta } from 'site-utils'; import { environment } from '../../../../environments/environment'; @@ -14,7 +14,7 @@ export class BlogContentResolve { private state = inject(TransferState); private platformService = inject(PlatformService); - resolve(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable { + resolve(route: ActivatedRouteSnapshot): Observable { return this.getMarkdownContent(route.paramMap.get('slug') as string); } diff --git a/src/app/blog/blog-posts/blog-post/blog-post-toc.component.ts b/src/app/blog/blog-posts/blog-post/blog-post-toc.component.ts index 67d1137bff..46d34ca5be 100644 --- a/src/app/blog/blog-posts/blog-post/blog-post-toc.component.ts +++ b/src/app/blog/blog-posts/blog-post/blog-post-toc.component.ts @@ -6,7 +6,7 @@ import { OnDestroy, TransferState, inject, - makeStateKey + makeStateKey, } from '@angular/core'; import { toSignal } from '@angular/core/rxjs-interop'; import { Observable, ReplaySubject, map, startWith, switchMap } from 'rxjs'; @@ -85,7 +85,7 @@ const HEADINGS_CACHE_KEY = makeStateKey('POST_TOC'); }`, standalone: true, imports: [], - changeDetection: ChangeDetectionStrategy.OnPush + changeDetection: ChangeDetectionStrategy.OnPush, }) export class BlogPostTocComponent implements OnDestroy { private transferState = inject(TransferState); @@ -170,7 +170,7 @@ export class BlogPostTocComponent implements OnDestroy { const containerElement = element.closest( '.mat-drawer-content.main-content' ); - let options = { + const options = { root: containerElement, rootMargin: '0px', threshold: 1.0, @@ -213,17 +213,19 @@ export class BlogPostTocComponent implements OnDestroy { } private getTocHeadings(element: HTMLElement) { - let result: any[] = []; + const result: Array<{ + text: string | null; + level: number; + element: Element | null; + active: boolean; + }> = []; element.querySelectorAll('h1,h2,h3,h4,h5,h6').forEach((head) => { - result = [ - ...result, - { - text: head.textContent, - level: +head.tagName.replace(/h(.)/i, '$1'), - element: this.platformService.isServer ? null : head, - active: false, - }, - ]; + result.push({ + text: head.textContent, + level: +head.tagName.replace(/h(.)/i, '$1'), + element: this.platformService.isServer ? null : head, + active: false, + }); }); return result; } diff --git a/src/app/blog/blog-posts/blog-post/blog-post.component.ts b/src/app/blog/blog-posts/blog-post/blog-post.component.ts index 8a5398df28..5c724f7ee2 100644 --- a/src/app/blog/blog-posts/blog-post/blog-post.component.ts +++ b/src/app/blog/blog-posts/blog-post/blog-post.component.ts @@ -13,7 +13,7 @@ import { MatDividerModule } from '@angular/material/divider'; import { MatIconModule } from '@angular/material/icon'; import { MatTooltipModule } from '@angular/material/tooltip'; import { DomSanitizer } from '@angular/platform-browser'; -import { ActivatedRoute, RouterLink } from '@angular/router'; +import { RouterLink } from '@angular/router'; import { MarkdownMeta } from 'site-utils'; import { getRouteData } from 'src/app/site-common/route-utils'; import { findMainContentContainer, scrollTo } from '../../../../utils'; diff --git a/src/app/blog/blog-tags/blog-tags-posts-resolve.ts b/src/app/blog/blog-tags/blog-tags-posts-resolve.ts index c247250ab8..2b0fec9b58 100644 --- a/src/app/blog/blog-tags/blog-tags-posts-resolve.ts +++ b/src/app/blog/blog-tags/blog-tags-posts-resolve.ts @@ -1,5 +1,5 @@ import { Injectable, inject } from '@angular/core'; -import { ActivatedRouteSnapshot, RouterStateSnapshot } from '@angular/router'; +import { ActivatedRouteSnapshot } from '@angular/router'; import { descend, prop, sortWith } from 'ramda'; import { Observable, map } from 'rxjs'; import { PostMetaWithSlug } from '../../site-common/post-meta.interface'; @@ -12,10 +12,7 @@ import { findPosts } from '../find-posts'; export class BlogTagsPostsResolve { private sitePostService = inject(SitePostService); - resolve( - route: ActivatedRouteSnapshot, - state: RouterStateSnapshot - ): Observable { + resolve(route: ActivatedRouteSnapshot): Observable { const tagSlug = route.paramMap.get('tag-slug') as string; return this.sitePostService.tagsAndPosts$.pipe( diff --git a/src/app/blog/blog-tags/blog-tags-resolve.ts b/src/app/blog/blog-tags/blog-tags-resolve.ts index 45c307d830..919fdd652d 100644 --- a/src/app/blog/blog-tags/blog-tags-resolve.ts +++ b/src/app/blog/blog-tags/blog-tags-resolve.ts @@ -1,5 +1,4 @@ import { Injectable, inject } from '@angular/core'; -import { ActivatedRouteSnapshot, RouterStateSnapshot } from '@angular/router'; import { Observable } from 'rxjs'; import { PostMetaWithSlug } from '../../site-common/post-meta.interface'; import { SitePostService } from '../../site-common/site-post.service'; @@ -10,10 +9,7 @@ import { SitePostService } from '../../site-common/site-post.service'; export class BlogTagsResolve { private sitePostService = inject(SitePostService); - resolve( - route: ActivatedRouteSnapshot, - state: RouterStateSnapshot - ): Observable<{ [key: string]: PostMetaWithSlug[] }> { + resolve(): Observable<{ [key: string]: PostMetaWithSlug[] }> { return this.sitePostService.tagsAndPosts$; } } diff --git a/src/app/layout/layout.component.ts b/src/app/layout/layout.component.ts index a99a78635c..25730ce843 100644 --- a/src/app/layout/layout.component.ts +++ b/src/app/layout/layout.component.ts @@ -166,7 +166,7 @@ export class LayoutComponent implements OnInit { ngOnInit() { this.router.events .pipe(filter((event) => event instanceof NavigationStart)) - .subscribe((url) => { + .subscribe(() => { if (this.matDrawerContent) { this.matDrawerContent.scrollTo({ top: 0, left: 0 }); this.cdr.detectChanges(); diff --git a/src/app/site-common/blog-post-subtitle.component.ts b/src/app/site-common/blog-post-subtitle.component.ts index 562403b0b7..b9fbb1c31e 100644 --- a/src/app/site-common/blog-post-subtitle.component.ts +++ b/src/app/site-common/blog-post-subtitle.component.ts @@ -1,9 +1,9 @@ -import { Component, Input, OnInit } from '@angular/core'; +import { Component, Input } from '@angular/core'; +import { MatIconModule } from '@angular/material/icon'; +import { RouterLink } from '@angular/router'; import { MarkdownMeta } from 'site-utils'; import { PostMeta } from './post-meta.interface'; import { SlugifyPipe } from './slugify.pipe'; -import { RouterLink } from '@angular/router'; -import { MatIconModule } from '@angular/material/icon'; @Component({ selector: 'app-blog-post-subtitle', diff --git a/src/app/site-common/pagination.component.ts b/src/app/site-common/pagination.component.ts index 89e90aefa5..37f0649aac 100644 --- a/src/app/site-common/pagination.component.ts +++ b/src/app/site-common/pagination.component.ts @@ -1,4 +1,4 @@ -import { ChangeDetectionStrategy, Component, Input, OnInit } from '@angular/core'; +import { ChangeDetectionStrategy, Component, Input } from '@angular/core'; import { MatIconModule } from '@angular/material/icon'; import { RouterLink } from '@angular/router'; import { MatTooltipModule } from '@angular/material/tooltip'; diff --git a/src/app/site-common/platform.service.ts b/src/app/site-common/platform.service.ts index 34fe3dc94a..503968387b 100644 --- a/src/app/site-common/platform.service.ts +++ b/src/app/site-common/platform.service.ts @@ -1,6 +1,6 @@ import { BreakpointObserver, Breakpoints } from '@angular/cdk/layout'; import { isPlatformServer } from '@angular/common'; -import { Inject, Injectable, PLATFORM_ID, inject } from '@angular/core'; +import { Injectable, PLATFORM_ID, inject } from '@angular/core'; import { toSignal } from '@angular/core/rxjs-interop'; import { map, shareReplay } from 'rxjs'; diff --git a/src/app/site-common/route-utils.ts b/src/app/site-common/route-utils.ts index 775776da29..16b30b6f95 100644 --- a/src/app/site-common/route-utils.ts +++ b/src/app/site-common/route-utils.ts @@ -8,6 +8,7 @@ export const getRouteParam = (getFn: (paramMap: ParamMap, index?: number) => const param$ = route.paramMap.pipe( map(getFn) ); + // eslint-disable-next-line @typescript-eslint/no-explicit-any return toSignal(param$, { initialValue: initialValue as any }) as Signal; }; @@ -16,5 +17,6 @@ export const getRouteData = (getFn: (data: Data, index?: number) => T, initia const data$ = route.data.pipe( map(getFn) ); + // eslint-disable-next-line @typescript-eslint/no-explicit-any return toSignal(data$, { initialValue: initialValue as any })as Signal; } diff --git a/src/app/site-common/search-posts.ts b/src/app/site-common/search-posts.ts index 46d708934e..0f17a2e3ae 100644 --- a/src/app/site-common/search-posts.ts +++ b/src/app/site-common/search-posts.ts @@ -3,46 +3,60 @@ import { PostMetaWithSlug } from './post-meta.interface'; const searchFieldMapping = { tag: '標籤', - category: '分類' -} + category: '分類', +}; -const getSearchFieldName = (fieldName: string) => { - return (searchFieldMapping as any)[fieldName] || ''; -} - -export const searchPostsByDateRange = (start?: Date, end?: Date) => (posts: PostMetaWithSlug[]) => { - return posts.filter(post => { - const postDate = new Date(post.date); - return (start ? postDate >= new Date(start) : true) && (end ? postDate <= new Date(end) : true); - }); -} +const getSearchFieldName = (fieldName: '' | 'tag' | 'category') => { + if (!fieldName) { + return ''; + } + return searchFieldMapping[fieldName] || ''; +}; -export const searchPosts = (posts: PostMetaWithSlug[], keywordString: string) => { +export const searchPostsByDateRange = + (start?: Date, end?: Date) => (posts: PostMetaWithSlug[]) => { + return posts.filter((post) => { + const postDate = new Date(post.date); + return ( + (start ? postDate >= new Date(start) : true) && + (end ? postDate <= new Date(end) : true) + ); + }); + }; +export const searchPosts = ( + posts: PostMetaWithSlug[], + keywordString: string +) => { if (!keywordString) { - return posts.map(post => ({ + return posts.map((post) => ({ type: '文章', text: post.title, date: post.date, link: `/blog/${post.date.slice(0, 10).replace(/-/g, '/')}/${post.slug}`, - toString: () => '' + toString: () => '', })); } const filterPostBy = (keyword: string) => (post: PostMetaWithSlug) => - post.title.toLowerCase().indexOf(keyword.toLowerCase()) >= 0 - || post.summary.toLowerCase().indexOf(keyword.toLowerCase()) >= 0; + post.title.toLowerCase().indexOf(keyword.toLowerCase()) >= 0 || + post.summary.toLowerCase().indexOf(keyword.toLowerCase()) >= 0; - let result = []; + const result: Array<{ + type: string; + text: string; + date: string; + link: string; + }> = []; let searchType = 'any'; - let searchField = ''; + let searchField: 'tag' | 'category' | '' = ''; let searchFrom = ''; let keyword = ''; const chunks = keywordString.split(':'); if (chunks.length > 2) { searchType = 'post'; - searchField = chunks[0]; + searchField = chunks[0] as 'tag' | 'category' | ''; searchFrom = chunks[1]; keyword = chunks[2]; } else if (chunks.length > 1) { @@ -54,61 +68,97 @@ export const searchPosts = (posts: PostMetaWithSlug[], keywordString: string) => if (searchType === 'any' || searchType === 'post') { const relatePosts = posts - .filter(post => { + .filter((post) => { const filterKeywordFn = filterPostBy(keyword); if (searchField === 'category') { - return filterKeywordFn(post) && !!(post.categories || []).find((category) => category.toLowerCase().indexOf(searchFrom.toLowerCase()) >= 0); + return ( + filterKeywordFn(post) && + !!(post.categories || []).find( + (category) => + category.toLowerCase().indexOf(searchFrom.toLowerCase()) >= 0 + ) + ); } else if (searchField === 'tag') { - return filterKeywordFn(post) && !!(post.tags || []).find((tag) => tag.toLowerCase().indexOf(searchFrom.toLowerCase()) >= 0); + return ( + filterKeywordFn(post) && + !!(post.tags || []).find( + (tag) => tag.toLowerCase().indexOf(searchFrom.toLowerCase()) >= 0 + ) + ); } else { return filterKeywordFn(post); } }) - .sort((postA, postB) => - postA.title.toLowerCase().indexOf(keyword.toLowerCase()) - postB.title.toLowerCase().indexOf(keyword.toLowerCase())) - result.push(...relatePosts.map(post => ({ - type: `${getSearchFieldName(searchField)}${searchField ? ':' : ''}${searchFrom}${searchFrom ? ';' : ''}文章`, - text: post.title, - date: post.date, - link: `/blog/${post.date.slice(0, 10).replace(/-/g, '/')}/${post.slug}`, - toString: () => '' - }))); + .sort( + (postA, postB) => + postA.title.toLowerCase().indexOf(keyword.toLowerCase()) - + postB.title.toLowerCase().indexOf(keyword.toLowerCase()) + ); + result.push( + ...relatePosts.map((post) => ({ + type: `${getSearchFieldName(searchField)}${ + searchField ? ':' : '' + }${searchFrom}${searchFrom ? ';' : ''}文章`, + text: post.title, + date: post.date, + link: `/blog/${post.date.slice(0, 10).replace(/-/g, '/')}/${post.slug}`, + toString: () => '', + })) + ); } if (searchType === 'any' || searchType === 'category') { - const allCategories = posts - .reduce((curr, post) => ([...new Set([...curr, ...post.categories || []])]), [] as string[]) + const allCategories = posts.reduce( + (curr, post) => [...new Set([...curr, ...(post.categories || [])])], + [] as string[] + ); - const relatedCategories = allCategories.filter((category: string) => - category.toLowerCase().indexOf(keyword.toLowerCase()) >= 0 - ) - .sort((categoryA, categoryB) => - categoryA.toLowerCase().indexOf(keyword.toLowerCase()) - categoryB.toLowerCase().indexOf(keyword.toLowerCase())) - result.push(...relatedCategories.map(category => ({ - type: '分類', - text: category, - date: '', - link: `/blog/categories/${slugify(category)}`, - toString: () => '' - }))); + const relatedCategories = allCategories + .filter( + (category: string) => + category.toLowerCase().indexOf(keyword.toLowerCase()) >= 0 + ) + .sort( + (categoryA, categoryB) => + categoryA.toLowerCase().indexOf(keyword.toLowerCase()) - + categoryB.toLowerCase().indexOf(keyword.toLowerCase()) + ); + result.push( + ...relatedCategories.map((category) => ({ + type: '分類', + text: category, + date: '', + link: `/blog/categories/${slugify(category)}`, + toString: () => '', + })) + ); } if (searchType === 'any' || searchType === 'tag') { - const allTags = posts - .reduce((curr, post) => ([...new Set([...curr, ...post.tags || []])]), [] as string[]) + const allTags = posts.reduce( + (curr, post) => [...new Set([...curr, ...(post.tags || [])])], + [] as string[] + ); const relatedTags = allTags - .filter((tag: string) => tag.toLowerCase().indexOf(keyword.toLowerCase()) >= 0) - .sort((tagA, tagB) => - tagA.toLowerCase().indexOf(keyword.toLowerCase()) - tagB.toLowerCase().indexOf(keyword.toLowerCase())) - result.push(...relatedTags.map(tag => ({ - type: '標籤', - text: tag, - date: '', - link: `/blog/tags/${slugify(tag)}`, - toString: () => '' - }))); + .filter( + (tag: string) => tag.toLowerCase().indexOf(keyword.toLowerCase()) >= 0 + ) + .sort( + (tagA, tagB) => + tagA.toLowerCase().indexOf(keyword.toLowerCase()) - + tagB.toLowerCase().indexOf(keyword.toLowerCase()) + ); + result.push( + ...relatedTags.map((tag) => ({ + type: '標籤', + text: tag, + date: '', + link: `/blog/tags/${slugify(tag)}`, + toString: () => '', + })) + ); } return result; -} +}; diff --git a/src/app/site-common/trailing-slash-url-serializer.ts b/src/app/site-common/trailing-slash-url-serializer.ts index 0c3a43e554..061972e38e 100644 --- a/src/app/site-common/trailing-slash-url-serializer.ts +++ b/src/app/site-common/trailing-slash-url-serializer.ts @@ -11,7 +11,7 @@ export class TrailingSlashUrlSerializer extends DefaultUrlSerializer { const pathArr = url.split(splitOn); if (!pathArr[0].endsWith('/')) { - let fileName: string = url.substring( url.lastIndexOf('/') + 1); + const fileName = url.substring( url.lastIndexOf('/') + 1); if (fileName.indexOf('.') === -1) { pathArr[0] += '/'; }