because I got bored of customising my CV for every job
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

refactor(services): delegate OrFail methods to non-throwing counterparts

- Refactor findByXOrFail methods to delegate to corresponding findByX methods
- Apply pattern across UserService, CompanyService, LevelService, RoleService, SkillService, UserJobExperienceService, OrganizationRoleService
- Remove code duplication and ensure consistent error handling
- OrFail methods now only handle the error-throwing responsibility

+93 -700
+2
.cursorrules
··· 267 267 - **Use `findFor` methods** (e.g., `findForUser(user)`) instead of `findBy` methods with IDs 268 268 - **DTOs should contain full entities** instead of foreign key IDs 269 269 - **Only use IDs for Prisma operations** - extract IDs from entities at the service boundary 270 + - **OrFail delegation**: Implement `findByXOrFail` methods by delegating to the corresponding non-throwing `findByX` method and only handling the error-throwing responsibility (prefer early return style). This avoids duplication and ensures consistent behavior. 271 + - **Maximise mapper usage**: Services must use their injected mappers (`toDomain`, `mapToDomain`, and any specialized helpers) for all conversions from Prisma to domain, including joined/`include` cases. Avoid manual `new Entity(...)` in services. 270 272 271 273 #### Mapping Functions 272 274 - **`fromDomain()`** - Domain entity to GraphQL type
+1 -1
apps/client/package.json
··· 23 23 "react-router-dom": "^7.9.4" 24 24 }, 25 25 "devDependencies": { 26 - "@biomejs/biome": "^1.8.3", 26 + "@biomejs/biome": "^2.2.6", 27 27 "@catppuccin/tailwindcss": "^1.0.0", 28 28 "@cv/biome-config": "0.0.0", 29 29 "@cv/tsconfig": "0.0.0",
+1 -1
apps/server/package.json
··· 49 49 "zod": "^3.23.8" 50 50 }, 51 51 "devDependencies": { 52 - "@biomejs/biome": "^1.8.3", 52 + "@biomejs/biome": "^2.2.6", 53 53 "@cv/biome-config": "0.0.0", 54 54 "@cv/tsconfig": "0.0.0", 55 55 "@nestjs/testing": "^10.4.7",
+28 -1
apps/server/src/modules/auth/user.mapper.ts
··· 1 1 import { Injectable } from "@nestjs/common"; 2 - import type { User as PrismaUser } from "@prisma/client"; 2 + import type { 3 + Organization as PrismaOrganization, 4 + User as PrismaUser, 5 + } from "@prisma/client"; 3 6 import type { BaseMapper } from "../base/mapper.interface"; 4 7 import { User } from "./user.entity"; 5 8 ··· 33 36 */ 34 37 mapToDomain(prismaUsers: PrismaUser[]): User[] { 35 38 return prismaUsers.map((user) => this.toDomain(user)); 39 + } 40 + 41 + /** 42 + * Maps a Prisma user with joined organizations to a domain User preserving organizations 43 + */ 44 + toDomainWithOrganizations( 45 + prismaUser: 46 + | (PrismaUser & { 47 + organizations: Array<{ organization: PrismaOrganization }>; 48 + }) 49 + | null, 50 + ): User | null { 51 + if (prismaUser === null) return null; 52 + const organizations = prismaUser.organizations.map( 53 + (uo: { organization: PrismaOrganization }) => uo.organization, 54 + ); 55 + return new User( 56 + prismaUser.id, 57 + prismaUser.email, 58 + prismaUser.name, 59 + prismaUser.createdAt, 60 + prismaUser.updatedAt, 61 + organizations, 62 + ); 36 63 } 37 64 }
+9 -24
apps/server/src/modules/auth/user.service.ts
··· 78 78 } 79 79 80 80 async findByEmailOrFail(email: string): Promise<User> { 81 - const prismaUser = await this.prisma.user.findUnique({ 82 - where: { email }, 83 - }); 84 - 85 - if (!prismaUser) { 81 + const user = await this.findByEmail(email); 82 + if (!user) { 86 83 throw new NotFoundException(`User with email ${email} not found`); 87 84 } 88 - 89 - return this.userMapper.toDomain(prismaUser); 85 + return user; 90 86 } 91 87 92 88 async findByIdOrFail(id: string): Promise<User> { 93 - const prismaUser = await this.prisma.user.findUnique({ 94 - where: { id }, 95 - }); 96 - 97 - if (!prismaUser) { 89 + const user = await this.findById(id); 90 + if (!user) { 98 91 throw new NotFoundException(`User with id ${id} not found`); 99 92 } 100 - 101 - return this.userMapper.toDomain(prismaUser); 93 + return user; 102 94 } 103 95 104 96 async findByIdWithOrganizations(id: string): Promise<User> { ··· 117 109 throw new NotFoundException(`User with id ${id} not found`); 118 110 } 119 111 120 - const organizations = prismaUser.organizations.map((uo) => uo.organization); 121 - 122 - return new User( 123 - prismaUser.id, 124 - prismaUser.email, 125 - prismaUser.name, 126 - prismaUser.createdAt, 127 - prismaUser.updatedAt, 128 - organizations, 129 - ); 112 + const user = this.userMapper.toDomainWithOrganizations(prismaUser); 113 + // user is non-null due to guard above 114 + return user as User; 130 115 } 131 116 }
+6 -14
apps/server/src/modules/job-experience/company/company.service.ts
··· 33 33 } 34 34 35 35 async findByIdOrFail(id: string): Promise<Company> { 36 - const prismaCompany = await this.prisma.company.findUnique({ 37 - where: { id }, 38 - }); 39 - 40 - if (!prismaCompany) { 36 + const company = await this.findById(id); 37 + if (!company) { 41 38 throw new NotFoundException(`Company with id ${id} not found`); 42 39 } 43 - 44 - return this.companyMapper.toDomain(prismaCompany); 40 + return company; 45 41 } 46 42 47 43 async findByName(name: string): Promise<Company | null> { ··· 52 48 } 53 49 54 50 async findByNameOrFail(name: string): Promise<Company> { 55 - const prismaCompany = await this.prisma.company.findUnique({ 56 - where: { name }, 57 - }); 58 - 59 - if (!prismaCompany) { 51 + const company = await this.findByName(name); 52 + if (!company) { 60 53 throw new NotFoundException(`Company with name ${name} not found`); 61 54 } 62 - 63 - return this.companyMapper.toDomain(prismaCompany); 55 + return company; 64 56 } 65 57 66 58 async update(
+3 -13
apps/server/src/modules/job-experience/employment/user-job-experience.service.ts
··· 105 105 } 106 106 107 107 async findByIdOrFail(id: string): Promise<UserJobExperience> { 108 - const prismaExperience = await this.prisma.userJobExperience.findUnique({ 109 - where: { id }, 110 - include: { 111 - company: true, 112 - role: true, 113 - level: true, 114 - skills: true, 115 - }, 116 - }); 117 - 118 - if (!prismaExperience) { 108 + const experience = await this.findById(id); 109 + if (!experience) { 119 110 throw new NotFoundException(`Job experience with id ${id} not found`); 120 111 } 121 - 122 - return this.userJobExperienceMapper.toDomain(prismaExperience); 112 + return experience; 123 113 } 124 114 125 115 async update(
+6 -14
apps/server/src/modules/job-experience/level/level.service.ts
··· 33 33 } 34 34 35 35 async findByIdOrFail(id: string): Promise<Level> { 36 - const prismaLevel = await this.prisma.level.findUnique({ 37 - where: { id }, 38 - }); 39 - 40 - if (!prismaLevel) { 36 + const level = await this.findById(id); 37 + if (!level) { 41 38 throw new NotFoundException(`Level with id ${id} not found`); 42 39 } 43 - 44 - return this.levelMapper.toDomain(prismaLevel); 40 + return level; 45 41 } 46 42 47 43 async findByName(name: string): Promise<Level | null> { ··· 52 48 } 53 49 54 50 async findByNameOrFail(name: string): Promise<Level> { 55 - const prismaLevel = await this.prisma.level.findUnique({ 56 - where: { name }, 57 - }); 58 - 59 - if (!prismaLevel) { 51 + const level = await this.findByName(name); 52 + if (!level) { 60 53 throw new NotFoundException(`Level with name ${name} not found`); 61 54 } 62 - 63 - return this.levelMapper.toDomain(prismaLevel); 55 + return level; 64 56 } 65 57 66 58 async update(id: string, updateLevelDto: UpdateLevelDto): Promise<Level> {
+6 -14
apps/server/src/modules/job-experience/role/role.service.ts
··· 33 33 } 34 34 35 35 async findByIdOrFail(id: string): Promise<Role> { 36 - const prismaRole = await this.prisma.role.findUnique({ 37 - where: { id }, 38 - }); 39 - 40 - if (!prismaRole) { 36 + const role = await this.findById(id); 37 + if (!role) { 41 38 throw new NotFoundException(`Role with id ${id} not found`); 42 39 } 43 - 44 - return this.roleMapper.toDomain(prismaRole); 40 + return role; 45 41 } 46 42 47 43 async findByName(name: string): Promise<Role | null> { ··· 52 48 } 53 49 54 50 async findByNameOrFail(name: string): Promise<Role> { 55 - const prismaRole = await this.prisma.role.findUnique({ 56 - where: { name }, 57 - }); 58 - 59 - if (!prismaRole) { 51 + const role = await this.findByName(name); 52 + if (!role) { 60 53 throw new NotFoundException(`Role with name ${name} not found`); 61 54 } 62 - 63 - return this.roleMapper.toDomain(prismaRole); 55 + return role; 64 56 } 65 57 66 58 async update(id: string, updateRoleDto: UpdateRoleDto): Promise<Role> {
+6 -14
apps/server/src/modules/job-experience/skill/skill.service.ts
··· 33 33 } 34 34 35 35 async findByIdOrFail(id: string): Promise<Skill> { 36 - const prismaSkill = await this.prisma.skill.findUnique({ 37 - where: { id }, 38 - }); 39 - 40 - if (!prismaSkill) { 36 + const skill = await this.findById(id); 37 + if (!skill) { 41 38 throw new NotFoundException(`Skill with id ${id} not found`); 42 39 } 43 - 44 - return this.skillMapper.toDomain(prismaSkill); 40 + return skill; 45 41 } 46 42 47 43 async findByName(name: string): Promise<Skill | null> { ··· 52 48 } 53 49 54 50 async findByNameOrFail(name: string): Promise<Skill> { 55 - const prismaSkill = await this.prisma.skill.findUnique({ 56 - where: { name }, 57 - }); 58 - 59 - if (!prismaSkill) { 51 + const skill = await this.findByName(name); 52 + if (!skill) { 60 53 throw new NotFoundException(`Skill with name ${name} not found`); 61 54 } 62 - 63 - return this.skillMapper.toDomain(prismaSkill); 55 + return skill; 64 56 } 65 57 66 58 async update(id: string, updateSkillDto: UpdateSkillDto): Promise<Skill> {
+4 -4
apps/server/src/modules/seed/organization-seed.service.ts
··· 1 1 import { faker } from "@faker-js/faker"; 2 - import { Injectable, Logger } from "@nestjs/common"; 2 + import { Injectable } from "@nestjs/common"; 3 3 import { PrismaService } from "../database/prisma.service"; 4 4 5 5 @Injectable() ··· 17 17 ]; 18 18 const created: Array<{ id: string }> = []; 19 19 for (const name of names) { 20 - const existing = await this.prisma["organization"].findFirst({ where: { name } }); 20 + const existing = await this.prisma["organization"].findFirst({ 21 + where: { name }, 22 + }); 21 23 if (existing) { 22 24 created.push({ id: existing.id }); 23 25 continue; ··· 30 32 return created; 31 33 } 32 34 } 33 - 34 -
+15 -7
apps/server/src/modules/seed/reference-data-seed.service.ts
··· 1 1 import { faker } from "@faker-js/faker"; 2 - import { Injectable, Logger } from "@nestjs/common"; 2 + import { Injectable } from "@nestjs/common"; 3 3 import { PrismaService } from "../database/prisma.service"; 4 4 5 5 @Injectable() ··· 12 12 const skills = ["React", "TypeScript", "Node.js", "GraphQL", "PostgreSQL"]; 13 13 const created: Array<{ id: string }> = []; 14 14 for (const name of skills) { 15 - const existing = await this.prisma["skill"].findFirst({ where: { name } }); 15 + const existing = await this.prisma["skill"].findFirst({ 16 + where: { name }, 17 + }); 16 18 if (existing) { 17 19 created.push({ id: existing.id }); 18 20 continue; ··· 29 31 const names = ["Google", "Microsoft", "Amazon", "Netflix"]; 30 32 const created: Array<{ id: string }> = []; 31 33 for (const name of names) { 32 - const existing = await this.prisma["company"].findFirst({ where: { name } }); 34 + const existing = await this.prisma["company"].findFirst({ 35 + where: { name }, 36 + }); 33 37 if (existing) { 34 38 created.push({ id: existing.id }); 35 39 continue; 36 40 } 37 41 const c = await this.prisma["company"].create({ 38 - data: { name, description: faker.company.catchPhrase(), website: faker.internet.url() }, 42 + data: { 43 + name, 44 + description: faker.company.catchPhrase(), 45 + website: faker.internet.url(), 46 + }, 39 47 }); 40 48 created.push({ id: c.id }); 41 49 } ··· 67 75 const names = ["Junior", "Mid-level", "Senior"]; 68 76 const created: Array<{ id: string }> = []; 69 77 for (const name of names) { 70 - const existing = await this.prisma["level"].findFirst({ where: { name } }); 78 + const existing = await this.prisma["level"].findFirst({ 79 + where: { name }, 80 + }); 71 81 if (existing) { 72 82 created.push({ id: existing.id }); 73 83 continue; ··· 80 90 return created; 81 91 } 82 92 } 83 - 84 -
-2
apps/server/src/scripts/e2e-coverage-all.cjs
··· 71 71 main().catch(() => { 72 72 process.exit(1); 73 73 }); 74 - 75 -
-2
apps/server/src/scripts/seed-test.ts
··· 12 12 main().catch(() => { 13 13 process.exitCode = 1; 14 14 }); 15 - 16 -
-87
apps/server/test/coverage-unit/lcov-report/block-navigation.js
··· 1 - /* eslint-disable */ 2 - var jumpToCode = (function init() { 3 - // Classes of code we would like to highlight in the file view 4 - var missingCoverageClasses = ['.cbranch-no', '.cstat-no', '.fstat-no']; 5 - 6 - // Elements to highlight in the file listing view 7 - var fileListingElements = ['td.pct.low']; 8 - 9 - // We don't want to select elements that are direct descendants of another match 10 - var notSelector = ':not(' + missingCoverageClasses.join('):not(') + ') > '; // becomes `:not(a):not(b) > ` 11 - 12 - // Selector that finds elements on the page to which we can jump 13 - var selector = 14 - fileListingElements.join(', ') + 15 - ', ' + 16 - notSelector + 17 - missingCoverageClasses.join(', ' + notSelector); // becomes `:not(a):not(b) > a, :not(a):not(b) > b` 18 - 19 - // The NodeList of matching elements 20 - var missingCoverageElements = document.querySelectorAll(selector); 21 - 22 - var currentIndex; 23 - 24 - function toggleClass(index) { 25 - missingCoverageElements 26 - .item(currentIndex) 27 - .classList.remove('highlighted'); 28 - missingCoverageElements.item(index).classList.add('highlighted'); 29 - } 30 - 31 - function makeCurrent(index) { 32 - toggleClass(index); 33 - currentIndex = index; 34 - missingCoverageElements.item(index).scrollIntoView({ 35 - behavior: 'smooth', 36 - block: 'center', 37 - inline: 'center' 38 - }); 39 - } 40 - 41 - function goToPrevious() { 42 - var nextIndex = 0; 43 - if (typeof currentIndex !== 'number' || currentIndex === 0) { 44 - nextIndex = missingCoverageElements.length - 1; 45 - } else if (missingCoverageElements.length > 1) { 46 - nextIndex = currentIndex - 1; 47 - } 48 - 49 - makeCurrent(nextIndex); 50 - } 51 - 52 - function goToNext() { 53 - var nextIndex = 0; 54 - 55 - if ( 56 - typeof currentIndex === 'number' && 57 - currentIndex < missingCoverageElements.length - 1 58 - ) { 59 - nextIndex = currentIndex + 1; 60 - } 61 - 62 - makeCurrent(nextIndex); 63 - } 64 - 65 - return function jump(event) { 66 - if ( 67 - document.getElementById('fileSearch') === document.activeElement && 68 - document.activeElement != null 69 - ) { 70 - // if we're currently focused on the search input, we don't want to navigate 71 - return; 72 - } 73 - 74 - switch (event.which) { 75 - case 78: // n 76 - case 74: // j 77 - goToNext(); 78 - break; 79 - case 66: // b 80 - case 75: // k 81 - case 80: // p 82 - goToPrevious(); 83 - break; 84 - } 85 - }; 86 - })(); 87 - window.addEventListener('keydown', jumpToCode);
+1 -1
apps/server/test/coverage-unit/lcov-report/index.html
··· 86 86 <div class='footer quiet pad2 space-top1 center small'> 87 87 Code coverage generated by 88 88 <a href="https://istanbul.js.org/" target="_blank" rel="noopener noreferrer">istanbul</a> 89 - at 2025-10-20T12:27:27.089Z 89 + at 2025-10-20T15:57:14.900Z 90 90 </div> 91 91 <script src="prettify.js"></script> 92 92 <script>
-2
apps/server/test/coverage-unit/lcov-report/prettify.js
··· 1 - /* eslint-disable */ 2 - window.PR_SHOULD_USE_CONTINUATION=true;(function(){var h=["break,continue,do,else,for,if,return,while"];var u=[h,"auto,case,char,const,default,double,enum,extern,float,goto,int,long,register,short,signed,sizeof,static,struct,switch,typedef,union,unsigned,void,volatile"];var p=[u,"catch,class,delete,false,import,new,operator,private,protected,public,this,throw,true,try,typeof"];var l=[p,"alignof,align_union,asm,axiom,bool,concept,concept_map,const_cast,constexpr,decltype,dynamic_cast,explicit,export,friend,inline,late_check,mutable,namespace,nullptr,reinterpret_cast,static_assert,static_cast,template,typeid,typename,using,virtual,where"];var x=[p,"abstract,boolean,byte,extends,final,finally,implements,import,instanceof,null,native,package,strictfp,super,synchronized,throws,transient"];var R=[x,"as,base,by,checked,decimal,delegate,descending,dynamic,event,fixed,foreach,from,group,implicit,in,interface,internal,into,is,lock,object,out,override,orderby,params,partial,readonly,ref,sbyte,sealed,stackalloc,string,select,uint,ulong,unchecked,unsafe,ushort,var"];var r="all,and,by,catch,class,else,extends,false,finally,for,if,in,is,isnt,loop,new,no,not,null,of,off,on,or,return,super,then,true,try,unless,until,when,while,yes";var w=[p,"debugger,eval,export,function,get,null,set,undefined,var,with,Infinity,NaN"];var s="caller,delete,die,do,dump,elsif,eval,exit,foreach,for,goto,if,import,last,local,my,next,no,our,print,package,redo,require,sub,undef,unless,until,use,wantarray,while,BEGIN,END";var I=[h,"and,as,assert,class,def,del,elif,except,exec,finally,from,global,import,in,is,lambda,nonlocal,not,or,pass,print,raise,try,with,yield,False,True,None"];var f=[h,"alias,and,begin,case,class,def,defined,elsif,end,ensure,false,in,module,next,nil,not,or,redo,rescue,retry,self,super,then,true,undef,unless,until,when,yield,BEGIN,END"];var H=[h,"case,done,elif,esac,eval,fi,function,in,local,set,then,until"];var A=[l,R,w,s+I,f,H];var e=/^(DIR|FILE|vector|(de|priority_)?queue|list|stack|(const_)?iterator|(multi)?(set|map)|bitset|u?(int|float)\d*)/;var C="str";var z="kwd";var j="com";var O="typ";var G="lit";var L="pun";var F="pln";var m="tag";var E="dec";var J="src";var P="atn";var n="atv";var N="nocode";var M="(?:^^\\.?|[+-]|\\!|\\!=|\\!==|\\#|\\%|\\%=|&|&&|&&=|&=|\\(|\\*|\\*=|\\+=|\\,|\\-=|\\->|\\/|\\/=|:|::|\\;|<|<<|<<=|<=|=|==|===|>|>=|>>|>>=|>>>|>>>=|\\?|\\@|\\[|\\^|\\^=|\\^\\^|\\^\\^=|\\{|\\||\\|=|\\|\\||\\|\\|=|\\~|break|case|continue|delete|do|else|finally|instanceof|return|throw|try|typeof)\\s*";function k(Z){var ad=0;var S=false;var ac=false;for(var V=0,U=Z.length;V<U;++V){var ae=Z[V];if(ae.ignoreCase){ac=true}else{if(/[a-z]/i.test(ae.source.replace(/\\u[0-9a-f]{4}|\\x[0-9a-f]{2}|\\[^ux]/gi,""))){S=true;ac=false;break}}}var Y={b:8,t:9,n:10,v:11,f:12,r:13};function ab(ah){var ag=ah.charCodeAt(0);if(ag!==92){return ag}var af=ah.charAt(1);ag=Y[af];if(ag){return ag}else{if("0"<=af&&af<="7"){return parseInt(ah.substring(1),8)}else{if(af==="u"||af==="x"){return parseInt(ah.substring(2),16)}else{return ah.charCodeAt(1)}}}}function T(af){if(af<32){return(af<16?"\\x0":"\\x")+af.toString(16)}var ag=String.fromCharCode(af);if(ag==="\\"||ag==="-"||ag==="["||ag==="]"){ag="\\"+ag}return ag}function X(am){var aq=am.substring(1,am.length-1).match(new RegExp("\\\\u[0-9A-Fa-f]{4}|\\\\x[0-9A-Fa-f]{2}|\\\\[0-3][0-7]{0,2}|\\\\[0-7]{1,2}|\\\\[\\s\\S]|-|[^-\\\\]","g"));var ak=[];var af=[];var ao=aq[0]==="^";for(var ar=ao?1:0,aj=aq.length;ar<aj;++ar){var ah=aq[ar];if(/\\[bdsw]/i.test(ah)){ak.push(ah)}else{var ag=ab(ah);var al;if(ar+2<aj&&"-"===aq[ar+1]){al=ab(aq[ar+2]);ar+=2}else{al=ag}af.push([ag,al]);if(!(al<65||ag>122)){if(!(al<65||ag>90)){af.push([Math.max(65,ag)|32,Math.min(al,90)|32])}if(!(al<97||ag>122)){af.push([Math.max(97,ag)&~32,Math.min(al,122)&~32])}}}}af.sort(function(av,au){return(av[0]-au[0])||(au[1]-av[1])});var ai=[];var ap=[NaN,NaN];for(var ar=0;ar<af.length;++ar){var at=af[ar];if(at[0]<=ap[1]+1){ap[1]=Math.max(ap[1],at[1])}else{ai.push(ap=at)}}var an=["["];if(ao){an.push("^")}an.push.apply(an,ak);for(var ar=0;ar<ai.length;++ar){var at=ai[ar];an.push(T(at[0]));if(at[1]>at[0]){if(at[1]+1>at[0]){an.push("-")}an.push(T(at[1]))}}an.push("]");return an.join("")}function W(al){var aj=al.source.match(new RegExp("(?:\\[(?:[^\\x5C\\x5D]|\\\\[\\s\\S])*\\]|\\\\u[A-Fa-f0-9]{4}|\\\\x[A-Fa-f0-9]{2}|\\\\[0-9]+|\\\\[^ux0-9]|\\(\\?[:!=]|[\\(\\)\\^]|[^\\x5B\\x5C\\(\\)\\^]+)","g"));var ah=aj.length;var an=[];for(var ak=0,am=0;ak<ah;++ak){var ag=aj[ak];if(ag==="("){++am}else{if("\\"===ag.charAt(0)){var af=+ag.substring(1);if(af&&af<=am){an[af]=-1}}}}for(var ak=1;ak<an.length;++ak){if(-1===an[ak]){an[ak]=++ad}}for(var ak=0,am=0;ak<ah;++ak){var ag=aj[ak];if(ag==="("){++am;if(an[am]===undefined){aj[ak]="(?:"}}else{if("\\"===ag.charAt(0)){var af=+ag.substring(1);if(af&&af<=am){aj[ak]="\\"+an[am]}}}}for(var ak=0,am=0;ak<ah;++ak){if("^"===aj[ak]&&"^"!==aj[ak+1]){aj[ak]=""}}if(al.ignoreCase&&S){for(var ak=0;ak<ah;++ak){var ag=aj[ak];var ai=ag.charAt(0);if(ag.length>=2&&ai==="["){aj[ak]=X(ag)}else{if(ai!=="\\"){aj[ak]=ag.replace(/[a-zA-Z]/g,function(ao){var ap=ao.charCodeAt(0);return"["+String.fromCharCode(ap&~32,ap|32)+"]"})}}}}return aj.join("")}var aa=[];for(var V=0,U=Z.length;V<U;++V){var ae=Z[V];if(ae.global||ae.multiline){throw new Error(""+ae)}aa.push("(?:"+W(ae)+")")}return new RegExp(aa.join("|"),ac?"gi":"g")}function a(V){var U=/(?:^|\s)nocode(?:\s|$)/;var X=[];var T=0;var Z=[];var W=0;var S;if(V.currentStyle){S=V.currentStyle.whiteSpace}else{if(window.getComputedStyle){S=document.defaultView.getComputedStyle(V,null).getPropertyValue("white-space")}}var Y=S&&"pre"===S.substring(0,3);function aa(ab){switch(ab.nodeType){case 1:if(U.test(ab.className)){return}for(var ae=ab.firstChild;ae;ae=ae.nextSibling){aa(ae)}var ad=ab.nodeName;if("BR"===ad||"LI"===ad){X[W]="\n";Z[W<<1]=T++;Z[(W++<<1)|1]=ab}break;case 3:case 4:var ac=ab.nodeValue;if(ac.length){if(!Y){ac=ac.replace(/[ \t\r\n]+/g," ")}else{ac=ac.replace(/\r\n?/g,"\n")}X[W]=ac;Z[W<<1]=T;T+=ac.length;Z[(W++<<1)|1]=ab}break}}aa(V);return{sourceCode:X.join("").replace(/\n$/,""),spans:Z}}function B(S,U,W,T){if(!U){return}var V={sourceCode:U,basePos:S};W(V);T.push.apply(T,V.decorations)}var v=/\S/;function o(S){var V=undefined;for(var U=S.firstChild;U;U=U.nextSibling){var T=U.nodeType;V=(T===1)?(V?S:U):(T===3)?(v.test(U.nodeValue)?S:V):V}return V===S?undefined:V}function g(U,T){var S={};var V;(function(){var ad=U.concat(T);var ah=[];var ag={};for(var ab=0,Z=ad.length;ab<Z;++ab){var Y=ad[ab];var ac=Y[3];if(ac){for(var ae=ac.length;--ae>=0;){S[ac.charAt(ae)]=Y}}var af=Y[1];var aa=""+af;if(!ag.hasOwnProperty(aa)){ah.push(af);ag[aa]=null}}ah.push(/[\0-\uffff]/);V=k(ah)})();var X=T.length;var W=function(ah){var Z=ah.sourceCode,Y=ah.basePos;var ad=[Y,F];var af=0;var an=Z.match(V)||[];var aj={};for(var ae=0,aq=an.length;ae<aq;++ae){var ag=an[ae];var ap=aj[ag];var ai=void 0;var am;if(typeof ap==="string"){am=false}else{var aa=S[ag.charAt(0)];if(aa){ai=ag.match(aa[1]);ap=aa[0]}else{for(var ao=0;ao<X;++ao){aa=T[ao];ai=ag.match(aa[1]);if(ai){ap=aa[0];break}}if(!ai){ap=F}}am=ap.length>=5&&"lang-"===ap.substring(0,5);if(am&&!(ai&&typeof ai[1]==="string")){am=false;ap=J}if(!am){aj[ag]=ap}}var ab=af;af+=ag.length;if(!am){ad.push(Y+ab,ap)}else{var al=ai[1];var ak=ag.indexOf(al);var ac=ak+al.length;if(ai[2]){ac=ag.length-ai[2].length;ak=ac-al.length}var ar=ap.substring(5);B(Y+ab,ag.substring(0,ak),W,ad);B(Y+ab+ak,al,q(ar,al),ad);B(Y+ab+ac,ag.substring(ac),W,ad)}}ah.decorations=ad};return W}function i(T){var W=[],S=[];if(T.tripleQuotedStrings){W.push([C,/^(?:\'\'\'(?:[^\'\\]|\\[\s\S]|\'{1,2}(?=[^\']))*(?:\'\'\'|$)|\"\"\"(?:[^\"\\]|\\[\s\S]|\"{1,2}(?=[^\"]))*(?:\"\"\"|$)|\'(?:[^\\\']|\\[\s\S])*(?:\'|$)|\"(?:[^\\\"]|\\[\s\S])*(?:\"|$))/,null,"'\""])}else{if(T.multiLineStrings){W.push([C,/^(?:\'(?:[^\\\']|\\[\s\S])*(?:\'|$)|\"(?:[^\\\"]|\\[\s\S])*(?:\"|$)|\`(?:[^\\\`]|\\[\s\S])*(?:\`|$))/,null,"'\"`"])}else{W.push([C,/^(?:\'(?:[^\\\'\r\n]|\\.)*(?:\'|$)|\"(?:[^\\\"\r\n]|\\.)*(?:\"|$))/,null,"\"'"])}}if(T.verbatimStrings){S.push([C,/^@\"(?:[^\"]|\"\")*(?:\"|$)/,null])}var Y=T.hashComments;if(Y){if(T.cStyleComments){if(Y>1){W.push([j,/^#(?:##(?:[^#]|#(?!##))*(?:###|$)|.*)/,null,"#"])}else{W.push([j,/^#(?:(?:define|elif|else|endif|error|ifdef|include|ifndef|line|pragma|undef|warning)\b|[^\r\n]*)/,null,"#"])}S.push([C,/^<(?:(?:(?:\.\.\/)*|\/?)(?:[\w-]+(?:\/[\w-]+)+)?[\w-]+\.h|[a-z]\w*)>/,null])}else{W.push([j,/^#[^\r\n]*/,null,"#"])}}if(T.cStyleComments){S.push([j,/^\/\/[^\r\n]*/,null]);S.push([j,/^\/\*[\s\S]*?(?:\*\/|$)/,null])}if(T.regexLiterals){var X=("/(?=[^/*])(?:[^/\\x5B\\x5C]|\\x5C[\\s\\S]|\\x5B(?:[^\\x5C\\x5D]|\\x5C[\\s\\S])*(?:\\x5D|$))+/");S.push(["lang-regex",new RegExp("^"+M+"("+X+")")])}var V=T.types;if(V){S.push([O,V])}var U=(""+T.keywords).replace(/^ | $/g,"");if(U.length){S.push([z,new RegExp("^(?:"+U.replace(/[\s,]+/g,"|")+")\\b"),null])}W.push([F,/^\s+/,null," \r\n\t\xA0"]);S.push([G,/^@[a-z_$][a-z_$@0-9]*/i,null],[O,/^(?:[@_]?[A-Z]+[a-z][A-Za-z_$@0-9]*|\w+_t\b)/,null],[F,/^[a-z_$][a-z_$@0-9]*/i,null],[G,new RegExp("^(?:0x[a-f0-9]+|(?:\\d(?:_\\d+)*\\d*(?:\\.\\d*)?|\\.\\d\\+)(?:e[+\\-]?\\d+)?)[a-z]*","i"),null,"0123456789"],[F,/^\\[\s\S]?/,null],[L,/^.[^\s\w\.$@\'\"\`\/\#\\]*/,null]);return g(W,S)}var K=i({keywords:A,hashComments:true,cStyleComments:true,multiLineStrings:true,regexLiterals:true});function Q(V,ag){var U=/(?:^|\s)nocode(?:\s|$)/;var ab=/\r\n?|\n/;var ac=V.ownerDocument;var S;if(V.currentStyle){S=V.currentStyle.whiteSpace}else{if(window.getComputedStyle){S=ac.defaultView.getComputedStyle(V,null).getPropertyValue("white-space")}}var Z=S&&"pre"===S.substring(0,3);var af=ac.createElement("LI");while(V.firstChild){af.appendChild(V.firstChild)}var W=[af];function ae(al){switch(al.nodeType){case 1:if(U.test(al.className)){break}if("BR"===al.nodeName){ad(al);if(al.parentNode){al.parentNode.removeChild(al)}}else{for(var an=al.firstChild;an;an=an.nextSibling){ae(an)}}break;case 3:case 4:if(Z){var am=al.nodeValue;var aj=am.match(ab);if(aj){var ai=am.substring(0,aj.index);al.nodeValue=ai;var ah=am.substring(aj.index+aj[0].length);if(ah){var ak=al.parentNode;ak.insertBefore(ac.createTextNode(ah),al.nextSibling)}ad(al);if(!ai){al.parentNode.removeChild(al)}}}break}}function ad(ak){while(!ak.nextSibling){ak=ak.parentNode;if(!ak){return}}function ai(al,ar){var aq=ar?al.cloneNode(false):al;var ao=al.parentNode;if(ao){var ap=ai(ao,1);var an=al.nextSibling;ap.appendChild(aq);for(var am=an;am;am=an){an=am.nextSibling;ap.appendChild(am)}}return aq}var ah=ai(ak.nextSibling,0);for(var aj;(aj=ah.parentNode)&&aj.nodeType===1;){ah=aj}W.push(ah)}for(var Y=0;Y<W.length;++Y){ae(W[Y])}if(ag===(ag|0)){W[0].setAttribute("value",ag)}var aa=ac.createElement("OL");aa.className="linenums";var X=Math.max(0,((ag-1))|0)||0;for(var Y=0,T=W.length;Y<T;++Y){af=W[Y];af.className="L"+((Y+X)%10);if(!af.firstChild){af.appendChild(ac.createTextNode("\xA0"))}aa.appendChild(af)}V.appendChild(aa)}function D(ac){var aj=/\bMSIE\b/.test(navigator.userAgent);var am=/\n/g;var al=ac.sourceCode;var an=al.length;var V=0;var aa=ac.spans;var T=aa.length;var ah=0;var X=ac.decorations;var Y=X.length;var Z=0;X[Y]=an;var ar,aq;for(aq=ar=0;aq<Y;){if(X[aq]!==X[aq+2]){X[ar++]=X[aq++];X[ar++]=X[aq++]}else{aq+=2}}Y=ar;for(aq=ar=0;aq<Y;){var at=X[aq];var ab=X[aq+1];var W=aq+2;while(W+2<=Y&&X[W+1]===ab){W+=2}X[ar++]=at;X[ar++]=ab;aq=W}Y=X.length=ar;var ae=null;while(ah<T){var af=aa[ah];var S=aa[ah+2]||an;var ag=X[Z];var ap=X[Z+2]||an;var W=Math.min(S,ap);var ak=aa[ah+1];var U;if(ak.nodeType!==1&&(U=al.substring(V,W))){if(aj){U=U.replace(am,"\r")}ak.nodeValue=U;var ai=ak.ownerDocument;var ao=ai.createElement("SPAN");ao.className=X[Z+1];var ad=ak.parentNode;ad.replaceChild(ao,ak);ao.appendChild(ak);if(V<S){aa[ah+1]=ak=ai.createTextNode(al.substring(W,S));ad.insertBefore(ak,ao.nextSibling)}}V=W;if(V>=S){ah+=2}if(V>=ap){Z+=2}}}var t={};function c(U,V){for(var S=V.length;--S>=0;){var T=V[S];if(!t.hasOwnProperty(T)){t[T]=U}else{if(window.console){console.warn("cannot override language handler %s",T)}}}}function q(T,S){if(!(T&&t.hasOwnProperty(T))){T=/^\s*</.test(S)?"default-markup":"default-code"}return t[T]}c(K,["default-code"]);c(g([],[[F,/^[^<?]+/],[E,/^<!\w[^>]*(?:>|$)/],[j,/^<\!--[\s\S]*?(?:-\->|$)/],["lang-",/^<\?([\s\S]+?)(?:\?>|$)/],["lang-",/^<%([\s\S]+?)(?:%>|$)/],[L,/^(?:<[%?]|[%?]>)/],["lang-",/^<xmp\b[^>]*>([\s\S]+?)<\/xmp\b[^>]*>/i],["lang-js",/^<script\b[^>]*>([\s\S]*?)(<\/script\b[^>]*>)/i],["lang-css",/^<style\b[^>]*>([\s\S]*?)(<\/style\b[^>]*>)/i],["lang-in.tag",/^(<\/?[a-z][^<>]*>)/i]]),["default-markup","htm","html","mxml","xhtml","xml","xsl"]);c(g([[F,/^[\s]+/,null," \t\r\n"],[n,/^(?:\"[^\"]*\"?|\'[^\']*\'?)/,null,"\"'"]],[[m,/^^<\/?[a-z](?:[\w.:-]*\w)?|\/?>$/i],[P,/^(?!style[\s=]|on)[a-z](?:[\w:-]*\w)?/i],["lang-uq.val",/^=\s*([^>\'\"\s]*(?:[^>\'\"\s\/]|\/(?=\s)))/],[L,/^[=<>\/]+/],["lang-js",/^on\w+\s*=\s*\"([^\"]+)\"/i],["lang-js",/^on\w+\s*=\s*\'([^\']+)\'/i],["lang-js",/^on\w+\s*=\s*([^\"\'>\s]+)/i],["lang-css",/^style\s*=\s*\"([^\"]+)\"/i],["lang-css",/^style\s*=\s*\'([^\']+)\'/i],["lang-css",/^style\s*=\s*([^\"\'>\s]+)/i]]),["in.tag"]);c(g([],[[n,/^[\s\S]+/]]),["uq.val"]);c(i({keywords:l,hashComments:true,cStyleComments:true,types:e}),["c","cc","cpp","cxx","cyc","m"]);c(i({keywords:"null,true,false"}),["json"]);c(i({keywords:R,hashComments:true,cStyleComments:true,verbatimStrings:true,types:e}),["cs"]);c(i({keywords:x,cStyleComments:true}),["java"]);c(i({keywords:H,hashComments:true,multiLineStrings:true}),["bsh","csh","sh"]);c(i({keywords:I,hashComments:true,multiLineStrings:true,tripleQuotedStrings:true}),["cv","py"]);c(i({keywords:s,hashComments:true,multiLineStrings:true,regexLiterals:true}),["perl","pl","pm"]);c(i({keywords:f,hashComments:true,multiLineStrings:true,regexLiterals:true}),["rb"]);c(i({keywords:w,cStyleComments:true,regexLiterals:true}),["js"]);c(i({keywords:r,hashComments:3,cStyleComments:true,multilineStrings:true,tripleQuotedStrings:true,regexLiterals:true}),["coffee"]);c(g([],[[C,/^[\s\S]+/]]),["regex"]);function d(V){var U=V.langExtension;try{var S=a(V.sourceNode);var T=S.sourceCode;V.sourceCode=T;V.spans=S.spans;V.basePos=0;q(U,T)(V);D(V)}catch(W){if("console" in window){console.log(W&&W.stack?W.stack:W)}}}function y(W,V,U){var S=document.createElement("PRE");S.innerHTML=W;if(U){Q(S,U)}var T={langExtension:V,numberLines:U,sourceNode:S};d(T);return S.innerHTML}function b(ad){function Y(af){return document.getElementsByTagName(af)}var ac=[Y("pre"),Y("code"),Y("xmp")];var T=[];for(var aa=0;aa<ac.length;++aa){for(var Z=0,V=ac[aa].length;Z<V;++Z){T.push(ac[aa][Z])}}ac=null;var W=Date;if(!W.now){W={now:function(){return +(new Date)}}}var X=0;var S;var ab=/\blang(?:uage)?-([\w.]+)(?!\S)/;var ae=/\bprettyprint\b/;function U(){var ag=(window.PR_SHOULD_USE_CONTINUATION?W.now()+250:Infinity);for(;X<T.length&&W.now()<ag;X++){var aj=T[X];var ai=aj.className;if(ai.indexOf("prettyprint")>=0){var ah=ai.match(ab);var am;if(!ah&&(am=o(aj))&&"CODE"===am.tagName){ah=am.className.match(ab)}if(ah){ah=ah[1]}var al=false;for(var ak=aj.parentNode;ak;ak=ak.parentNode){if((ak.tagName==="pre"||ak.tagName==="code"||ak.tagName==="xmp")&&ak.className&&ak.className.indexOf("prettyprint")>=0){al=true;break}}if(!al){var af=aj.className.match(/\blinenums\b(?::(\d+))?/);af=af?af[1]&&af[1].length?+af[1]:true:false;if(af){Q(aj,af)}S={langExtension:ah,sourceNode:aj,numberLines:af};d(S)}}}if(X<T.length){setTimeout(U,250)}else{if(ad){ad()}}}U()}window.prettyPrintOne=y;window.prettyPrint=b;window.PR={createSimpleLexer:g,registerLangHandler:c,sourceDecorator:i,PR_ATTRIB_NAME:P,PR_ATTRIB_VALUE:n,PR_COMMENT:j,PR_DECLARATION:E,PR_KEYWORD:z,PR_LITERAL:G,PR_NOCODE:N,PR_PLAIN:F,PR_PUNCTUATION:L,PR_SOURCE:J,PR_STRING:C,PR_TAG:m,PR_TYPE:O}})();PR.registerLangHandler(PR.createSimpleLexer([],[[PR.PR_DECLARATION,/^<!\w[^>]*(?:>|$)/],[PR.PR_COMMENT,/^<\!--[\s\S]*?(?:-\->|$)/],[PR.PR_PUNCTUATION,/^(?:<[%?]|[%?]>)/],["lang-",/^<\?([\s\S]+?)(?:\?>|$)/],["lang-",/^<%([\s\S]+?)(?:%>|$)/],["lang-",/^<xmp\b[^>]*>([\s\S]+?)<\/xmp\b[^>]*>/i],["lang-handlebars",/^<script\b[^>]*type\s*=\s*['"]?text\/x-handlebars-template['"]?\b[^>]*>([\s\S]*?)(<\/script\b[^>]*>)/i],["lang-js",/^<script\b[^>]*>([\s\S]*?)(<\/script\b[^>]*>)/i],["lang-css",/^<style\b[^>]*>([\s\S]*?)(<\/style\b[^>]*>)/i],["lang-in.tag",/^(<\/?[a-z][^<>]*>)/i],[PR.PR_DECLARATION,/^{{[#^>/]?\s*[\w.][^}]*}}/],[PR.PR_DECLARATION,/^{{&?\s*[\w.][^}]*}}/],[PR.PR_DECLARATION,/^{{{>?\s*[\w.][^}]*}}}/],[PR.PR_COMMENT,/^{{![^}]*}}/]]),["handlebars","hbs"]);PR.registerLangHandler(PR.createSimpleLexer([[PR.PR_PLAIN,/^[ \t\r\n\f]+/,null," \t\r\n\f"]],[[PR.PR_STRING,/^\"(?:[^\n\r\f\\\"]|\\(?:\r\n?|\n|\f)|\\[\s\S])*\"/,null],[PR.PR_STRING,/^\'(?:[^\n\r\f\\\']|\\(?:\r\n?|\n|\f)|\\[\s\S])*\'/,null],["lang-css-str",/^url\(([^\)\"\']*)\)/i],[PR.PR_KEYWORD,/^(?:url|rgb|\!important|@import|@page|@media|@charset|inherit)(?=[^\-\w]|$)/i,null],["lang-css-kw",/^(-?(?:[_a-z]|(?:\\[0-9a-f]+ ?))(?:[_a-z0-9\-]|\\(?:\\[0-9a-f]+ ?))*)\s*:/i],[PR.PR_COMMENT,/^\/\*[^*]*\*+(?:[^\/*][^*]*\*+)*\//],[PR.PR_COMMENT,/^(?:<!--|-->)/],[PR.PR_LITERAL,/^(?:\d+|\d*\.\d+)(?:%|[a-z]+)?/i],[PR.PR_LITERAL,/^#(?:[0-9a-f]{3}){1,2}/i],[PR.PR_PLAIN,/^-?(?:[_a-z]|(?:\\[\da-f]+ ?))(?:[_a-z\d\-]|\\(?:\\[\da-f]+ ?))*/i],[PR.PR_PUNCTUATION,/^[^\s\w\'\"]+/]]),["css"]);PR.registerLangHandler(PR.createSimpleLexer([],[[PR.PR_KEYWORD,/^-?(?:[_a-z]|(?:\\[\da-f]+ ?))(?:[_a-z\d\-]|\\(?:\\[\da-f]+ ?))*/i]]),["css-kw"]);PR.registerLangHandler(PR.createSimpleLexer([],[[PR.PR_STRING,/^[^\)\"\']+/]]),["css-str"]);
-210
apps/server/test/coverage-unit/lcov-report/sorter.js
··· 1 - /* eslint-disable */ 2 - var addSorting = (function() { 3 - 'use strict'; 4 - var cols, 5 - currentSort = { 6 - index: 0, 7 - desc: false 8 - }; 9 - 10 - // returns the summary table element 11 - function getTable() { 12 - return document.querySelector('.coverage-summary'); 13 - } 14 - // returns the thead element of the summary table 15 - function getTableHeader() { 16 - return getTable().querySelector('thead tr'); 17 - } 18 - // returns the tbody element of the summary table 19 - function getTableBody() { 20 - return getTable().querySelector('tbody'); 21 - } 22 - // returns the th element for nth column 23 - function getNthColumn(n) { 24 - return getTableHeader().querySelectorAll('th')[n]; 25 - } 26 - 27 - function onFilterInput() { 28 - const searchValue = document.getElementById('fileSearch').value; 29 - const rows = document.getElementsByTagName('tbody')[0].children; 30 - 31 - // Try to create a RegExp from the searchValue. If it fails (invalid regex), 32 - // it will be treated as a plain text search 33 - let searchRegex; 34 - try { 35 - searchRegex = new RegExp(searchValue, 'i'); // 'i' for case-insensitive 36 - } catch (error) { 37 - searchRegex = null; 38 - } 39 - 40 - for (let i = 0; i < rows.length; i++) { 41 - const row = rows[i]; 42 - let isMatch = false; 43 - 44 - if (searchRegex) { 45 - // If a valid regex was created, use it for matching 46 - isMatch = searchRegex.test(row.textContent); 47 - } else { 48 - // Otherwise, fall back to the original plain text search 49 - isMatch = row.textContent 50 - .toLowerCase() 51 - .includes(searchValue.toLowerCase()); 52 - } 53 - 54 - row.style.display = isMatch ? '' : 'none'; 55 - } 56 - } 57 - 58 - // loads the search box 59 - function addSearchBox() { 60 - var template = document.getElementById('filterTemplate'); 61 - var templateClone = template.content.cloneNode(true); 62 - templateClone.getElementById('fileSearch').oninput = onFilterInput; 63 - template.parentElement.appendChild(templateClone); 64 - } 65 - 66 - // loads all columns 67 - function loadColumns() { 68 - var colNodes = getTableHeader().querySelectorAll('th'), 69 - colNode, 70 - cols = [], 71 - col, 72 - i; 73 - 74 - for (i = 0; i < colNodes.length; i += 1) { 75 - colNode = colNodes[i]; 76 - col = { 77 - key: colNode.getAttribute('data-col'), 78 - sortable: !colNode.getAttribute('data-nosort'), 79 - type: colNode.getAttribute('data-type') || 'string' 80 - }; 81 - cols.push(col); 82 - if (col.sortable) { 83 - col.defaultDescSort = col.type === 'number'; 84 - colNode.innerHTML = 85 - colNode.innerHTML + '<span class="sorter"></span>'; 86 - } 87 - } 88 - return cols; 89 - } 90 - // attaches a data attribute to every tr element with an object 91 - // of data values keyed by column name 92 - function loadRowData(tableRow) { 93 - var tableCols = tableRow.querySelectorAll('td'), 94 - colNode, 95 - col, 96 - data = {}, 97 - i, 98 - val; 99 - for (i = 0; i < tableCols.length; i += 1) { 100 - colNode = tableCols[i]; 101 - col = cols[i]; 102 - val = colNode.getAttribute('data-value'); 103 - if (col.type === 'number') { 104 - val = Number(val); 105 - } 106 - data[col.key] = val; 107 - } 108 - return data; 109 - } 110 - // loads all row data 111 - function loadData() { 112 - var rows = getTableBody().querySelectorAll('tr'), 113 - i; 114 - 115 - for (i = 0; i < rows.length; i += 1) { 116 - rows[i].data = loadRowData(rows[i]); 117 - } 118 - } 119 - // sorts the table using the data for the ith column 120 - function sortByIndex(index, desc) { 121 - var key = cols[index].key, 122 - sorter = function(a, b) { 123 - a = a.data[key]; 124 - b = b.data[key]; 125 - return a < b ? -1 : a > b ? 1 : 0; 126 - }, 127 - finalSorter = sorter, 128 - tableBody = document.querySelector('.coverage-summary tbody'), 129 - rowNodes = tableBody.querySelectorAll('tr'), 130 - rows = [], 131 - i; 132 - 133 - if (desc) { 134 - finalSorter = function(a, b) { 135 - return -1 * sorter(a, b); 136 - }; 137 - } 138 - 139 - for (i = 0; i < rowNodes.length; i += 1) { 140 - rows.push(rowNodes[i]); 141 - tableBody.removeChild(rowNodes[i]); 142 - } 143 - 144 - rows.sort(finalSorter); 145 - 146 - for (i = 0; i < rows.length; i += 1) { 147 - tableBody.appendChild(rows[i]); 148 - } 149 - } 150 - // removes sort indicators for current column being sorted 151 - function removeSortIndicators() { 152 - var col = getNthColumn(currentSort.index), 153 - cls = col.className; 154 - 155 - cls = cls.replace(/ sorted$/, '').replace(/ sorted-desc$/, ''); 156 - col.className = cls; 157 - } 158 - // adds sort indicators for current column being sorted 159 - function addSortIndicators() { 160 - getNthColumn(currentSort.index).className += currentSort.desc 161 - ? ' sorted-desc' 162 - : ' sorted'; 163 - } 164 - // adds event listeners for all sorter widgets 165 - function enableUI() { 166 - var i, 167 - el, 168 - ithSorter = function ithSorter(i) { 169 - var col = cols[i]; 170 - 171 - return function() { 172 - var desc = col.defaultDescSort; 173 - 174 - if (currentSort.index === i) { 175 - desc = !currentSort.desc; 176 - } 177 - sortByIndex(i, desc); 178 - removeSortIndicators(); 179 - currentSort.index = i; 180 - currentSort.desc = desc; 181 - addSortIndicators(); 182 - }; 183 - }; 184 - for (i = 0; i < cols.length; i += 1) { 185 - if (cols[i].sortable) { 186 - // add the click event handler on the th so users 187 - // dont have to click on those tiny arrows 188 - el = getNthColumn(i).querySelector('.sorter').parentElement; 189 - if (el.addEventListener) { 190 - el.addEventListener('click', ithSorter(i)); 191 - } else { 192 - el.attachEvent('onclick', ithSorter(i)); 193 - } 194 - } 195 - } 196 - } 197 - // adds sorting functionality to the UI 198 - return function() { 199 - if (!getTable()) { 200 - return; 201 - } 202 - cols = loadColumns(); 203 - loadData(); 204 - addSearchBox(); 205 - addSortIndicators(); 206 - enableUI(); 207 - }; 208 - })(); 209 - 210 - window.addEventListener('load', addSorting);
+3 -1
biome.json
··· 6 6 "packages/**/*", 7 7 "!**/node_modules", 8 8 "!**/dist", 9 - "!**/build" 9 + "!**/build", 10 + "!**/coverage", 11 + "!**/coverage-unit" 10 12 ], 11 13 "ignoreUnknown": false 12 14 },
+2 -288
package-lock.json
··· 33 33 "react-router-dom": "^7.9.4" 34 34 }, 35 35 "devDependencies": { 36 - "@biomejs/biome": "^1.8.3", 36 + "@biomejs/biome": "^2.2.6", 37 37 "@catppuccin/tailwindcss": "^1.0.0", 38 38 "@cv/biome-config": "0.0.0", 39 39 "@cv/tsconfig": "0.0.0", ··· 48 48 "tailwindcss": "^4.0.0", 49 49 "typescript": "^5.6.3", 50 50 "vite": "^7.1.10" 51 - } 52 - }, 53 - "apps/client/node_modules/@biomejs/biome": { 54 - "version": "1.9.4", 55 - "dev": true, 56 - "hasInstallScript": true, 57 - "license": "MIT OR Apache-2.0", 58 - "bin": { 59 - "biome": "bin/biome" 60 - }, 61 - "engines": { 62 - "node": ">=14.21.3" 63 - }, 64 - "funding": { 65 - "type": "opencollective", 66 - "url": "https://opencollective.com/biome" 67 - }, 68 - "optionalDependencies": { 69 - "@biomejs/cli-darwin-arm64": "1.9.4", 70 - "@biomejs/cli-darwin-x64": "1.9.4", 71 - "@biomejs/cli-linux-arm64": "1.9.4", 72 - "@biomejs/cli-linux-arm64-musl": "1.9.4", 73 - "@biomejs/cli-linux-x64": "1.9.4", 74 - "@biomejs/cli-linux-x64-musl": "1.9.4", 75 - "@biomejs/cli-win32-arm64": "1.9.4", 76 - "@biomejs/cli-win32-x64": "1.9.4" 77 - } 78 - }, 79 - "apps/client/node_modules/@biomejs/cli-darwin-arm64": { 80 - "version": "1.9.4", 81 - "resolved": "https://registry.npmjs.org/@biomejs/cli-darwin-arm64/-/cli-darwin-arm64-1.9.4.tgz", 82 - "integrity": "sha512-bFBsPWrNvkdKrNCYeAp+xo2HecOGPAy9WyNyB/jKnnedgzl4W4Hb9ZMzYNbf8dMCGmUdSavlYHiR01QaYR58cw==", 83 - "cpu": [ 84 - "arm64" 85 - ], 86 - "dev": true, 87 - "license": "MIT OR Apache-2.0", 88 - "optional": true, 89 - "os": [ 90 - "darwin" 91 - ], 92 - "engines": { 93 - "node": ">=14.21.3" 94 - } 95 - }, 96 - "apps/client/node_modules/@biomejs/cli-darwin-x64": { 97 - "version": "1.9.4", 98 - "resolved": "https://registry.npmjs.org/@biomejs/cli-darwin-x64/-/cli-darwin-x64-1.9.4.tgz", 99 - "integrity": "sha512-ngYBh/+bEedqkSevPVhLP4QfVPCpb+4BBe2p7Xs32dBgs7rh9nY2AIYUL6BgLw1JVXV8GlpKmb/hNiuIxfPfZg==", 100 - "cpu": [ 101 - "x64" 102 - ], 103 - "dev": true, 104 - "license": "MIT OR Apache-2.0", 105 - "optional": true, 106 - "os": [ 107 - "darwin" 108 - ], 109 - "engines": { 110 - "node": ">=14.21.3" 111 - } 112 - }, 113 - "apps/client/node_modules/@biomejs/cli-linux-x64": { 114 - "version": "1.9.4", 115 - "resolved": "https://registry.npmjs.org/@biomejs/cli-linux-x64/-/cli-linux-x64-1.9.4.tgz", 116 - "integrity": "sha512-lRCJv/Vi3Vlwmbd6K+oQ0KhLHMAysN8lXoCI7XeHlxaajk06u7G+UsFSO01NAs5iYuWKmVZjmiOzJ0OJmGsMwg==", 117 - "cpu": [ 118 - "x64" 119 - ], 120 - "dev": true, 121 - "license": "MIT OR Apache-2.0", 122 - "optional": true, 123 - "os": [ 124 - "linux" 125 - ], 126 - "engines": { 127 - "node": ">=14.21.3" 128 - } 129 - }, 130 - "apps/client/node_modules/@biomejs/cli-linux-x64-musl": { 131 - "version": "1.9.4", 132 - "resolved": "https://registry.npmjs.org/@biomejs/cli-linux-x64-musl/-/cli-linux-x64-musl-1.9.4.tgz", 133 - "integrity": "sha512-gEhi/jSBhZ2m6wjV530Yy8+fNqG8PAinM3oV7CyO+6c3CEh16Eizm21uHVsyVBEB6RIM8JHIl6AGYCv6Q6Q9Tg==", 134 - "cpu": [ 135 - "x64" 136 - ], 137 - "dev": true, 138 - "license": "MIT OR Apache-2.0", 139 - "optional": true, 140 - "os": [ 141 - "linux" 142 - ], 143 - "engines": { 144 - "node": ">=14.21.3" 145 - } 146 - }, 147 - "apps/client/node_modules/@biomejs/cli-win32-arm64": { 148 - "version": "1.9.4", 149 - "resolved": "https://registry.npmjs.org/@biomejs/cli-win32-arm64/-/cli-win32-arm64-1.9.4.tgz", 150 - "integrity": "sha512-tlbhLk+WXZmgwoIKwHIHEBZUwxml7bRJgk0X2sPyNR3S93cdRq6XulAZRQJ17FYGGzWne0fgrXBKpl7l4M87Hg==", 151 - "cpu": [ 152 - "arm64" 153 - ], 154 - "dev": true, 155 - "license": "MIT OR Apache-2.0", 156 - "optional": true, 157 - "os": [ 158 - "win32" 159 - ], 160 - "engines": { 161 - "node": ">=14.21.3" 162 - } 163 - }, 164 - "apps/client/node_modules/@biomejs/cli-win32-x64": { 165 - "version": "1.9.4", 166 - "resolved": "https://registry.npmjs.org/@biomejs/cli-win32-x64/-/cli-win32-x64-1.9.4.tgz", 167 - "integrity": "sha512-8Y5wMhVIPaWe6jw2H+KlEm4wP/f7EW3810ZLmDlrEEy5KvBsb9ECEfu/kMWD484ijfQ8+nIi0giMgu9g1UAuuA==", 168 - "cpu": [ 169 - "x64" 170 - ], 171 - "dev": true, 172 - "license": "MIT OR Apache-2.0", 173 - "optional": true, 174 - "os": [ 175 - "win32" 176 - ], 177 - "engines": { 178 - "node": ">=14.21.3" 179 51 } 180 52 }, 181 53 "apps/server": { ··· 207 79 "zod": "^3.23.8" 208 80 }, 209 81 "devDependencies": { 210 - "@biomejs/biome": "^1.8.3", 82 + "@biomejs/biome": "^2.2.6", 211 83 "@cv/biome-config": "0.0.0", 212 84 "@cv/tsconfig": "0.0.0", 213 85 "@nestjs/testing": "^10.4.7", ··· 225 97 "tsconfig-paths": "^4.2.0", 226 98 "tslib": "^2.8.0", 227 99 "typescript": "^5.6.3" 228 - } 229 - }, 230 - "apps/server/node_modules/@biomejs/biome": { 231 - "version": "1.9.4", 232 - "dev": true, 233 - "hasInstallScript": true, 234 - "license": "MIT OR Apache-2.0", 235 - "bin": { 236 - "biome": "bin/biome" 237 - }, 238 - "engines": { 239 - "node": ">=14.21.3" 240 - }, 241 - "funding": { 242 - "type": "opencollective", 243 - "url": "https://opencollective.com/biome" 244 - }, 245 - "optionalDependencies": { 246 - "@biomejs/cli-darwin-arm64": "1.9.4", 247 - "@biomejs/cli-darwin-x64": "1.9.4", 248 - "@biomejs/cli-linux-arm64": "1.9.4", 249 - "@biomejs/cli-linux-arm64-musl": "1.9.4", 250 - "@biomejs/cli-linux-x64": "1.9.4", 251 - "@biomejs/cli-linux-x64-musl": "1.9.4", 252 - "@biomejs/cli-win32-arm64": "1.9.4", 253 - "@biomejs/cli-win32-x64": "1.9.4" 254 - } 255 - }, 256 - "apps/server/node_modules/@biomejs/cli-darwin-arm64": { 257 - "version": "1.9.4", 258 - "resolved": "https://registry.npmjs.org/@biomejs/cli-darwin-arm64/-/cli-darwin-arm64-1.9.4.tgz", 259 - "integrity": "sha512-bFBsPWrNvkdKrNCYeAp+xo2HecOGPAy9WyNyB/jKnnedgzl4W4Hb9ZMzYNbf8dMCGmUdSavlYHiR01QaYR58cw==", 260 - "cpu": [ 261 - "arm64" 262 - ], 263 - "dev": true, 264 - "license": "MIT OR Apache-2.0", 265 - "optional": true, 266 - "os": [ 267 - "darwin" 268 - ], 269 - "engines": { 270 - "node": ">=14.21.3" 271 - } 272 - }, 273 - "apps/server/node_modules/@biomejs/cli-darwin-x64": { 274 - "version": "1.9.4", 275 - "resolved": "https://registry.npmjs.org/@biomejs/cli-darwin-x64/-/cli-darwin-x64-1.9.4.tgz", 276 - "integrity": "sha512-ngYBh/+bEedqkSevPVhLP4QfVPCpb+4BBe2p7Xs32dBgs7rh9nY2AIYUL6BgLw1JVXV8GlpKmb/hNiuIxfPfZg==", 277 - "cpu": [ 278 - "x64" 279 - ], 280 - "dev": true, 281 - "license": "MIT OR Apache-2.0", 282 - "optional": true, 283 - "os": [ 284 - "darwin" 285 - ], 286 - "engines": { 287 - "node": ">=14.21.3" 288 - } 289 - }, 290 - "apps/server/node_modules/@biomejs/cli-linux-x64": { 291 - "version": "1.9.4", 292 - "resolved": "https://registry.npmjs.org/@biomejs/cli-linux-x64/-/cli-linux-x64-1.9.4.tgz", 293 - "integrity": "sha512-lRCJv/Vi3Vlwmbd6K+oQ0KhLHMAysN8lXoCI7XeHlxaajk06u7G+UsFSO01NAs5iYuWKmVZjmiOzJ0OJmGsMwg==", 294 - "cpu": [ 295 - "x64" 296 - ], 297 - "dev": true, 298 - "license": "MIT OR Apache-2.0", 299 - "optional": true, 300 - "os": [ 301 - "linux" 302 - ], 303 - "engines": { 304 - "node": ">=14.21.3" 305 - } 306 - }, 307 - "apps/server/node_modules/@biomejs/cli-linux-x64-musl": { 308 - "version": "1.9.4", 309 - "resolved": "https://registry.npmjs.org/@biomejs/cli-linux-x64-musl/-/cli-linux-x64-musl-1.9.4.tgz", 310 - "integrity": "sha512-gEhi/jSBhZ2m6wjV530Yy8+fNqG8PAinM3oV7CyO+6c3CEh16Eizm21uHVsyVBEB6RIM8JHIl6AGYCv6Q6Q9Tg==", 311 - "cpu": [ 312 - "x64" 313 - ], 314 - "dev": true, 315 - "license": "MIT OR Apache-2.0", 316 - "optional": true, 317 - "os": [ 318 - "linux" 319 - ], 320 - "engines": { 321 - "node": ">=14.21.3" 322 - } 323 - }, 324 - "apps/server/node_modules/@biomejs/cli-win32-arm64": { 325 - "version": "1.9.4", 326 - "resolved": "https://registry.npmjs.org/@biomejs/cli-win32-arm64/-/cli-win32-arm64-1.9.4.tgz", 327 - "integrity": "sha512-tlbhLk+WXZmgwoIKwHIHEBZUwxml7bRJgk0X2sPyNR3S93cdRq6XulAZRQJ17FYGGzWne0fgrXBKpl7l4M87Hg==", 328 - "cpu": [ 329 - "arm64" 330 - ], 331 - "dev": true, 332 - "license": "MIT OR Apache-2.0", 333 - "optional": true, 334 - "os": [ 335 - "win32" 336 - ], 337 - "engines": { 338 - "node": ">=14.21.3" 339 - } 340 - }, 341 - "apps/server/node_modules/@biomejs/cli-win32-x64": { 342 - "version": "1.9.4", 343 - "resolved": "https://registry.npmjs.org/@biomejs/cli-win32-x64/-/cli-win32-x64-1.9.4.tgz", 344 - "integrity": "sha512-8Y5wMhVIPaWe6jw2H+KlEm4wP/f7EW3810ZLmDlrEEy5KvBsb9ECEfu/kMWD484ijfQ8+nIi0giMgu9g1UAuuA==", 345 - "cpu": [ 346 - "x64" 347 - ], 348 - "dev": true, 349 - "license": "MIT OR Apache-2.0", 350 - "optional": true, 351 - "os": [ 352 - "win32" 353 - ], 354 - "engines": { 355 - "node": ">=14.21.3" 356 100 } 357 101 }, 358 102 "node_modules/@alloc/quick-lru": { ··· 1758 1502 "optional": true, 1759 1503 "os": [ 1760 1504 "darwin" 1761 - ], 1762 - "engines": { 1763 - "node": ">=14.21.3" 1764 - } 1765 - }, 1766 - "node_modules/@biomejs/cli-linux-arm64": { 1767 - "version": "1.9.4", 1768 - "cpu": [ 1769 - "arm64" 1770 - ], 1771 - "dev": true, 1772 - "license": "MIT OR Apache-2.0", 1773 - "optional": true, 1774 - "os": [ 1775 - "linux" 1776 - ], 1777 - "engines": { 1778 - "node": ">=14.21.3" 1779 - } 1780 - }, 1781 - "node_modules/@biomejs/cli-linux-arm64-musl": { 1782 - "version": "1.9.4", 1783 - "cpu": [ 1784 - "arm64" 1785 - ], 1786 - "dev": true, 1787 - "license": "MIT OR Apache-2.0", 1788 - "optional": true, 1789 - "os": [ 1790 - "linux" 1791 1505 ], 1792 1506 "engines": { 1793 1507 "node": ">=14.21.3"