From fc32daf884f498ce6d05bc0a8416b80d7e884c7e Mon Sep 17 00:00:00 2001 From: Jamie Magee Date: Tue, 14 Apr 2026 19:51:08 -0700 Subject: [PATCH 1/4] enable strict sub-flags in test tsconfig Enable strictFunctionTypes, noImplicitThis, alwaysStrict, strictBindCallApply, and useUnknownInCatchVariables. Fix 19 errors. --- providers/queueing/azureStorageQueue.ts | 35 +++++++++++-------- test/providers/caching/redis.ts | 4 +-- test/providers/store/abstractFileStore.ts | 2 +- test/providers/store/azblobAttachment.ts | 2 +- test/providers/store/azblobDefinition.ts | 2 +- test/providers/store/fileAttachment.ts | 2 +- test/providers/store/fileDefintion.ts | 2 +- test/providers/store/fileHarvest.ts | 2 +- test/providers/store/mongoDefinition.ts | 2 +- .../summary/scancode/legacy-summarizer.mts | 2 +- .../summary/scancode/new-summarizer.mts | 2 +- test/summary/licensee.ts | 2 +- test/summary/reuse.ts | 2 +- test/tsconfig.json | 7 +++- 14 files changed, 39 insertions(+), 29 deletions(-) diff --git a/providers/queueing/azureStorageQueue.ts b/providers/queueing/azureStorageQueue.ts index 30d0f936..0faf0b55 100644 --- a/providers/queueing/azureStorageQueue.ts +++ b/providers/queueing/azureStorageQueue.ts @@ -5,7 +5,7 @@ import { promisify } from 'node:util' import azure from 'azure-storage' import type { Logger } from '../logging/index.js' import logger from '../logging/logger.ts' -import type { DequeuedMessage, IQueue } from './index.js' +import type { DequeuedMessage, IQueue, QueueMessage } from './index.js' export interface AzureStorageQueueOptions { connectionString: string @@ -50,9 +50,12 @@ class AzureStorageQueue implements IQueue { return null } if (message.dequeueCount <= 5) { - return { original: message, data: JSON.parse(Buffer.from(message.messageText, 'base64').toString('utf8')) } + return { + original: message as unknown as QueueMessage, + data: JSON.parse(Buffer.from(message.messageText, 'base64').toString('utf8')) + } } - await this.delete({ original: message }) + await this.delete({ original: message as unknown as QueueMessage }) return this.dequeue() } @@ -60,24 +63,26 @@ class AzureStorageQueue implements IQueue { * Similar to dequeue() but returns multiple messages to improve performance */ async dequeueMultiple(): Promise { - const messages = await promisify(this.queueService.getMessages).bind(this.queueService)( - this.options.queueName, - this.options.dequeueOptions - ) + const boundGetMessages = promisify(this.queueService.getMessages).bind(this.queueService) as ( + queueName: string, + options?: Record + ) => Promise + const messages = await boundGetMessages(this.options.queueName, this.options.dequeueOptions) if (!messages || messages.length === 0) { return [] } - for (const i in messages) { - if (messages[i].dequeueCount <= 5) { - messages[i] = { - original: messages[i], - data: JSON.parse(Buffer.from(messages[i].messageText, 'base64').toString('utf8')) - } + const result: DequeuedMessage[] = [] + for (const msg of messages) { + if (msg.dequeueCount <= 5) { + result.push({ + original: msg, + data: JSON.parse(Buffer.from(msg.messageText!, 'base64').toString('utf8')) + }) } else { - await this.delete({ original: messages[i] }) + await this.delete({ original: msg }) } } - return messages + return result } /** diff --git a/test/providers/caching/redis.ts b/test/providers/caching/redis.ts index ca5fae62..4b7deb15 100644 --- a/test/providers/caching/redis.ts +++ b/test/providers/caching/redis.ts @@ -73,7 +73,7 @@ describe('Redis Cache', () => { try { await cache.initialize() } catch (error) { - assert.strictEqual(error.message, 'Connection failed') + assert.strictEqual((error as Error).message, 'Connection failed') } }) @@ -95,7 +95,7 @@ describe('Redis Cache', () => { await cache.initialize() assert.fail('Expected error was not thrown') } catch (error) { - assert.strictEqual(error.message, 'Connection failed') + assert.strictEqual((error as Error).message, 'Connection failed') } // Second call to initialize will succeed await cache.initialize() diff --git a/test/providers/store/abstractFileStore.ts b/test/providers/store/abstractFileStore.ts index 96c826a3..ab81307d 100644 --- a/test/providers/store/abstractFileStore.ts +++ b/test/providers/store/abstractFileStore.ts @@ -66,7 +66,7 @@ describe('AbstractFileStore', () => { await fileStore.list(new EntityCoordinates('npm', 'npmjs', null, 'error', '0.0'), data => data) throw new Error('should have thrown error') } catch (error) { - expect(error.message).to.eq('test error') + expect((error as Error).message).to.eq('test error') } }) diff --git a/test/providers/store/azblobAttachment.ts b/test/providers/store/azblobAttachment.ts index 41bbf4f9..8331b7b6 100644 --- a/test/providers/store/azblobAttachment.ts +++ b/test/providers/store/azblobAttachment.ts @@ -12,7 +12,7 @@ describe('AzureAttachmentStore list definitions', () => { await store.get('error') throw new Error('should have thrown error') } catch (error) { - expect(error.message).to.eq('test error') + expect((error as Error).message).to.eq('test error') } }) diff --git a/test/providers/store/azblobDefinition.ts b/test/providers/store/azblobDefinition.ts index 0e4995e0..8425cb3e 100644 --- a/test/providers/store/azblobDefinition.ts +++ b/test/providers/store/azblobDefinition.ts @@ -17,7 +17,7 @@ describe('azblob Definition store', () => { await store.list(EntityCoordinates.fromString('npm/npmjs/-/error/4.6.0')) throw new Error('should have thrown error') } catch (error) { - expect(error.message).to.eq('test error') + expect((error as Error).message).to.eq('test error') } }) diff --git a/test/providers/store/fileAttachment.ts b/test/providers/store/fileAttachment.ts index 18eb21ac..3a168197 100644 --- a/test/providers/store/fileAttachment.ts +++ b/test/providers/store/fileAttachment.ts @@ -43,7 +43,7 @@ describe('FileAttachmentStore list definitions', () => { await fileStore.get('error') throw new Error('should have thrown error') } catch (error) { - expect(error.message).to.eq('test error') + expect((error as Error).message).to.eq('test error') } }) diff --git a/test/providers/store/fileDefintion.ts b/test/providers/store/fileDefintion.ts index 82e35b70..03776a5d 100644 --- a/test/providers/store/fileDefintion.ts +++ b/test/providers/store/fileDefintion.ts @@ -44,7 +44,7 @@ describe('FileDefinitionStore list definitions', () => { await fileStore.list(new EntityCoordinates('npm', 'npmjs', null, 'error', '0.0')) throw new Error('should have thrown error') } catch (error) { - expect(error.message).to.eq('test error') + expect((error as Error).message).to.eq('test error') } }) diff --git a/test/providers/store/fileHarvest.ts b/test/providers/store/fileHarvest.ts index e55bbcfb..f5b9f947 100644 --- a/test/providers/store/fileHarvest.ts +++ b/test/providers/store/fileHarvest.ts @@ -50,7 +50,7 @@ describe('FileHarvestStore list tool results', () => { await fileStore.list(new EntityCoordinates('npm', 'npmjs', null, 'error', '0.0')) throw new Error('should have thrown error') } catch (error) { - expect(error.message).to.eq('test error') + expect((error as Error).message).to.eq('test error') } }) diff --git a/test/providers/store/mongoDefinition.ts b/test/providers/store/mongoDefinition.ts index 023f90de..1838053d 100644 --- a/test/providers/store/mongoDefinition.ts +++ b/test/providers/store/mongoDefinition.ts @@ -26,7 +26,7 @@ describe('Mongo Definition store', () => { await store.list(EntityCoordinates.fromString('npm/npmjs/-/error/4.6.0')) throw new Error('should have thrown error') } catch (error) { - expect(error.message).to.eq('test error') + expect((error as Error).message).to.eq('test error') } }) diff --git a/test/providers/summary/scancode/legacy-summarizer.mts b/test/providers/summary/scancode/legacy-summarizer.mts index 4b25389f..d13d3782 100644 --- a/test/providers/summary/scancode/legacy-summarizer.mts +++ b/test/providers/summary/scancode/legacy-summarizer.mts @@ -127,7 +127,7 @@ describe('ScanCodeLegacySummarizer basic compatability', () => { try { summarizer.summarize(coordinates, harvestData) } catch (error) { - expect(error.message).to.eq(`Invalid version of ScanCode: ${version}`) + expect((error as Error).message).to.eq(`Invalid version of ScanCode: ${version}`) } }) diff --git a/test/providers/summary/scancode/new-summarizer.mts b/test/providers/summary/scancode/new-summarizer.mts index e1346cd1..21090b76 100644 --- a/test/providers/summary/scancode/new-summarizer.mts +++ b/test/providers/summary/scancode/new-summarizer.mts @@ -129,7 +129,7 @@ describe('ScanCodeNewSummarizer basic compatability', () => { try { summarizer.summarize(coordinates, harvestData) } catch (error) { - expect(error.message).to.eq(`Invalid version of ScanCode: ${version}`) + expect((error as Error).message).to.eq(`Invalid version of ScanCode: ${version}`) } }) diff --git a/test/summary/licensee.ts b/test/summary/licensee.ts index 8826cc53..80987934 100644 --- a/test/summary/licensee.ts +++ b/test/summary/licensee.ts @@ -70,7 +70,7 @@ describe('LicenseeSummarizer', () => { summarizer.summarize(null, {}) assert.equal(true, false) } catch (error) { - assert.equal(error.message, 'Invalid Licensee data') + assert.equal((error as Error).message, 'Invalid Licensee data') } }) }) diff --git a/test/summary/reuse.ts b/test/summary/reuse.ts index 305db546..f41abfa9 100644 --- a/test/summary/reuse.ts +++ b/test/summary/reuse.ts @@ -98,7 +98,7 @@ describe('FsfeReuseSummarizer', () => { summarizer.summarize(null, {}) assert.equal(true, false) } catch (error) { - assert.equal(error.message, 'Invalid REUSE data') + assert.equal((error as Error).message, 'Invalid REUSE data') } }) }) diff --git a/test/tsconfig.json b/test/tsconfig.json index 053dce23..3eb96b05 100644 --- a/test/tsconfig.json +++ b/test/tsconfig.json @@ -10,7 +10,12 @@ "noImplicitReturns": true, "noFallthroughCasesInSwitch": true, "noUncheckedIndexedAccess": false, - "noImplicitOverride": true + "noImplicitOverride": true, + "strictFunctionTypes": true, + "noImplicitThis": true, + "alwaysStrict": true, + "strictBindCallApply": true, + "useUnknownInCatchVariables": true }, "include": [ "../types/**/*", From c1274e9d47f686427b8c92f49e606dba246a6870 Mon Sep 17 00:00:00 2001 From: Jamie Magee Date: Tue, 14 Apr 2026 19:57:11 -0700 Subject: [PATCH 2/4] fix strictNullChecks errors in test/summary/ Add non-null assertions to test files for: - EntityCoordinates.fromString() return values in setup functions - summary.described, summary.licensed, summary.files property access - Nested properties: sourceLocation, urls, attributions, natures --- test/summary/clearlyDefined.ts | 206 ++++++++++++++++----------------- test/summary/fossology.ts | 2 +- test/summary/scancode.ts | 90 +++++++------- 3 files changed, 149 insertions(+), 149 deletions(-) diff --git a/test/summary/clearlyDefined.ts b/test/summary/clearlyDefined.ts index ec3c6a6f..a0e7e1d6 100644 --- a/test/summary/clearlyDefined.ts +++ b/test/summary/clearlyDefined.ts @@ -16,7 +16,7 @@ describe('ClearlyDefined Maven summarizer', () => { const summary = Summarizer().summarize(coordinates, harvested) validate(summary) expect(summary.licensed).to.be.undefined - expect(summary.described.releaseDate).to.eq('2018-03-06') + expect(summary.described!.releaseDate).to.eq('2018-03-06') }) it('handles licenseUrl', () => { @@ -25,8 +25,8 @@ describe('ClearlyDefined Maven summarizer', () => { }) const summary = Summarizer().summarize(coordinates, harvested) validate(summary) - expect(summary.licensed.declared).to.eq('MIT') - expect(summary.described.releaseDate).to.eq('2018-03-06') + expect(summary.licensed!.declared).to.eq('MIT') + expect(summary.described!.releaseDate).to.eq('2018-03-06') }) it('handles licenseName', () => { @@ -35,8 +35,8 @@ describe('ClearlyDefined Maven summarizer', () => { }) const summary = Summarizer().summarize(coordinates, harvested) validate(summary) - expect(summary.licensed.declared).to.eq('MIT') - expect(summary.described.releaseDate).to.eq('2018-03-06') + expect(summary.licensed!.declared).to.eq('MIT') + expect(summary.described!.releaseDate).to.eq('2018-03-06') }) it('handles missing license of projectSummary', () => { @@ -44,7 +44,7 @@ describe('ClearlyDefined Maven summarizer', () => { const summary = Summarizer().summarize(coordinates, harvested) validate(summary) expect(summary.licensed).to.be.undefined - expect(summary.described.releaseDate).to.eq('2018-03-06') + expect(summary.described!.releaseDate).to.eq('2018-03-06') }) it('handles projectSummaryLicenses with just url', () => { @@ -53,8 +53,8 @@ describe('ClearlyDefined Maven summarizer', () => { }) const summary = Summarizer().summarize(coordinates, harvested) validate(summary) - expect(summary.licensed.declared).to.eq('MIT') - expect(summary.described.releaseDate).to.eq('2018-03-06') + expect(summary.licensed!.declared).to.eq('MIT') + expect(summary.described!.releaseDate).to.eq('2018-03-06') }) it('handles data with source location', () => { @@ -62,8 +62,8 @@ describe('ClearlyDefined Maven summarizer', () => { const summary = Summarizer().summarize(coordinates, harvested) validate(summary) expect(summary.licensed).to.be.undefined - expect(summary.described.releaseDate).to.eq('2018-03-06') - expect(summary.described.sourceLocation.url).to.eq(getSourceUrl()) + expect(summary.described!.releaseDate).to.eq('2018-03-06') + expect(summary.described!.sourceLocation!.url).to.eq(getSourceUrl()) }) it('handles no data', () => { @@ -71,12 +71,12 @@ describe('ClearlyDefined Maven summarizer', () => { const summary = Summarizer().summarize(coordinates, harvested) validate(summary) expect(summary.licensed).to.be.undefined - expect(summary.described.urls).not.to.be.undefined + expect(summary.described!.urls).not.to.be.undefined }) }) function setupMaven(releaseDate?, sourceInfo?, projectSummary?) { - const coordinates = EntityCoordinates.fromString('maven/mavencentral/io.clearlydefined/test/1.0') + const coordinates = EntityCoordinates.fromString('maven/mavencentral/io.clearlydefined/test/1.0')! const harvested: Record = {} setIfValue(harvested, 'releaseDate', releaseDate) setIfValue(harvested, 'manifest.summary.project', projectSummary) @@ -92,7 +92,7 @@ describe('ClearlyDefined NuGet summarizer', () => { const summary = Summarizer().summarize(coordinates, harvested) validate(summary) expect(summary.licensed).to.be.undefined - expect(summary.described.releaseDate).to.eq('2018-03-06') + expect(summary.described!.releaseDate).to.eq('2018-03-06') }) it('handles data with source location', () => { @@ -100,8 +100,8 @@ describe('ClearlyDefined NuGet summarizer', () => { const summary = Summarizer().summarize(coordinates, harvested) validate(summary) expect(summary.licensed).to.be.undefined - expect(summary.described.releaseDate).to.eq('2018-03-06') - expect(summary.described.sourceLocation.url).to.eq(getSourceUrl()) + expect(summary.described!.releaseDate).to.eq('2018-03-06') + expect(summary.described!.sourceLocation!.url).to.eq(getSourceUrl()) }) it('handles no data', () => { @@ -109,7 +109,7 @@ describe('ClearlyDefined NuGet summarizer', () => { const summary = Summarizer().summarize(coordinates, harvested) validate(summary) expect(summary.licensed).to.be.undefined - expect(summary.described.urls).not.to.be.undefined + expect(summary.described!.urls).not.to.be.undefined }) it('includes files from manifest', () => { @@ -131,7 +131,7 @@ describe('ClearlyDefined NuGet summarizer', () => { }) function setupNuGet({ releaseDate, sourceInfo, packageEntries }: any = {}) { - const coordinates = EntityCoordinates.fromString('nuget/nuget/-/test/1.0') + const coordinates = EntityCoordinates.fromString('nuget/nuget/-/test/1.0')! const harvested: Record = {} setIfValue(harvested, 'releaseDate', releaseDate) setIfValue(harvested, 'manifest.packageEntries', packageEntries) @@ -147,7 +147,7 @@ describe('ClearlyDefined Source Archive summarizer', () => { const summary = Summarizer().summarize(coordinates, harvested) validate(summary) expect(summary.licensed).to.be.undefined - expect(summary.described.releaseDate).to.eq('2018-03-06') + expect(summary.described!.releaseDate).to.eq('2018-03-06') }) it('handles data with source location', () => { @@ -155,8 +155,8 @@ describe('ClearlyDefined Source Archive summarizer', () => { const summary = Summarizer().summarize(coordinates, harvested) validate(summary) expect(summary.licensed).to.be.undefined - expect(summary.described.releaseDate).to.eq('2018-03-06') - expect(summary.described.sourceLocation.url).to.eq(getSourceUrl()) + expect(summary.described!.releaseDate).to.eq('2018-03-06') + expect(summary.described!.sourceLocation!.url).to.eq(getSourceUrl()) }) it('handles no data', () => { @@ -164,12 +164,12 @@ describe('ClearlyDefined Source Archive summarizer', () => { const summary = Summarizer().summarize(coordinates, harvested) validate(summary) expect(summary.licensed).to.be.undefined - expect(summary.described.urls).not.to.be.undefined + expect(summary.described!.urls).not.to.be.undefined }) }) function setupSourceArchive(releaseDate?, sourceInfo?) { - const coordinates = EntityCoordinates.fromString('sourcearchive/github/-/test/1.0') + const coordinates = EntityCoordinates.fromString('sourcearchive/github/-/test/1.0')! const harvested: Record = {} setIfValue(harvested, 'releaseDate', releaseDate) if (sourceInfo) { @@ -186,10 +186,10 @@ describe('ClearlyDefined NPM summarizer', () => { }) const summary = Summarizer().summarize(coordinates, harvested) validate(summary) - expect(summary.licensed.declared).to.eq('MIT') - expect(summary.described.releaseDate).to.eq('2018-03-06') - expect(summary.described.issueTracker).to.eq('http://bugs') - expect(summary.described.projectWebsite).to.eq('http://homepage') + expect(summary.licensed!.declared).to.eq('MIT') + expect(summary.described!.releaseDate).to.eq('2018-03-06') + expect(summary.described!.issueTracker).to.eq('http://bugs') + expect(summary.described!.projectWebsite).to.eq('http://homepage') }) it('handles with all the data and a license array of one string', () => { @@ -199,10 +199,10 @@ describe('ClearlyDefined NPM summarizer', () => { }) const summary = Summarizer().summarize(coordinates, harvested) validate(summary) - expect(summary.licensed.declared).to.eq('MIT') - expect(summary.described.releaseDate).to.eq('2018-03-06') - expect(summary.described.issueTracker).to.eq('http://bugs') - expect(summary.described.projectWebsite).to.eq('http://homepage') + expect(summary.licensed!.declared).to.eq('MIT') + expect(summary.described!.releaseDate).to.eq('2018-03-06') + expect(summary.described!.issueTracker).to.eq('http://bugs') + expect(summary.described!.projectWebsite).to.eq('http://homepage') }) it('handles with all the data and a license array of strings', () => { @@ -212,26 +212,26 @@ describe('ClearlyDefined NPM summarizer', () => { }) const summary = Summarizer().summarize(coordinates, harvested) validate(summary) - expect(summary.licensed.declared).to.eq('MIT AND Apache-2.0') - expect(summary.described.releaseDate).to.eq('2018-03-06') - expect(summary.described.issueTracker).to.eq('http://bugs') - expect(summary.described.projectWebsite).to.eq('http://homepage') + expect(summary.licensed!.declared).to.eq('MIT AND Apache-2.0') + expect(summary.described!.releaseDate).to.eq('2018-03-06') + expect(summary.described!.issueTracker).to.eq('http://bugs') + expect(summary.described!.projectWebsite).to.eq('http://homepage') }) it('handles a license as an object', () => { const { coordinates, harvested } = setupNpm(null, { type: 'MIT' }) const summary = Summarizer().summarize(coordinates, harvested) validate(summary) - expect(summary.licensed.declared).to.eq('MIT') - expect(summary.described.urls).not.to.be.undefined + expect(summary.licensed!.declared).to.eq('MIT') + expect(summary.described!.urls).not.to.be.undefined }) it('handles a license as an object with an array of strings ', () => { const { coordinates, harvested } = setupNpm(null, { type: ['MIT', 'Apache-2.0'] }) const summary = Summarizer().summarize(coordinates, harvested) validate(summary) - expect(summary.licensed.declared).to.eq('MIT AND Apache-2.0') - expect(summary.described.urls).not.to.be.undefined + expect(summary.licensed!.declared).to.eq('MIT AND Apache-2.0') + expect(summary.described!.urls).not.to.be.undefined }) it('handles data with source location', () => { @@ -239,8 +239,8 @@ describe('ClearlyDefined NPM summarizer', () => { const summary = Summarizer().summarize(coordinates, harvested) validate(summary) expect(summary.licensed).to.be.undefined - expect(summary.described.releaseDate).to.eq('2018-03-06') - expect(summary.described.sourceLocation.url).to.eq(getSourceUrl()) + expect(summary.described!.releaseDate).to.eq('2018-03-06') + expect(summary.described!.sourceLocation!.url).to.eq(getSourceUrl()) }) it('handles no data', () => { @@ -248,7 +248,7 @@ describe('ClearlyDefined NPM summarizer', () => { const summary = Summarizer().summarize(coordinates, harvested) validate(summary) expect(summary.licensed).to.be.undefined - expect(summary.described.urls).not.to.be.undefined + expect(summary.described!.urls).not.to.be.undefined }) it('handles only releaseDate', () => { @@ -256,9 +256,9 @@ describe('ClearlyDefined NPM summarizer', () => { const summary = Summarizer().summarize(coordinates, harvested) validate(summary) expect(summary.licensed).to.be.undefined - expect(summary.described.releaseDate).to.eq('2018-03-06') - expect(summary.described.issueTracker).to.be.undefined - expect(summary.described.projectWebsite).to.be.undefined + expect(summary.described!.releaseDate).to.eq('2018-03-06') + expect(summary.described!.issueTracker).to.be.undefined + expect(summary.described!.projectWebsite).to.be.undefined }) it('handles string issueTracker', () => { @@ -266,9 +266,9 @@ describe('ClearlyDefined NPM summarizer', () => { const summary = Summarizer().summarize(coordinates, harvested) validate(summary) expect(summary.licensed).to.be.undefined - expect(summary.described.releaseDate).to.be.undefined - expect(summary.described.issueTracker).to.eq('http://bugs') - expect(summary.described.projectWebsite).to.be.undefined + expect(summary.described!.releaseDate).to.be.undefined + expect(summary.described!.issueTracker).to.eq('http://bugs') + expect(summary.described!.projectWebsite).to.be.undefined }) it('handles non url string issueTracker', () => { @@ -276,7 +276,7 @@ describe('ClearlyDefined NPM summarizer', () => { const summary = Summarizer().summarize(coordinates, harvested) validate(summary) expect(summary.licensed).to.be.undefined - expect(summary.described.urls).not.to.be.undefined + expect(summary.described!.urls).not.to.be.undefined }) }) @@ -290,7 +290,7 @@ function setupNpm(releaseDate?, license?, homepage?, bugs?, sourceInfo?) { if (sourceInfo) { harvested.sourceInfo = createSourceLocation(sourceInfo) } - const coordinates = EntityCoordinates.fromString('npm/npmjs/-/test/1.0') + const coordinates = EntityCoordinates.fromString('npm/npmjs/-/test/1.0')! return { coordinates, harvested } } @@ -299,29 +299,29 @@ describe('ClearlyDefined Gem summarizer', () => { const { coordinates, harvested } = setupGem('2018-03-06T11:38:10.284Z', ['MIT']) const summary = Summarizer().summarize(coordinates, harvested) validate(summary) - expect(summary.licensed.declared).to.eq('MIT') - expect(summary.described.releaseDate).to.eq('2018-03-06') + expect(summary.licensed!.declared).to.eq('MIT') + expect(summary.described!.releaseDate).to.eq('2018-03-06') }) it('handles multiple licenses', () => { const { coordinates, harvested } = setupGem('2018-03-06T11:38:10.284Z', ['MIT', 'BSD-2-Clause']) const summary = Summarizer().summarize(coordinates, harvested) validate(summary) - expect(summary.licensed.declared).to.eq('MIT OR BSD-2-Clause') + expect(summary.licensed!.declared).to.eq('MIT OR BSD-2-Clause') }) it('normalizes multiple licenses', () => { const { coordinates, harvested } = setupGem('2018-03-06T11:38:10.284Z', ['MIT', 'JUNK']) const summary = Summarizer().summarize(coordinates, harvested) validate(summary) - expect(summary.licensed.declared).to.eq('MIT OR NOASSERTION') + expect(summary.licensed!.declared).to.eq('MIT OR NOASSERTION') }) it('handles singular license', () => { const { coordinates, harvested } = setupGem('2018-03-06T11:38:10.284Z', 'MIT') const summary = Summarizer().summarize(coordinates, harvested) validate(summary) - expect(summary.licensed.declared).to.eq('MIT') + expect(summary.licensed!.declared).to.eq('MIT') }) it('handles data with source location', () => { @@ -329,8 +329,8 @@ describe('ClearlyDefined Gem summarizer', () => { const summary = Summarizer().summarize(coordinates, harvested) validate(summary) expect(summary.licensed).to.be.undefined - expect(summary.described.releaseDate).to.eq('2018-03-06') - expect(summary.described.sourceLocation.url).to.eq(getSourceUrl()) + expect(summary.described!.releaseDate).to.eq('2018-03-06') + expect(summary.described!.sourceLocation!.url).to.eq(getSourceUrl()) }) it('handles no data', () => { @@ -338,12 +338,12 @@ describe('ClearlyDefined Gem summarizer', () => { const summary = Summarizer().summarize(coordinates, harvested) validate(summary) expect(summary.licensed).to.be.undefined - expect(summary.described.urls).not.to.be.undefined + expect(summary.described!.urls).not.to.be.undefined }) }) function setupGem(releaseDate?, licenses?, sourceInfo?) { - const coordinates = EntityCoordinates.fromString('gem/rubygems/-/test/1.0') + const coordinates = EntityCoordinates.fromString('gem/rubygems/-/test/1.0')! const harvested: Record = {} setIfValue(harvested, 'releaseDate', releaseDate) if (typeof licenses === 'string') { @@ -362,8 +362,8 @@ describe('ClearlyDefined Pypi summarizer', () => { const { coordinates, harvested } = setupPypi('2018-03-06T11:38:10.284Z', 'MIT') const summary = Summarizer().summarize(coordinates, harvested) validate(summary) - expect(summary.licensed.declared).to.eq('MIT') - expect(summary.described.releaseDate).to.eq('2018-03-06') + expect(summary.licensed!.declared).to.eq('MIT') + expect(summary.described!.releaseDate).to.eq('2018-03-06') }) it('handles data with source location', () => { @@ -371,8 +371,8 @@ describe('ClearlyDefined Pypi summarizer', () => { const summary = Summarizer().summarize(coordinates, harvested) validate(summary) expect(summary.licensed).to.be.undefined - expect(summary.described.releaseDate).to.eq('2018-03-06') - expect(summary.described.sourceLocation.url).to.eq(getSourceUrl()) + expect(summary.described!.releaseDate).to.eq('2018-03-06') + expect(summary.described!.sourceLocation!.url).to.eq(getSourceUrl()) }) it('handles no data', () => { @@ -380,12 +380,12 @@ describe('ClearlyDefined Pypi summarizer', () => { const summary = Summarizer().summarize(coordinates, harvested) validate(summary) expect(summary.licensed).to.be.undefined - expect(summary.described.urls).not.to.be.undefined + expect(summary.described!.urls).not.to.be.undefined }) }) function setupPypi(releaseDate?, license?, sourceInfo?) { - const coordinates = EntityCoordinates.fromString('pypi/pypi/-/test/1.0') + const coordinates = EntityCoordinates.fromString('pypi/pypi/-/test/1.0')! const harvested: Record = {} setIfValue(harvested, 'releaseDate', releaseDate) setIfValue(harvested, 'declaredLicense', license) @@ -403,23 +403,23 @@ describe('ClearlyDefined CocoaPod summarizer', () => { const { coordinates, harvested } = setupCocoaPod('MIT', '2018-03-06T11:38:10.284Z', 'https://clearlydefined.com') const summary = Summarizer().summarize(coordinates, harvested) validate(summary) - expect(summary.licensed.declared).to.eq('MIT') - expect(summary.described.releaseDate).to.eq('2018-03-06') - expect(summary.described.projectWebsite).to.eq('https://clearlydefined.com') + expect(summary.licensed!.declared).to.eq('MIT') + expect(summary.described!.releaseDate).to.eq('2018-03-06') + expect(summary.described!.projectWebsite).to.eq('https://clearlydefined.com') }) it('handles license type', () => { const { coordinates, harvested } = setupCocoaPod({ type: 'MIT' }) const summary = Summarizer().summarize(coordinates, harvested) validate(summary) - expect(summary.licensed.declared).to.eq('MIT') + expect(summary.licensed!.declared).to.eq('MIT') }) it('Sets noassertion for license', () => { const { coordinates, harvested } = setupCocoaPod({ type: 'Commercial' }) const summary = Summarizer().summarize(coordinates, harvested) validate(summary) - expect(summary.licensed.declared).to.eq('NOASSERTION') + expect(summary.licensed!.declared).to.eq('NOASSERTION') }) it('handles no data', () => { @@ -427,12 +427,12 @@ describe('ClearlyDefined CocoaPod summarizer', () => { const summary = Summarizer().summarize(coordinates, harvested) validate(summary) expect(summary.licensed).to.be.undefined - expect(summary.described.urls).not.to.be.undefined + expect(summary.described!.urls).not.to.be.undefined }) }) function setupCocoaPod(license?, releaseDate?, homepage?) { - const coordinates = EntityCoordinates.fromString('pod/cocoapods/-/test/1.0.0') + const coordinates = EntityCoordinates.fromString('pod/cocoapods/-/test/1.0.0')! const harvested: Record = {} setIfValue(harvested, 'registryData.license', license) setIfValue(harvested, 'releaseDate', releaseDate) @@ -447,9 +447,9 @@ describe('ClearlyDefined PHP composer summarizer', () => { const summary = Summarizer().summarize(coordinates, harvested) validate(summary) - expect(summary.licensed.declared).to.eq('MIT') - expect(summary.described.releaseDate).to.eq('2018-03-06') - expect(summary.described.projectWebsite).to.eq('http://homepage') + expect(summary.licensed!.declared).to.eq('MIT') + expect(summary.described!.releaseDate).to.eq('2018-03-06') + expect(summary.described!.projectWebsite).to.eq('http://homepage') }) it('handles with all the data and a single license string', () => { @@ -457,9 +457,9 @@ describe('ClearlyDefined PHP composer summarizer', () => { const summary = Summarizer().summarize(coordinates, harvested) validate(summary) - expect(summary.licensed.declared).to.eq('MIT') - expect(summary.described.releaseDate).to.eq('2018-03-06') - expect(summary.described.projectWebsite).to.eq('http://homepage') + expect(summary.licensed!.declared).to.eq('MIT') + expect(summary.described!.releaseDate).to.eq('2018-03-06') + expect(summary.described!.projectWebsite).to.eq('http://homepage') }) it('handles with all the data and a disjunctive license array', () => { @@ -472,9 +472,9 @@ describe('ClearlyDefined PHP composer summarizer', () => { const summary = Summarizer().summarize(coordinates, harvested) validate(summary) - expect(summary.licensed.declared).to.eq('MIT OR Apache-2.0') - expect(summary.described.releaseDate).to.eq('2018-03-06') - expect(summary.described.projectWebsite).to.eq('http://homepage') + expect(summary.licensed!.declared).to.eq('MIT OR Apache-2.0') + expect(summary.described!.releaseDate).to.eq('2018-03-06') + expect(summary.described!.projectWebsite).to.eq('http://homepage') }) it('handles no data', () => { @@ -482,7 +482,7 @@ describe('ClearlyDefined PHP composer summarizer', () => { const summary = Summarizer().summarize(coordinates, harvested) validate(summary) expect(summary.licensed).to.be.undefined - expect(summary.described.urls).not.to.be.undefined + expect(summary.described!.urls).not.to.be.undefined }) it('handles only releaseDate', () => { @@ -490,9 +490,9 @@ describe('ClearlyDefined PHP composer summarizer', () => { const summary = Summarizer().summarize(coordinates, harvested) validate(summary) expect(summary.licensed).to.be.undefined - expect(summary.described.releaseDate).to.eq('2018-03-06') - expect(summary.described.issueTracker).to.be.undefined - expect(summary.described.projectWebsite).to.be.undefined + expect(summary.described!.releaseDate).to.eq('2018-03-06') + expect(summary.described!.issueTracker).to.be.undefined + expect(summary.described!.projectWebsite).to.be.undefined }) }) @@ -503,7 +503,7 @@ function setupComposer(releaseDate?, version?, license?, homepage?) { setIfValue(registryData, 'manifest.license', license) setIfValue(registryData, 'manifest.homepage', homepage) const harvested = { registryData } - const coordinates = EntityCoordinates.fromString('composer/packagist/vendor/test/1.0.0') + const coordinates = EntityCoordinates.fromString('composer/packagist/vendor/test/1.0.0')! return { coordinates, harvested } } @@ -591,12 +591,12 @@ describe('ClearlyDefined Debian summarizer', () => { const summary = Summarizer().summarize(coordinates, harvested) const registryUrl = 'http://ftp.debian.org/debian/pool/main/0/0ad' validate(summary) - expect(summary.described.releaseDate).to.eq('2018-03-06') - expect(summary.described.urls.registry).to.eq(registryUrl) - expect(summary.described.urls.version).to.eq(registryUrl) - expect(summary.described.urls.download).to.eq('http://ftp.debian.org/debian/pool/main/0/0ad/0ad_0.0.17-1_i386.deb') - expect(summary.described.sourceLocation.url).to.eq(registryUrl) - expect(summary.licensed.declared).to.eq( + expect(summary.described!.releaseDate).to.eq('2018-03-06') + expect(summary.described!.urls!.registry).to.eq(registryUrl) + expect(summary.described!.urls!.version).to.eq(registryUrl) + expect(summary.described!.urls!.download).to.eq('http://ftp.debian.org/debian/pool/main/0/0ad/0ad_0.0.17-1_i386.deb') + expect(summary.described!.sourceLocation!.url).to.eq(registryUrl) + expect(summary.licensed!.declared).to.eq( 'GPL-2.0+ AND (CPL-1.0 OR MIT) AND (BSD-3-Clause OR GPL-3.0 AND LGPL-2.1+) AND NOASSERTION' ) }) @@ -614,8 +614,8 @@ describe('ClearlyDefined Debian summarizer', () => { const summary = Summarizer().summarize(coordinates, harvested) validate(summary) expect(summary.licensed).to.be.undefined - expect(summary.described.releaseDate).to.eq('2018-03-06') - expect(summary.described.urls).to.be.undefined + expect(summary.described!.releaseDate).to.eq('2018-03-06') + expect(summary.described!.urls).to.be.undefined }) }) @@ -630,12 +630,12 @@ describe('ClearlyDefined Debian source summarizer', () => { const summary = Summarizer().summarize(coordinates, harvested) const registryUrl = 'http://ftp.debian.org/debian/pool/main/0/0ad' validate(summary) - expect(summary.described.releaseDate).to.eq('2018-03-06') - expect(summary.described.urls.registry).to.eq(registryUrl) - expect(summary.described.urls.version).to.eq(registryUrl) - expect(summary.described.urls.download).to.eq('http://ftp.debian.org/debian/pool/main/0/0ad/0ad_0.0.17.orig.tar.xz') - expect(summary.described.sourceLocation.url).to.eq(registryUrl) - expect(summary.licensed.declared).to.eq('MPL-1.1 AND (MIT OR Artistic-1.0 AND Artistic-2.0)') + expect(summary.described!.releaseDate).to.eq('2018-03-06') + expect(summary.described!.urls!.registry).to.eq(registryUrl) + expect(summary.described!.urls!.version).to.eq(registryUrl) + expect(summary.described!.urls!.download).to.eq('http://ftp.debian.org/debian/pool/main/0/0ad/0ad_0.0.17.orig.tar.xz') + expect(summary.described!.sourceLocation!.url).to.eq(registryUrl) + expect(summary.licensed!.declared).to.eq('MPL-1.1 AND (MIT OR Artistic-1.0 AND Artistic-2.0)') }) it('handles no data', () => { @@ -651,15 +651,15 @@ describe('ClearlyDefined Debian source summarizer', () => { const summary = Summarizer().summarize(coordinates, harvested) validate(summary) expect(summary.licensed).to.be.undefined - expect(summary.described.releaseDate).to.eq('2018-03-06') - expect(summary.described.urls).to.be.undefined + expect(summary.described!.releaseDate).to.eq('2018-03-06') + expect(summary.described!.urls).to.be.undefined }) }) function setupDebian({ isSrc, releaseDate, registryData, sourceInfo, declaredLicenses }: any = {}) { const coordinates = isSrc - ? EntityCoordinates.fromString('debsrc/debian/-/test/1.0.0') - : EntityCoordinates.fromString('deb/debian/-/test/1.0.0_i386') + ? EntityCoordinates.fromString('debsrc/debian/-/test/1.0.0')! + : EntityCoordinates.fromString('deb/debian/-/test/1.0.0_i386')! const harvested: Record = {} setIfValue(harvested, 'releaseDate', releaseDate) setIfValue(harvested, 'registryData', registryData) diff --git a/test/summary/fossology.ts b/test/summary/fossology.ts index f9a67534..56693618 100644 --- a/test/summary/fossology.ts +++ b/test/summary/fossology.ts @@ -186,7 +186,7 @@ function setup(files, coordinateSpec?) { setupNomos(harvested, grouped.nomos) setupMonk(harvested, grouped.monk) setupCopyright(harvested, grouped.copyright) - const coordinates = EntityCoordinates.fromString(coordinateSpec || 'npm/npmjs/-/test/1.0') + const coordinates = EntityCoordinates.fromString(coordinateSpec || 'npm/npmjs/-/test/1.0')! return { coordinates, harvested } } diff --git a/test/summary/scancode.ts b/test/summary/scancode.ts index bd71a84e..a9561069 100644 --- a/test/summary/scancode.ts +++ b/test/summary/scancode.ts @@ -27,19 +27,19 @@ describe('ScanCode summarizer', () => { ]) const summary = Summarizer().summarize(coordinates, harvested) validate(summary) - expect(summary.files.length).to.eq(2) - expect(summary.files[0].attributions.length).to.eq(3) - expect(summary.files[0].path).to.equal('foo.txt') - expect(summary.files[0].attributions).to.deep.equalInAnyOrder(['Copyright Bob', 'Copyright Fred', 'Copyright bob']) - expect(summary.files[0].license).to.equal('MIT') - expect(summary.files[1].path).to.equal('bar.txt') - expect(summary.files[1].attributions.length).to.eq(3) - expect(summary.files[1].attributions).to.deep.equalInAnyOrder([ + expect(summary.files!.length).to.eq(2) + expect(summary.files![0].attributions!.length).to.eq(3) + expect(summary.files![0].path).to.equal('foo.txt') + expect(summary.files![0].attributions).to.deep.equalInAnyOrder(['Copyright Bob', 'Copyright Fred', 'Copyright bob']) + expect(summary.files![0].license).to.equal('MIT') + expect(summary.files![1].path).to.equal('bar.txt') + expect(summary.files![1].attributions!.length).to.eq(3) + expect(summary.files![1].attributions).to.deep.equalInAnyOrder([ 'Copyright John', 'Copyright Jane', 'Copyright Fred' ]) - expect(summary.files[1].license).to.equal('GPL-3.0') + expect(summary.files![1].license).to.equal('GPL-3.0') }) it('uses discovered full text license as declared license', () => { @@ -49,16 +49,16 @@ describe('ScanCode summarizer', () => { ]) const summary = Summarizer().summarize(coordinates, harvested) validate(summary) - expect(summary.licensed.declared).to.eq('MIT') - expect(summary.files.length).to.eq(2) - expect(summary.files[0].natures[0]).to.be.equal('license') + expect(summary.licensed!.declared).to.eq('MIT') + expect(summary.files!.length).to.eq(2) + expect(summary.files![0].natures![0]).to.be.equal('license') }) it('respects low license score', () => { const { coordinates, harvested } = setup([buildFile('LICENSE', 'MIT', [], 10, { is_license_text: true })]) const summary = Summarizer().summarize(coordinates, harvested) validate(summary) - expect(summary.files.length).to.eq(1) + expect(summary.files!.length).to.eq(1) expect(summary.licensed).to.be.undefined }) @@ -69,8 +69,8 @@ describe('ScanCode summarizer', () => { ]) const summary = Summarizer().summarize(coordinates, harvested) validate(summary) - expect(summary.files.length).to.eq(2) - expect(summary.licensed.declared).to.eq('GPL-3.0 AND MIT') + expect(summary.files!.length).to.eq(2) + expect(summary.licensed!.declared).to.eq('GPL-3.0 AND MIT') }) it('skips license files in subdirectories', () => { @@ -80,11 +80,11 @@ describe('ScanCode summarizer', () => { ]) const summary = Summarizer().summarize(coordinates, harvested) validate(summary) - expect(summary.files.length).to.eq(2) + expect(summary.files!.length).to.eq(2) expect(summary.licensed).to.be.undefined - expect(summary.files[0].attributions).to.be.undefined - expect(summary.files[0].path).to.equal('foo/LICENSE.md') - expect(summary.files[0].license).to.equal('MIT') + expect(summary.files![0].attributions).to.be.undefined + expect(summary.files![0].path).to.equal('foo/LICENSE.md') + expect(summary.files![0].license).to.equal('MIT') }) it('DETECTS npm license file in package folder', () => { @@ -94,11 +94,11 @@ describe('ScanCode summarizer', () => { ) const summary = Summarizer().summarize(coordinates, harvested) validate(summary) - expect(summary.licensed.declared).to.be.equal('GPL-3.0') - expect(summary.files.length).to.eq(1) - expect(summary.files[0].attributions).to.be.undefined - expect(summary.files[0].path).to.equal('package/LICENSE.md') - expect(summary.files[0].license).to.equal('GPL-3.0') + expect(summary.licensed!.declared).to.be.equal('GPL-3.0') + expect(summary.files!.length).to.eq(1) + expect(summary.files![0].attributions).to.be.undefined + expect(summary.files![0].path).to.equal('package/LICENSE.md') + expect(summary.files![0].license).to.equal('GPL-3.0') }) it('SKIPS nuget license file in a nested `package` folder', () => { @@ -108,11 +108,11 @@ describe('ScanCode summarizer', () => { ) const summary = Summarizer().summarize(coordinates, harvested) validate(summary) - expect(summary.files.length).to.eq(1) + expect(summary.files!.length).to.eq(1) expect(summary.licensed).to.be.undefined - expect(summary.files[0].attributions).to.be.undefined - expect(summary.files[0].path).to.equal('package/LICENSE.md') - expect(summary.files[0].license).to.equal('GPL-3.0') + expect(summary.files![0].attributions).to.be.undefined + expect(summary.files![0].path).to.equal('package/LICENSE.md') + expect(summary.files![0].license).to.equal('GPL-3.0') }) it('DETECTS asserted license file in the NPM package subdirectory', () => { @@ -123,15 +123,15 @@ describe('ScanCode summarizer', () => { ) const summary = Summarizer().summarize(coordinates, harvested) validate(summary) - expect(summary.files.length).to.eq(1) - expect(summary.licensed.declared).to.eq('MIT') + expect(summary.files!.length).to.eq(1) + expect(summary.licensed!.declared).to.eq('MIT') }) it('SKIPS asserted license file NOT in the NPM package subdirectory', () => { const { coordinates, harvested } = setup([buildPackageFile('package.json', 'MIT', [])], 'npm/npmjs/-/test/1.0') const summary = Summarizer().summarize(coordinates, harvested) validate(summary) - expect(summary.files.length).to.eq(1) + expect(summary.files!.length).to.eq(1) expect(summary.licensed).to.be.undefined }) @@ -143,15 +143,15 @@ describe('ScanCode summarizer', () => { ) const summary = Summarizer().summarize(coordinates, harvested) validate(summary) - expect(summary.files.length).to.eq(1) - expect(summary.licensed.declared).to.eq('MIT') + expect(summary.files!.length).to.eq(1) + expect(summary.licensed!.declared).to.eq('MIT') }) it('SKIPS asserted license file NOT in the root', () => { const { coordinates, harvested } = setup([buildPackageFile('bar/foo.nuspec', 'MIT', [])]) const summary = Summarizer().summarize(coordinates, harvested) validate(summary) - expect(summary.files.length).to.eq(1) + expect(summary.files!.length).to.eq(1) expect(summary.licensed).to.be.undefined }) @@ -166,8 +166,8 @@ describe('ScanCode summarizer', () => { ) const summary = Summarizer().summarize(coordinates, harvested) validate(summary) - expect(summary.files.length).to.eq(2) - expect(summary.licensed.declared).to.eq('MIT') + expect(summary.files!.length).to.eq(2) + expect(summary.licensed!.declared).to.eq('MIT') }) it('prioritizes full text license file over package manifest for 3.0', () => { @@ -181,8 +181,8 @@ describe('ScanCode summarizer', () => { ) const summary = Summarizer().summarize(coordinates, harvested) validate(summary) - expect(summary.files.length).to.eq(2) - expect(summary.licensed.declared).to.eq('GPL-3.0') + expect(summary.files!.length).to.eq(2) + expect(summary.licensed!.declared).to.eq('GPL-3.0') }) it('creates expressions from license expressions', () => { @@ -207,9 +207,9 @@ describe('ScanCode summarizer', () => { ]) const summary = Summarizer().summarize(coordinates, harvested) validate(summary) - expect(summary.files.length).to.eq(2) - expect(summary.files[0].license).to.eq('Apache-2.0 AND MIT') - expect(summary.files[1].license).to.eq('MIT') + expect(summary.files!.length).to.eq(2) + expect(summary.files![0].license).to.eq('Apache-2.0 AND MIT') + expect(summary.files![1].license).to.eq('MIT') }) it('ANDs together invalid licenses', () => { @@ -219,9 +219,9 @@ describe('ScanCode summarizer', () => { ]) const summary = Summarizer().summarize(coordinates, harvested) validate(summary) - expect(summary.files.length).to.eq(2) - expect(summary.files[0].license).to.eq('MIT AND NOASSERTION') - expect(summary.files[1].license).to.eq('MIT') + expect(summary.files!.length).to.eq(2) + expect(summary.files![0].license).to.eq('MIT AND NOASSERTION') + expect(summary.files![1].license).to.eq('MIT') }) }) @@ -285,7 +285,7 @@ function setup(files, coordinateSpec?, scancode_version = '30.1.0') { _metadata: {}, content: { scancode_version, files } } - const coordinates = EntityCoordinates.fromString(coordinateSpec || 'nuget/nuget/-/test/1.0') + const coordinates = EntityCoordinates.fromString(coordinateSpec || 'nuget/nuget/-/test/1.0')! return { coordinates, harvested } } From e86844a3d72995fa776019ee66f9c87a1a565421 Mon Sep 17 00:00:00 2001 From: Jamie Magee Date: Tue, 14 Apr 2026 19:58:55 -0700 Subject: [PATCH 3/4] fix strictNullChecks errors in test/lib/ --- test/lib/coordinatesMapper.ts | 6 +-- test/lib/curation.ts | 2 +- test/lib/licenseMatcher.ts | 18 ++++---- test/lib/spdx.ts | 4 +- test/lib/util.ts | 86 +++++++++++++++++------------------ 5 files changed, 58 insertions(+), 58 deletions(-) diff --git a/test/lib/coordinatesMapper.ts b/test/lib/coordinatesMapper.ts index f2935dee..824c913b 100644 --- a/test/lib/coordinatesMapper.ts +++ b/test/lib/coordinatesMapper.ts @@ -7,7 +7,7 @@ import coordinatesMapper from '../../lib/coordinatesMapper.ts' import EntityCoordinates from '../../lib/entityCoordinates.ts' function pypiCoordinates(name: string) { - return EntityCoordinates.fromString(`pypi/pypi/-/${name}/1.1.0a4`) + return EntityCoordinates.fromString(`pypi/pypi/-/${name}/1.1.0a4`)! } function fakeCache(cache: Record) { @@ -43,13 +43,13 @@ describe('CoordinatesMapper', () => { //cached after map let mapped = await mapper.map(coordinates) - expect(mapped.name).to.be.eq('0-core-client') + expect(mapped!.name).to.be.eq('0-core-client') expect(mapStub.calledOnce).to.be.true expect(cacheStub.size()).to.be.eq(1) //2nd time, should use cache, map should not be called. mapped = await mapper.map(coordinates) - expect(mapped.name).to.be.eq('0-core-client') + expect(mapped!.name).to.be.eq('0-core-client') expect(mapStub.calledOnce).to.be.true expect(cacheStub.size()).to.be.eq(1) }) diff --git a/test/lib/curation.ts b/test/lib/curation.ts index e599a2c3..39109140 100644 --- a/test/lib/curation.ts +++ b/test/lib/curation.ts @@ -187,7 +187,7 @@ describe('Curations', () => { it('should also accept yaml data objects', () => { const data = yaml.load('foo: bar') - const curation = new Curation(data) + const curation = new Curation(data as string) expect(curation.isValid).to.be.false expect(curation.errors[0].message).to.equal('Invalid curation') }) diff --git a/test/lib/licenseMatcher.ts b/test/lib/licenseMatcher.ts index e86042aa..457d8044 100644 --- a/test/lib/licenseMatcher.ts +++ b/test/lib/licenseMatcher.ts @@ -303,7 +303,7 @@ describe('licenseMatcher.js', () => { definition: { coordinates: EntityCoordinates.fromString( `maven/mavencentral/io.opentelemetry/opentelemetry-sdk-common/${revision}` - ) + )! }, harvest: { clearlydefined: { @@ -370,7 +370,7 @@ describe('licenseMatcher.js', () => { function generateCrateDefinitionAndHarvest(revision: string, license?: unknown): LicenseMatchInput { return { definition: { - coordinates: EntityCoordinates.fromString(`crate/cratesio/-/libc/${revision}`) + coordinates: EntityCoordinates.fromString(`crate/cratesio/-/libc/${revision}`)! }, harvest: { clearlydefined: { @@ -431,7 +431,7 @@ describe('licenseMatcher.js', () => { ): LicenseMatchInput { return { definition: { - coordinates: EntityCoordinates.fromString(`nuget/nuget/-/Microsoft.Identity.Web.MicrosoftGraph/${revision}`) + coordinates: EntityCoordinates.fromString(`nuget/nuget/-/Microsoft.Identity.Web.MicrosoftGraph/${revision}`)! }, harvest: { clearlydefined: { @@ -533,7 +533,7 @@ describe('licenseMatcher.js', () => { function generateNpmDefinitionAndHarvest(revision: string, license?: unknown): LicenseMatchInput { return { definition: { - coordinates: EntityCoordinates.fromString(`npm/npmjs/-/mongoose/${revision}`) + coordinates: EntityCoordinates.fromString(`npm/npmjs/-/mongoose/${revision}`)! }, harvest: { clearlydefined: { @@ -589,7 +589,7 @@ describe('licenseMatcher.js', () => { function generateComposerDefinitionAndHarvest(revision: string, licenses?: unknown): LicenseMatchInput { return { definition: { - coordinates: EntityCoordinates.fromString(`composer/packagist/codeinwp/themeisle-sdk/$${revision}`) + coordinates: EntityCoordinates.fromString(`composer/packagist/codeinwp/themeisle-sdk/$${revision}`)! }, harvest: { clearlydefined: { @@ -645,7 +645,7 @@ describe('licenseMatcher.js', () => { function generateGemDefinitionAndHarvest(revision: string, licenses?: unknown): LicenseMatchInput { return { definition: { - coordinates: EntityCoordinates.fromString(`gem/rubygems/-/reline/${revision}`) + coordinates: EntityCoordinates.fromString(`gem/rubygems/-/reline/${revision}`)! }, harvest: { clearlydefined: { @@ -704,7 +704,7 @@ describe('licenseMatcher.js', () => { ): LicenseMatchInput { return { definition: { - coordinates: EntityCoordinates.fromString(`pypi/pypi/-/distributed/${revision}`) + coordinates: EntityCoordinates.fromString(`pypi/pypi/-/distributed/${revision}`)! }, harvest: { clearlydefined: { @@ -790,7 +790,7 @@ describe('licenseMatcher.js', () => { function generateDebDefinitionAndHarvest(revision: string, licenses?: unknown): LicenseMatchInput { return { definition: { - coordinates: EntityCoordinates.fromString(`deb/debian/-/kopano-contacts/${revision}`) + coordinates: EntityCoordinates.fromString(`deb/debian/-/kopano-contacts/${revision}`)! }, harvest: { clearlydefined: { @@ -842,7 +842,7 @@ describe('licenseMatcher.js', () => { function generateDebDefinitionAndHarvest(revision: string, licenses?: unknown): LicenseMatchInput { return { definition: { - coordinates: EntityCoordinates.fromString(`debsrc/debian/-/lava/${revision}`) + coordinates: EntityCoordinates.fromString(`debsrc/debian/-/lava/${revision}`)! }, harvest: { clearlydefined: { diff --git a/test/lib/spdx.ts b/test/lib/spdx.ts index a5e84400..ee4acd4e 100644 --- a/test/lib/spdx.ts +++ b/test/lib/spdx.ts @@ -236,7 +236,7 @@ describe('SPDX utility functions', () => { } for (let input of Object.keys(data)) { if (input === 'null') { - input = null + input = null as any } expect(SPDX.normalize(input)).to.eq(data[input]) } @@ -254,7 +254,7 @@ describe('SPDX utility functions', () => { } for (let input of Object.keys(data)) { if (input === 'null') { - input = null + input = null as any } expect(SPDX.lookupByName(input)).to.eq(data[input]) } diff --git a/test/lib/util.ts b/test/lib/util.ts index 27a6794a..db9df56c 100644 --- a/test/lib/util.ts +++ b/test/lib/util.ts @@ -20,7 +20,7 @@ describe('Utils latest version', () => { '4.0.0': ['4.0.0', '4.0.1-rc.2'], '5.0.0': ['5.0.0', '5.0.1-beta'], '6.0.0': ['6.0.0', 'undefined'], - '7.0.0': [undefined, '7.0.0'], + '7.0.0': [undefined as unknown as string, '7.0.0'], '8.0.0': ['2.9.0b1', '8.0.0'], notarray: 'notarray', null: [], @@ -28,7 +28,7 @@ describe('Utils latest version', () => { } for (const expected of Object.getOwnPropertyNames(inputs)) { - const result = `${utils.getLatestVersion(inputs[expected])}` + const result = `${utils.getLatestVersion(inputs[expected]!)}` expect(result).to.equal(expected) } }) @@ -149,9 +149,9 @@ describe('Utils merge Licenses', () => { ['MIT AND Apache-2.0', 'MIT OR Apache-2.0', 'Apache-2.0 AND MIT'] ] for (const input of inputs) { - const base = { licensed: { declared: input[0] } } - utils.mergeDefinitions(base, { licensed: { declared: input[1] } }) - expect(base.licensed.declared).to.eq(input[2]) + const base = { licensed: { declared: input[0] } } as unknown as Definition + utils.mergeDefinitions(base, { licensed: { declared: input[1] } } as unknown as Partial) + expect(base.licensed!.declared).to.eq(input[2]) } }) }) @@ -161,21 +161,21 @@ describe('Utils mergeDefinitions', () => { const base: Definition = { described: { releaseDate: '2018-6-3' } } const newDefinition = { described: { issueTracker: 'http://bugs' }, files: [{ path: '1.txt', token: '13' }] } utils.mergeDefinitions(base, newDefinition as unknown as Partial) - expect(base.described.releaseDate).to.eq('2018-6-3') - expect(base.files.length).to.eq(1) - expect(base.files[0].path).to.eq('1.txt') - expect(base.files[0].token).to.eq('13') + expect(base.described!.releaseDate).to.eq('2018-6-3') + expect(base.files!.length).to.eq(1) + expect(base.files![0].path).to.eq('1.txt') + expect(base.files![0].token).to.eq('13') }) it('should merge entries as needed', () => { const base: Definition = { described: { releaseDate: '2018-6-3' }, files: [{ path: '1.txt', license: 'MIT' }] } const newDefinition = { described: { issueTracker: 'http://bugs' }, files: [{ path: '1.txt', token: '13' }] } utils.mergeDefinitions(base, newDefinition as unknown as Partial) - expect(base.described.releaseDate).to.eq('2018-6-3') - expect(base.files.length).to.eq(1) - expect(base.files[0].path).to.eq('1.txt') - expect(base.files[0].token).to.eq('13') - expect(base.files[0].license).to.eq('MIT') + expect(base.described!.releaseDate).to.eq('2018-6-3') + expect(base.files!.length).to.eq(1) + expect(base.files![0].path).to.eq('1.txt') + expect(base.files![0].token).to.eq('13') + expect(base.files![0].license).to.eq('MIT') }) it('does not mess with existing entries', () => { @@ -188,13 +188,13 @@ describe('Utils mergeDefinitions', () => { } const newDefinition = { described: { issueTracker: 'http://bugs' }, files: [{ path: '1.txt', token: '13' }] } utils.mergeDefinitions(base, newDefinition as unknown as Partial) - expect(base.described.releaseDate).to.eq('2018-6-3') - expect(base.files.length).to.eq(2) - expect(base.files[0].path).to.eq('1.txt') - expect(base.files[0].token).to.eq('13') - expect(base.files[0].license).to.eq('MIT') - expect(base.files[1].path).to.eq('2.txt') - expect(base.files[1].license).to.eq('GPL') + expect(base.described!.releaseDate).to.eq('2018-6-3') + expect(base.files!.length).to.eq(2) + expect(base.files![0].path).to.eq('1.txt') + expect(base.files![0].token).to.eq('13') + expect(base.files![0].license).to.eq('MIT') + expect(base.files![1].path).to.eq('2.txt') + expect(base.files![1].license).to.eq('GPL') }) it('overrides NOASSERTION', () => { @@ -204,9 +204,9 @@ describe('Utils mergeDefinitions', () => { } const newDefinition = { licensed: { declared: 'MIT' }, files: [{ path: '1.txt', license: 'GPL-3.0' }] } utils.mergeDefinitions(base, newDefinition) - expect(base.licensed.declared).to.eq('MIT') - expect(base.files.length).to.eq(1) - expect(base.files[0].license).to.eq('GPL-3.0') + expect(base.licensed!.declared).to.eq('MIT') + expect(base.files!.length).to.eq(1) + expect(base.files![0].license).to.eq('GPL-3.0') }) it('merges files correctly', () => { @@ -235,12 +235,12 @@ describe('Utils mergeDefinitions', () => { ] } utils.mergeDefinitions(base, newDefinition) - const file = base.files[0] + const file = base.files![0] expect(file.attributions).to.have.members(['1', '2', '3']) expect(file.license).to.eq('GPL-3.0 AND MIT') expect(file.facets).to.have.members(['core', 'dev']) - expect(file.hashes.sha1).to.eq('1') - expect(file.hashes.sha256).to.eq('257') + expect(file.hashes!.sha1).to.eq('1') + expect(file.hashes!.sha256).to.eq('257') expect(file.natures).to.have.members(['license', 'test']) }) @@ -259,12 +259,12 @@ describe('Utils mergeDefinitions', () => { } } utils.mergeDefinitions(base, newDefinition as unknown as Partial) - expect(base.described.projectWebsite).to.eq('https://test') - expect(base.described.hashes.sha1).to.eq('1') - expect(base.described.hashes.sha256).to.eq('257') - expect(base.described.facets.dev).to.eq('foo') - expect(base.described.facets.core).to.eq('test') - expect(base.described.facets.doc).to.eq('this') + expect(base.described!.projectWebsite).to.eq('https://test') + expect(base.described!.hashes!.sha1).to.eq('1') + expect(base.described!.hashes!.sha256).to.eq('257') + expect(base.described!.facets!.dev).to.eq('foo') + expect(base.described!.facets!.core).to.eq('test') + expect(base.described!.facets!.doc).to.eq('this') }) }) @@ -326,7 +326,7 @@ describe('Utils isLicenseFile', () => { 'package/COPYING.md', 'package/COPYING.HTML' ] - const coordinate = EntityCoordinates.fromString('npm/npm/-/name/version') + const coordinate = EntityCoordinates.fromString('npm/npm/-/name/version')! for (const input of inputs) { expect(utils.isLicenseFile(input, coordinate), `input: ${input}`).to.be.true } @@ -345,7 +345,7 @@ describe('Utils isLicenseFile', () => { 'meta-inf/COPYING.md', 'meta-inf/COPYING.HTML' ] - const coordinate = EntityCoordinates.fromString('maven/mavencentral/group/artifact/version') + const coordinate = EntityCoordinates.fromString('maven/mavencentral/group/artifact/version')! for (const input of inputs) { expect(utils.isLicenseFile(input, coordinate), `input: ${input}`).to.be.true } @@ -364,7 +364,7 @@ describe('Utils isLicenseFile', () => { 'meta-inf/COPYING.md', 'meta-inf/COPYING.HTML' ] - const coordinate = EntityCoordinates.fromString('sourcearchive/mavencentral/group/artifact/version') + const coordinate = EntityCoordinates.fromString('sourcearchive/mavencentral/group/artifact/version')! for (const input of inputs) { expect(utils.isLicenseFile(input, coordinate), `input: ${input}`).to.be.true } @@ -383,7 +383,7 @@ describe('Utils isLicenseFile', () => { 'redis-3.1/COPYING.md', 'redis-3.1/COPYING.HTML' ] - const coordinate = EntityCoordinates.fromString('pypi/pypi/-/redis/3.1') + const coordinate = EntityCoordinates.fromString('pypi/pypi/-/redis/3.1')! for (const input of inputs) { expect(utils.isLicenseFile(input, coordinate), `input: ${input}`).to.be.true } @@ -402,7 +402,7 @@ describe('Utils isLicenseFile', () => { 'tenacity-8.2.1/COPYING.md', 'tenacity-8.2.1/COPYING.HTML' ] - const coordinate = EntityCoordinates.fromString('debsrc/debian/-/python-tenacity/8.2.1-1') + const coordinate = EntityCoordinates.fromString('debsrc/debian/-/python-tenacity/8.2.1-1')! const packages = [ { name: 'python-tenacity-doc' }, { name: 'python3-tenacity' }, @@ -426,7 +426,7 @@ describe('Utils isLicenseFile', () => { 'package/COPYING.md', 'package/COPYING.HTML' ] - const coordinate = EntityCoordinates.fromString('nuget/nuget/-/redis/3.1') + const coordinate = EntityCoordinates.fromString('nuget/nuget/-/redis/3.1')! for (const input of inputs) { expect(utils.isLicenseFile(input, coordinate), `input: ${input}`).to.be.false } @@ -445,7 +445,7 @@ describe('Utils isLicenseFile', () => { '.package/COPYING.md', 'package2/COPYING.HTML' ] - const coordinate = EntityCoordinates.fromString('npm/npm/-/name/version') + const coordinate = EntityCoordinates.fromString('npm/npm/-/name/version')! for (const input of inputs) { expect(utils.isLicenseFile(input, coordinate), `input: ${input}`).to.be.false } @@ -464,7 +464,7 @@ describe('Utils isLicenseFile', () => { '.package/COPYING.md', 'package2/COPYING.HTML' ] - const coordinate = EntityCoordinates.fromString('maven/mavencentral/group/artifact/version') + const coordinate = EntityCoordinates.fromString('maven/mavencentral/group/artifact/version')! for (const input of inputs) { expect(utils.isLicenseFile(input, coordinate), `input: ${input}`).to.be.false } @@ -483,7 +483,7 @@ describe('Utils isLicenseFile', () => { 'other-3.1/COPYING', 'package/COPYING' ] - const coordinate = EntityCoordinates.fromString('pypi/pypi/-/redis/3.1') + const coordinate = EntityCoordinates.fromString('pypi/pypi/-/redis/3.1')! for (const input of inputs) { expect(utils.isLicenseFile(input, coordinate), `input: ${input}`).to.be.false } @@ -512,7 +512,7 @@ describe('Utils isLicenseFile', () => { 'other-8.2.1/COPYING', 'package/COPYING' ] - const coordinate = EntityCoordinates.fromString('debsrc/debian/-/python-tenacity/8.2.1-1') + const coordinate = EntityCoordinates.fromString('debsrc/debian/-/python-tenacity/8.2.1-1')! const packages = [ { name: 'python-tenacity-doc' }, { name: 'python3-tenacity' }, From cfd29b4f08c3c7817224c5e9b3799700051c4b8e Mon Sep 17 00:00:00 2001 From: Jamie Magee Date: Tue, 14 Apr 2026 20:19:06 -0700 Subject: [PATCH 4/4] fix strictNullChecks errors in source files Fix ~240 null-safety issues across providers, business, routes, middleware, lib, and bin. --- bin/config.ts | 8 +- business/definitionService.ts | 34 ++--- business/suggestionService.ts | 2 +- lib/licenseMatcher.ts | 8 +- middleware/github.ts | 22 ++-- middleware/githubConfig.ts | 4 +- providers/caching/redisConfig.ts | 6 +- providers/curation/azureQueueConfig.ts | 4 +- providers/curation/github.ts | 122 +++++++++--------- providers/curation/githubConfig.ts | 8 +- providers/curation/memoryStore.ts | 8 +- providers/curation/mongoConfig.ts | 4 +- providers/curation/mongoCurationStore.ts | 18 +-- providers/harvest/azureQueueConfig.ts | 4 +- providers/harvest/crawlerConfig.ts | 8 +- providers/harvest/crawlerQueueConfig.ts | 12 +- .../harvest/throttling/listBasedFilter.ts | 10 +- providers/logging/winstonConfig.ts | 6 +- providers/queueing/azureStorageQueue.ts | 6 +- providers/queueing/memoryQueue.ts | 6 +- providers/search/abstractSearch.ts | 4 +- providers/search/azureConfig.ts | 8 +- providers/search/memory.ts | 2 +- providers/stores/abstractFileStore.ts | 4 +- .../stores/abstractMongoDefinitionStore.ts | 2 +- providers/stores/azblobConfig.ts | 12 +- providers/stores/azblobDefinitionStore.ts | 9 +- providers/stores/azblobHarvestStore.ts | 2 +- providers/stores/dispatchDefinitionStore.ts | 10 +- providers/stores/fileHarvestStore.ts | 8 +- providers/stores/mongo.ts | 11 +- providers/stores/mongoConfig.ts | 8 +- providers/summary/clearlydefined.ts | 49 +++---- providers/summary/fossology.ts | 2 +- providers/summary/licensee.ts | 8 +- providers/summary/reuse.ts | 12 +- providers/summary/scancode.ts | 2 +- .../summary/scancode/legacy-summarizer.ts | 14 +- providers/summary/scancode/new-summarizer.ts | 14 +- providers/upgrade/azureQueueConfig.ts | 6 +- providers/upgrade/defVersionCheck.ts | 8 +- providers/upgrade/recomputeHandler.ts | 2 +- routes/auth.ts | 30 ++--- 43 files changed, 268 insertions(+), 259 deletions(-) diff --git a/bin/config.ts b/bin/config.ts index f8a54af8..f523dc61 100644 --- a/bin/config.ts +++ b/bin/config.ts @@ -191,10 +191,10 @@ export default { website: config.get('WEBSITE_ENDPOINT') || 'http://localhost:3000' }, limits: { - windowSeconds: Number.parseInt(config.get('RATE_LIMIT_WINDOW'), 10) || 1, - max: Number.parseInt(config.get('RATE_LIMIT_MAX'), 10) || 0, - batchWindowSeconds: Number.parseInt(config.get('BATCH_RATE_LIMIT_WINDOW'), 10) || 1, - batchMax: Number.parseInt(config.get('BATCH_RATE_LIMIT_MAX'), 10) || 0 + windowSeconds: Number.parseInt(config.get('RATE_LIMIT_WINDOW')!, 10) || 1, + max: Number.parseInt(config.get('RATE_LIMIT_MAX')!, 10) || 0, + batchWindowSeconds: Number.parseInt(config.get('BATCH_RATE_LIMIT_WINDOW')!, 10) || 1, + batchMax: Number.parseInt(config.get('BATCH_RATE_LIMIT_MAX')!, 10) || 0 }, webhook: { githubSecret: diff --git a/business/definitionService.ts b/business/definitionService.ts index 3b46e402..9f4c4171 100644 --- a/business/definitionService.ts +++ b/business/definitionService.ts @@ -321,7 +321,7 @@ export class DefinitionService { } else { result = await this.recomputeHandler.compute(this, coordinates) } - return this._trimDefinition(this._cast(result), expand) + return this._trimDefinition(this._cast(result!), expand) } /** Get directly from cache or store without any side effect, like compute */ @@ -389,7 +389,7 @@ export class DefinitionService { } _cast(definition: Definition): Definition { - definition.coordinates = EntityCoordinates.fromObject(definition.coordinates) + definition.coordinates = EntityCoordinates.fromObject(definition.coordinates)! return definition } @@ -428,7 +428,7 @@ export class DefinitionService { } const curated = (await this.curationService.list(coordinates)).map(c => c.toString()) const tools = await this.harvestStore.list(coordinates) - const harvest = tools.map(tool => EntityCoordinates.fromString(tool).toString()) + const harvest = tools.map(tool => EntityCoordinates.fromString(tool)!.toString()) return sortedUniq([...harvest, ...curated]) } @@ -452,12 +452,12 @@ export class DefinitionService { } }) ) - const foundDefinitions = flatten(await Promise.all(concat(promises))) + const foundDefinitions = flatten(await Promise.all(concat(promises))).filter((x): x is string => x !== null) // Filter only the revisions matching the found definitions return intersectionWith( coordinatesList, foundDefinitions, - (a, b) => a && b && a.toString().toLowerCase() === b.toString().toLowerCase() + (a, b) => a.toString().toLowerCase() === b.toString().toLowerCase() ) } @@ -695,7 +695,7 @@ export class DefinitionService { for (const version in raw[tool]) { const cased = get(raw[tool][version], '_metadata.links.self.href') if (cased) { - return EntityCoordinates.fromUrn(cased) + return EntityCoordinates.fromUrn(cased)! } } } @@ -736,8 +736,8 @@ export class DefinitionService { _ensureFinalScores(definition: Definition): void { const { described, licensed } = definition - set(definition, 'scores.effective', Math.floor((described.score.total + licensed.score.total) / 2)) - set(definition, 'scores.tool', Math.floor((described.toolScore.total + licensed.toolScore.total) / 2)) + set(definition, 'scores.effective', Math.floor((described!.score!.total + licensed!.score!.total) / 2)) + set(definition, 'scores.tool', Math.floor((described!.toolScore!.total + licensed!.toolScore!.total) / 2)) } _finalizeDefinition(coordinates: EntityCoordinates, definition: Definition): void { @@ -847,7 +847,7 @@ export class DefinitionService { _collectLicenseTexts(definition: Definition): string[] { const result: Set = new Set() - for (const file of definition.files.filter(DefinitionService._isLicenseFile)) { + for (const file of definition.files!.filter(DefinitionService._isLicenseFile)) { this._extractLicensesFromExpression(file.license, result) } return Array.from(result) @@ -872,7 +872,7 @@ export class DefinitionService { /** Answer whether or not the given file is a license text file */ static _isLicenseFile(file: DefinitionFile): boolean { - return file.token && DefinitionService._isInCoreFacet(file) && (file.natures || []).includes('license') + return !!file.token && DefinitionService._isInCoreFacet(file) && (file.natures || []).includes('license') } /** Suggest a set of definition coordinates that match the given pattern. Only existing definitions are searched. */ @@ -884,20 +884,20 @@ export class DefinitionService { * Helper method to prime the search store while getting the system up and running. * Should not be needed in general. */ - async reload(mode: string, coordinatesList: string[] | null = null): Promise<(undefined | null)[]> { + async reload(mode: string, coordinatesList: string[] | null = null): Promise<(void | null | undefined)[]> { const recompute = mode === 'definitions' const baseList = coordinatesList || (await this.list(new EntityCoordinates(), recompute)) - const list = baseList.map(entry => EntityCoordinates.fromString(entry)) + const list = baseList.map(entry => EntityCoordinates.fromString(entry)!) return await Promise.all( list.map( throat(10, async (coordinates: EntityCoordinates) => { try { const definition = await this.get(coordinates, null, recompute) if (recompute) { - return Promise.resolve(null) + return null } if (this.search.store) { - return this.search.store(definition) + return this.search.store(definition!) } } catch (error) { this.logger.info('failed to reload in definition service', { @@ -984,7 +984,7 @@ export class DefinitionService { _ensureSourceLocation(coordinates: EntityCoordinates, definition: Definition): void { if (get(definition, 'described.sourceLocation')) { - updateSourceLocation(definition.described.sourceLocation) + updateSourceLocation(definition.described!.sourceLocation!) return } // For source components there may not be an explicit harvested source location (it is self-evident) @@ -999,7 +999,7 @@ export class DefinitionService { return } this._ensureDescribed(definition) - definition.described.sourceLocation = { ...coordinates, url } + definition.described!.sourceLocation = { ...coordinates, url } break } default: @@ -1025,7 +1025,7 @@ export class DefinitionService { } _getCacheKey(coordinates: EntityCoordinates): string { - return `def_${EntityCoordinates.fromObject(coordinates).toString().toLowerCase()}` + return `def_${EntityCoordinates.fromObject(coordinates)!.toString().toLowerCase()}` } } diff --git a/business/suggestionService.ts b/business/suggestionService.ts index c1cb7dc2..99b1d389 100644 --- a/business/suggestionService.ts +++ b/business/suggestionService.ts @@ -87,7 +87,7 @@ export class SuggestionService { */ async _getRelatedDefinitions(coordinates: EntityCoordinates): Promise { const query = coordinates.asRevisionless() - query.namespace = query.namespace ? query.namespace : null // explicitly exclude namespace + query.namespace = query.namespace ? query.namespace : (null as unknown as string) // explicitly exclude namespace const results = await this.definitionService.find(query) const definitions = results.data.sort((a, b) => compareDates(get(a, 'described.releaseDate'), get(b, 'described.releaseDate')) diff --git a/lib/licenseMatcher.ts b/lib/licenseMatcher.ts index b76f0331..f63d76d5 100644 --- a/lib/licenseMatcher.ts +++ b/lib/licenseMatcher.ts @@ -119,8 +119,8 @@ class DefinitionLicenseMatchPolicy implements LicenseMatchPolicy { const sourceLicenseFiles = this._getLicenseFile(source.definition) const targetLicenseFiles = this._getLicenseFile(target.definition) const fileMap = new Map() - this._addFileToMap(fileMap, sourceLicenseFiles, 'sourceFile') - this._addFileToMap(fileMap, targetLicenseFiles, 'targetFile') + this._addFileToMap(fileMap, sourceLicenseFiles || [], 'sourceFile') + this._addFileToMap(fileMap, targetLicenseFiles || [], 'targetFile') return fileMap } @@ -196,7 +196,7 @@ class HarvestLicenseMatchPolicy implements LicenseMatchPolicy { * Compare harvest license data between source and target */ compare(source: LicenseMatchInput, target: LicenseMatchInput): CompareResult { - const type = source.definition.coordinates.type + const type = source.definition.coordinates!.type! const strategy = this._getStrategy(type) return strategy.compare(source, target) } @@ -324,7 +324,7 @@ function getLatestToolHarvest(coordinateHarvest: CoordinateHarvest, tool: string return undefined } const latestVersion = getLatestVersion(Object.keys(coordinateHarvest[tool])) - return get(coordinateHarvest, [tool, latestVersion]) as object | undefined + return get(coordinateHarvest, [tool, latestVersion!]) as object | undefined } export { DefinitionLicenseMatchPolicy, HarvestLicenseMatchPolicy, LicenseMatcher } diff --git a/middleware/github.ts b/middleware/github.ts index 05f0be0c..0e564b6b 100644 --- a/middleware/github.ts +++ b/middleware/github.ts @@ -73,7 +73,7 @@ const middleware: RequestHandler = asyncMiddleware(async (req, res, next) => { return } - const serviceToken = options.token + const serviceToken = options!.token const serviceClient = await setupServiceClient(req, serviceToken) const userToken = authHeader ? authHeader.split(' ')[1] : null const userClient = await setupUserClient(req, userToken) @@ -81,21 +81,21 @@ const middleware: RequestHandler = asyncMiddleware(async (req, res, next) => { req.app.locals.user.github.getInfo = async () => { if (!req.app.locals.user.github._info) { const infoCacheKey = userClient - ? await getCacheKey('github.user', userToken) + ? await getCacheKey('github.user', userToken!) : await getCacheKey('github.user', serviceToken) await setupInfo(req, infoCacheKey, userClient || serviceClient) } - return req.app.locals.user.github._info + return req.app.locals.user.github._info! } - req.app.locals.user.github.getTeams = async () => { + req.app.locals.user.github.getTeams = async (): Promise => { if (!req.app.locals.user.github._teams) { - const teamCacheKey = userClient ? await getCacheKey('github.team', userToken) : null + const teamCacheKey = userClient ? await getCacheKey('github.team', userToken!) : null await setupTeams(req, teamCacheKey, userClient) } - return req.app.locals.user.github._teams + return req.app.locals.user.github._teams! } next() @@ -128,11 +128,11 @@ async function setupUserClient(req: Request, token: string | null): Promise { - let info = await cache.get(cacheKey) + let info = await cache!.get(cacheKey) if (!info) { info = await client.rest.users.getAuthenticated() info = { name: info.data.name, login: info.data.login, email: info.data.email } - await cache.set(cacheKey, info) + await cache!.set(cacheKey, info) } req.app.locals.user.github._info = info } @@ -144,10 +144,10 @@ async function setupTeams(req: Request, cacheKey: string | null, client: Octokit return } // check cache for team data; hash the token so we're not storing them raw - let teams = await cache.get(cacheKey) + let teams = await cache!.get(cacheKey) if (!teams) { - teams = await getTeams(client, options.org) - await cache.set(cacheKey, teams) + teams = await getTeams(client, options!.org) + await cache!.set(cacheKey, teams) } req.app.locals.user.github._teams = teams } diff --git a/middleware/githubConfig.ts b/middleware/githubConfig.ts index 792e9e5b..ebb0644b 100644 --- a/middleware/githubConfig.ts +++ b/middleware/githubConfig.ts @@ -25,11 +25,11 @@ export interface GitHubConfigOptions extends GitHubMiddlewareOptions { const defaultOptions: GitHubConfigOptions = { clientId: config.get('AUTH_GITHUB_CLIENT_ID'), clientSecret: config.get('AUTH_GITHUB_CLIENT_SECRET'), - token: config.get('CURATION_GITHUB_TOKEN'), + token: config.get('CURATION_GITHUB_TOKEN')!, org: config.get('AUTH_GITHUB_ORG') || 'clearlydefined', permissions: { harvest: [config.get('AUTH_HARVEST_TEAM') || 'harvest-dev'], - curate: [config.get('AUTH_CURATION_TEAM'), 'curation-dev'] + curate: [config.get('AUTH_CURATION_TEAM')!, 'curation-dev'] } } const defaultCache = memoryCache({ defaultTtlSeconds: 10 * 60 /* 10 mins */ }) diff --git a/providers/caching/redisConfig.ts b/providers/caching/redisConfig.ts index c5d96be1..b7cdf3d2 100644 --- a/providers/caching/redisConfig.ts +++ b/providers/caching/redisConfig.ts @@ -11,9 +11,9 @@ import redis from './redis.ts' * allowing for custom configuration when needed. */ function serviceFactory(options?: RedisCacheOptions): RedisCache { - const realOptions = options || { - service: config.get('CACHING_REDIS_SERVICE'), - apiKey: config.get('CACHING_REDIS_API_KEY'), + const realOptions: RedisCacheOptions = options || { + service: config.get('CACHING_REDIS_SERVICE')!, + apiKey: config.get('CACHING_REDIS_API_KEY')!, port: Number(config.get('CACHING_REDIS_PORT')) || 6380 } return redis(realOptions) diff --git a/providers/curation/azureQueueConfig.ts b/providers/curation/azureQueueConfig.ts index ff27cd43..735b1af3 100644 --- a/providers/curation/azureQueueConfig.ts +++ b/providers/curation/azureQueueConfig.ts @@ -6,8 +6,8 @@ import type { AzureStorageQueueOptions } from '../queueing/azureStorageQueue.ts' import AzureStorageQueue from '../queueing/azureStorageQueue.ts' function azure(options?: AzureStorageQueueOptions): AzureStorageQueue { - const realOptions = options || { - connectionString: config.get('CURATION_QUEUE_CONNECTION_STRING') || config.get('HARVEST_AZBLOB_CONNECTION_STRING'), + const realOptions: AzureStorageQueueOptions = options || { + connectionString: (config.get('CURATION_QUEUE_CONNECTION_STRING') || config.get('HARVEST_AZBLOB_CONNECTION_STRING'))!, queueName: config.get('CURATION_QUEUE_NAME') || 'curations' } return new AzureStorageQueue(realOptions) diff --git a/providers/curation/github.ts b/providers/curation/github.ts index d39cd66b..d2a3b9af 100644 --- a/providers/curation/github.ts +++ b/providers/curation/github.ts @@ -173,14 +173,14 @@ class GitHubCurationService { } this._cleanCurationTree(pr.number) await this.store.updateContribution(data, curations) - let toBeCleaned = flatten(curations.map(curation => curation.getCoordinates())) + let toBeCleaned = flatten(curations!.map(curation => curation.getCoordinates())) // Should also delete revision less coordinate curation cache toBeCleaned = uniqWith(toBeCleaned.concat(toBeCleaned.map(c => c.asRevisionless())), isEqual) await Promise.all( toBeCleaned.map(throat(10, async coordinates => this.cache.delete(this._getCacheKey(coordinates)))) ) if (data.merged_at) { - await this._prMerged(curations) + await this._prMerged(curations!) } } @@ -238,14 +238,14 @@ class GitHubCurationService { const otherDefinition = await this.definitionService.getStored(otherCoordinates) const otherHarvest = await this.harvestStore.getAll(otherCoordinates) const result = this.licenseMatcher.process( - { definition, harvest }, - { definition: otherDefinition, harvest: otherHarvest } + { definition: definition!, harvest }, + { definition: otherDefinition!, harvest: otherHarvest } ) if (result.isMatching) { matches.push({ - version: otherCoordinates.revision, - matchingProperties: result.match.map(reason => { + version: otherCoordinates.revision!, + matchingProperties: result.match!.map(reason => { if (reason.file) { return { file: reason.file } } @@ -263,8 +263,8 @@ class GitHubCurationService { let revisions: string[] = [] for (const coordinate of Object.keys(curations.curations)) { - const coordinateObject = EntityCoordinates.fromString(coordinate) - revisions.push(coordinateObject.revision) + const coordinateObject = EntityCoordinates.fromString(coordinate)! + revisions.push(coordinateObject.revision!) } for (const contribution of curations.contributions) { @@ -282,7 +282,7 @@ class GitHubCurationService { const revisionlessCoords = coordinates.asRevisionless() const coordinatesList = await this.definitionService.list(revisionlessCoords) const filteredCoordinatesList = coordinatesList - .map(stringCoords => EntityCoordinates.fromString(stringCoords)) + .map(stringCoords => EntityCoordinates.fromString(stringCoords)!) .filter( coords => coordinates.name === coords.name && @@ -305,10 +305,10 @@ class GitHubCurationService { curation: CurationRevision, matchingRevisionAndReason: MatchingRevisionAndReason[] ) { - const filtered = [] + const filtered: MatchingRevisionAndReason[] = [] for (const revisionAndReason of matchingRevisionAndReason) { const { version } = revisionAndReason - const matchingCoordinates = EntityCoordinates.fromObject({ ...coordinates, revision: version }) + const matchingCoordinates = EntityCoordinates.fromObject({ ...coordinates, revision: version })! const matchingDefinition = await this.definitionService.getStored(matchingCoordinates) const existingDeclaredLicense = get(matchingDefinition, 'licensed.declared') if (!existingDeclaredLicense || existingDeclaredLicense === 'NOASSERTION') { @@ -335,7 +335,7 @@ class GitHubCurationService { currentContent: CurationData, newContent: Record ) { - const newCoordinates = EntityCoordinates.fromObject(coordinates).asRevisionless() + const newCoordinates = EntityCoordinates.fromObject(coordinates)!.asRevisionless() const result = { coordinates: newCoordinates, revisions: get(currentContent, 'revisions') || {} @@ -352,10 +352,10 @@ class GitHubCurationService { branch: string ) { const { owner, repo } = this.options - const coordinates = EntityCoordinates.fromObject(patch.coordinates) + const coordinates = EntityCoordinates.fromObject(patch.coordinates)! const currentContent = await this._getCurations(coordinates) const newContent = patch.revisions - const updatedContent = this._updateContent(coordinates, currentContent, newContent) + const updatedContent = this._updateContent(coordinates, currentContent!, newContent) const content = Buffer.from(updatedContent).toString('base64') const path = this._getCurationPath(coordinates) const message = `Update ${path}` @@ -386,7 +386,7 @@ class GitHubCurationService { // Github requires name/email to set committer if ((info.name || info.login) && info.email) { - fileBody.committer = { name: info.name || info.login, email: info.email } + fileBody.committer = { name: (info.name || info.login)!, email: info.email } } if (get(currentContent, '_origin.sha')) { fileBody.sha = get(currentContent, '_origin.sha') @@ -411,9 +411,9 @@ class GitHubCurationService { // Return an array of valid patches that exist // and a list of definitions that do not exist in the store async _validateDefinitionsExist(patches: CurationPatchEntry[]) { - const targetCoordinates = patches.reduce((result, patch) => { + const targetCoordinates = patches.reduce((result: EntityCoordinates[], patch) => { for (const key in patch.revisions) { - result.push(EntityCoordinates.fromObject({ ...patch.coordinates, revision: key })) + result.push(EntityCoordinates.fromObject({ ...patch.coordinates, revision: key })!) } return result }, []) @@ -425,7 +425,7 @@ class GitHubCurationService { ) return result }, - { valid: [], missing: [] } + { valid: [] as EntityCoordinates[], missing: [] as EntityCoordinates[] } ) } @@ -435,24 +435,24 @@ class GitHubCurationService { return } - const revisionLessCoordinates = definition.coordinates.asRevisionless() + const revisionLessCoordinates = definition.coordinates!.asRevisionless() // @ts-expect-error list returns CurationListResult for GitHubCurationService const curationAndContributions: CurationListResult = await this.list(revisionLessCoordinates) if (!this._canBeAutoCurated(definition, curationAndContributions)) { this.logger.info('GitHubCurationService.autoCurate.notApplicable', { - coordinates: definition.coordinates.toString() + coordinates: definition.coordinates!.toString() }) return } // TODO: Only need to get the clearlydefined tool harvest data. Other tools' harvest data is not necessary. - const harvest = await this.harvestStore.getAll(definition.coordinates) + const harvest = await this.harvestStore.getAll(definition.coordinates!) const orderedCoordinates = Object.keys(curationAndContributions.curations || {}).sort((a, b) => { - const aRevision = EntityCoordinates.fromString(a).revision - const bRevision = EntityCoordinates.fromString(b).revision + const aRevision = EntityCoordinates.fromString(a)!.revision + const bRevision = EntityCoordinates.fromString(b)!.revision if (semver.valid(aRevision) && semver.valid(bRevision)) { - return semver.rcompare(aRevision, bRevision) + return semver.rcompare(aRevision!, bRevision!) } return 0 }) @@ -461,7 +461,7 @@ class GitHubCurationService { const curation = curationAndContributions.curations[coordinateStr] const declaredLicense = get(curation, 'licensed.declared') const logProps = { - source: definition.coordinates.toString(), + source: definition.coordinates!.toString(), target: coordinateStr } if (!declaredLicense) { @@ -469,7 +469,7 @@ class GitHubCurationService { continue } - const otherCoordinates = EntityCoordinates.fromString(coordinateStr) + const otherCoordinates = EntityCoordinates.fromString(coordinateStr)! const otherDefinition = await this.definitionService.getStored(otherCoordinates) if (!otherDefinition) { this.logger.info('GitHubCurationService.autoCurate.otherDefinitionEmpty', logProps) @@ -483,11 +483,11 @@ class GitHubCurationService { ) if (result.isMatching) { const info = await this._getUserInfo(this.github) - const resolution = `Auto-generated curation. Newly harvested version ${definition.coordinates.revision} matches existing version ${otherCoordinates.revision}. ${this._generateMatchingDescription(result.match)}` + const resolution = `Auto-generated curation. Newly harvested version ${definition.coordinates!.revision} matches existing version ${otherCoordinates.revision}. ${this._generateMatchingDescription(result.match!)}` const patch = { contributionInfo: { type: 'auto', - summary: definition.coordinates.toString(), + summary: definition.coordinates!.toString(), details: `Add ${declaredLicense} license`, resolution }, @@ -495,7 +495,7 @@ class GitHubCurationService { { coordinates: revisionLessCoordinates, revisions: { - [definition.coordinates.revision]: curation + [definition.coordinates!.revision!]: curation } } ] @@ -530,7 +530,7 @@ class GitHubCurationService { _hasExistingCurations(definition: Definition, curationAndContributions: CurationListResult) { const revisions = this._getRevisionsFromCurations(curationAndContributions) - return revisions.includes(definition.coordinates.revision) + return revisions.includes(definition.coordinates!.revision!) } async addOrUpdate( @@ -553,10 +553,10 @@ class GitHubCurationService { } // @ts-expect-error patches returned from _getPatchesFromMergedPullRequest match CurationPatchEntry shape const patches: CurationPatchEntry[] = await this._getPatchesFromMergedPullRequest(pr) - const component = first(patches) - const curationRevisions = get(component, 'revisions') + const component = first(patches)! + const curationRevisions = get(component, 'revisions')! const revision = first(Object.keys(curationRevisions)) - const curatedCoordinates = EntityCoordinates.fromObject({ ...component.coordinates, revision }) + const curatedCoordinates = EntityCoordinates.fromObject({ ...component.coordinates, revision })! const { missing } = await this._validateDefinitionsExist(patches) if (missing.length > 0) { @@ -565,29 +565,29 @@ class GitHubCurationService { if (!this._isEligibleForMultiversionCuration(patches)) { return undefined } - this.logger.info('eligible component for multiversion curation', { coordinates: curatedCoordinates.toString() }) + this.logger.info('eligible component for multiversion curation', { coordinates: curatedCoordinates!.toString() }) let matchingRevisionAndReason = await this._calculateMatchingRevisionAndReason(curatedCoordinates) matchingRevisionAndReason = await this._filterRevisionWithDeclaredLicense( - curatedCoordinates, - get(curationRevisions, [revision]), + curatedCoordinates!, + get(curationRevisions, [revision!]), matchingRevisionAndReason ) if (matchingRevisionAndReason.length === 0) { return undefined } this.logger.info('found additional versions to curate', { - coordinates: curatedCoordinates.toString(), + coordinates: curatedCoordinates!.toString(), additionalRevisionCount: matchingRevisionAndReason.length }) const info = { type: 'auto', - summary: curatedCoordinates.toString(), - details: `Add ${get(curationRevisions, [revision, 'licensed', 'declared'])} license`, + summary: curatedCoordinates!.toString(), + details: `Add ${get(curationRevisions, [revision!, 'licensed', 'declared'])} license`, resolution: `Automatically added versions based on ${pr.html_url}\n ${this._formatMultiversionCuratedRevisions(matchingRevisionAndReason)}` } return this._addCurationWithMatchingRevisions( - curatedCoordinates, - curationRevisions[revision], + curatedCoordinates!, + curationRevisions[revision!], info, matchingRevisionAndReason ) @@ -601,8 +601,8 @@ class GitHubCurationService { const curations = await this.getContributedCurations(pr.number, pr.head.sha) const preCurations = await this.getContributedCurations(pr.number, pr.base.sha) for (const curation of curations) { - const preCuration = preCurations.find(x => x.path === curation.path) - for (const revision of Object.keys(curation.data.revisions)) { + const preCuration = preCurations.find(x => x!.path === curation!.path) + for (const revision of Object.keys(curation!.data!.revisions!)) { const current = get(curation, ['data', 'revisions', revision]) const previous = get(preCuration, ['data', 'revisions', revision]) // biome-ignore lint/suspicious/noDoubleEquals: intentional loose equality to catch both null and undefined @@ -611,7 +611,7 @@ class GitHubCurationService { } } } - return curations.map(c => c.data) + return curations.map(c => c!.data!) } async _addOrUpdate( @@ -709,7 +709,7 @@ ${this._formatDefinitions(patch.patches)}` matchingLicenses.push(match.file) } } else { - matchingMetadata[match.propPath] = match.value + matchingMetadata[match.propPath!] = match.value } } @@ -803,7 +803,7 @@ ${this._formatDefinitions(patch.patches)}` ts: new Date().toISOString(), coordinates: coordinates.toString() }) - const content: CurationData & { _origin?: { sha: string } } = yaml.load(data.toString()) + const content: CurationData & { _origin?: { sha: string } } = yaml.load(data.toString()) as CurationData & { _origin?: { sha: string } } // Stash the sha of the content as a NON-enumerable prop so it does not get merged into the patch Object.defineProperty(content, '_origin', { value: { sha: blob.object }, enumerable: false }) return content @@ -829,7 +829,7 @@ ${this._formatDefinitions(patch.patches)}` }) ) ) - return result.filter(i => i) + return result.filter((i): i is Curation => !!i) } async apply( @@ -838,8 +838,8 @@ ${this._formatDefinitions(patch.patches)}` definition: Definition ) { const curation = await this.get(coordinates, curationSpec) - const result = Curation.apply(definition, curation) - this._ensureCurationInfo(result, curation) + const result = Curation.apply(definition, curation!) + this._ensureCurationInfo(result, curation!) return result } @@ -982,16 +982,16 @@ ${this._formatDefinitions(patch.patches)}` const changedCoordinates: string[] = [] for (let i = 0; i < files.length; ++i) { const fileName = files[i].filename.replace(/\.yaml$/, '').replace(/^curations\//, '') - const coordinates = EntityCoordinates.fromString(fileName) + const coordinates = EntityCoordinates.fromString(fileName)! const prDefinitions = (await this._getCurations(coordinates, number)) || { revisions: {} } const masterDefinitions = (await this._getCurations(coordinates)) || { revisions: {} } const allUnfilteredRevisions = concat( - Object.keys(prDefinitions.revisions), - Object.keys(masterDefinitions.revisions) + Object.keys(prDefinitions.revisions!), + Object.keys(masterDefinitions.revisions!) ) const allRevisions = uniq(allUnfilteredRevisions) const changedRevisions = allRevisions.filter( - revision => !isEqual(prDefinitions.revisions[revision], masterDefinitions.revisions[revision]) + revision => !isEqual(prDefinitions.revisions![revision], masterDefinitions.revisions![revision]) ) for (const revision of changedRevisions) { changedCoordinates.push(`${fileName}/${revision}`) @@ -1005,7 +1005,7 @@ ${this._formatDefinitions(patch.patches)}` return coordinates.toString() } - _getBranchName(info: { login?: string }) { + _getBranchName(info: { login?: string | null }) { return `${info.login}_${DateTime.now().toFormat('yyMMdd_HHmmss.SSS')}` } @@ -1024,7 +1024,7 @@ ${this._formatDefinitions(patch.patches)}` } _getCacheKey(coordinates: EntityCoordinates) { - return `cur_${EntityCoordinates.fromObject(coordinates).toString().toLowerCase()}` + return `cur_${EntityCoordinates.fromObject(coordinates)!.toString().toLowerCase()}` } async _addCurationWithMatchingRevisions( @@ -1085,7 +1085,7 @@ ${this._formatDefinitions(patch.patches)}` } async _reprocessMergedCuration(coordinates: EntityCoordinates) { - const contributions = [] + const contributions: { coordinates: string; contribution?: string }[] = [] coordinates = coordinates.asRevisionless() // @ts-expect-error list returns CurationListResult for GitHubCurationService const { curations } = await this.list(coordinates) @@ -1094,12 +1094,12 @@ ${this._formatDefinitions(patch.patches)}` } const processedRevisions = new Set() for (const [curatedCoordinatesStr, curation] of Object.entries(curations)) { - const curatedCoordinates = EntityCoordinates.fromString(curatedCoordinatesStr) + const curatedCoordinates = EntityCoordinates.fromString(curatedCoordinatesStr)! let matchingRevisionAndReason = await this._calculateMatchingRevisionAndReason(curatedCoordinates) matchingRevisionAndReason = matchingRevisionAndReason.filter(r => !processedRevisions.has(r.version)) matchingRevisionAndReason = await this._filterRevisionWithDeclaredLicense( curatedCoordinates, - curation, + curation as CurationRevision, matchingRevisionAndReason ) if (matchingRevisionAndReason.length === 0) { @@ -1112,13 +1112,13 @@ ${this._formatDefinitions(patch.patches)}` }) const info = { type: 'auto', - summary: `Reprocess merged curation for ${EntityCoordinates.fromObject(curatedCoordinates).toString()}`, + summary: `Reprocess merged curation for ${EntityCoordinates.fromObject(curatedCoordinates)!.toString()}`, details: `Curated ${get(curation, ['licensed.declared'])} license`, resolution: `Automatically added versions based on merged curation:\n ${this._formatMultiversionCuratedRevisions(matchingRevisionAndReason)}` } const contribution = await this._addCurationWithMatchingRevisions( curatedCoordinates, - curation, + curation as CurationRevision, info, matchingRevisionAndReason ) @@ -1126,7 +1126,7 @@ ${this._formatDefinitions(patch.patches)}` processedRevisions.add(r.version) } contributions.push({ - coordinates: curatedCoordinates.toString(), + coordinates: curatedCoordinates!.toString(), contribution: get(contribution, 'data.html_url') }) } diff --git a/providers/curation/githubConfig.ts b/providers/curation/githubConfig.ts index 97b075e7..97dc4959 100644 --- a/providers/curation/githubConfig.ts +++ b/providers/curation/githubConfig.ts @@ -4,7 +4,7 @@ import config from 'painless-config' import type { ICache } from '../caching/index.js' import githubService from './github.ts' -import type { CurationHarvestStore, Endpoints, GitHubCurationOptions, ICurationStore } from './index.js' +import type { CurationDefinitionService, CurationHarvestStore, Endpoints, GitHubCurationOptions, ICurationStore } from './index.js' function github( options: GitHubCurationOptions | null | undefined, @@ -13,14 +13,14 @@ function github( cache: ICache, harvestStore: CurationHarvestStore ) { - const realOptions = options || { + const realOptions: GitHubCurationOptions = options || { owner: config.get('CURATION_GITHUB_OWNER') || 'clearlydefined', repo: config.get('CURATION_GITHUB_REPO') || 'curated-data', branch: config.get('CURATION_GITHUB_BRANCH') || 'master', - token: config.get('CURATION_GITHUB_TOKEN'), + token: config.get('CURATION_GITHUB_TOKEN')!, multiversionCurationFeatureFlag: config.get('MULTIVERSION_CURATION_FF') === 'true' } - return githubService(realOptions, store, endpoints, null, cache, harvestStore) + return githubService(realOptions, store, endpoints, null as unknown as CurationDefinitionService, cache, harvestStore) } export default github diff --git a/providers/curation/memoryStore.ts b/providers/curation/memoryStore.ts index 409be789..bb6f8843 100644 --- a/providers/curation/memoryStore.ts +++ b/providers/curation/memoryStore.ts @@ -26,8 +26,8 @@ class MemoryStore { updateCurations(curations: Curation[]) { for (const curation of curations) { - const coordinates = EntityCoordinates.fromObject(curation.data.coordinates) - this.curations[this._getCurationId(coordinates)] = curation.data + const coordinates = EntityCoordinates.fromObject(curation.data!.coordinates!)! + this.curations[this._getCurationId(coordinates)] = curation.data! } } @@ -39,7 +39,7 @@ class MemoryStore { if (curations) { const files: Record = {} for (const curation of curations) { - files[curation.path] = curation.data + files[curation.path] = curation.data! } this.contributions[pr.number] = { pr, files } return @@ -76,7 +76,7 @@ class MemoryStore { if (!coordinates) { return '' } - return EntityCoordinates.fromObject(coordinates).toString().toLowerCase() + return EntityCoordinates.fromObject(coordinates)!.toString().toLowerCase() } } diff --git a/providers/curation/mongoConfig.ts b/providers/curation/mongoConfig.ts index 1cdd6e48..17044d5a 100644 --- a/providers/curation/mongoConfig.ts +++ b/providers/curation/mongoConfig.ts @@ -6,8 +6,8 @@ import type { MongoCurationStoreOptions } from './mongoCurationStore.ts' import storeFactory from './mongoCurationStore.ts' function store(options?: MongoCurationStoreOptions) { - const realOptions = options || { - connectionString: config.get('CURATION_MONGO_CONNECTION_STRING'), + const realOptions: MongoCurationStoreOptions = options || { + connectionString: config.get('CURATION_MONGO_CONNECTION_STRING')!, dbName: config.get('CURATION_MONGO_DB_NAME') || 'clearlydefined', collectionName: config.get('CURATION_MONGO_COLLECTION_NAME') || 'curations' } diff --git a/providers/curation/mongoCurationStore.ts b/providers/curation/mongoCurationStore.ts index 72947431..c0f98b15 100644 --- a/providers/curation/mongoCurationStore.ts +++ b/providers/curation/mongoCurationStore.ts @@ -65,7 +65,7 @@ class MongoCurationStore { await Promise.all( curations.map( throat(10, async curation => { - const _id = this._getCurationId(curation.data.coordinates) + const _id = this._getCurationId(curation.data!.coordinates!) if (_id) { await this.collection.replaceOne({ _id }, { _id, ...curation.data }, { upsert: true }) } @@ -100,11 +100,11 @@ class MongoCurationStore { .map(curation => { return { path: curation.path, - coordinates: this._lowercaseCoordinates(curation.data.coordinates), - revisions: Object.keys(curation.data.revisions).map(revision => { + coordinates: this._lowercaseCoordinates(curation.data!.coordinates!), + revisions: Object.keys(curation.data!.revisions!).map(revision => { return { revision: revision.toLowerCase(), - data: curation.data.revisions[revision] + data: curation.data!.revisions![revision] } }) } @@ -152,7 +152,7 @@ class MongoCurationStore { if (!coordinates) { return '' } - return EntityCoordinates.fromObject(coordinates).toString().toLowerCase() + return EntityCoordinates.fromObject(coordinates)!.toString().toLowerCase() } _buildContributionQuery(coordinates: EntityCoordinates) { @@ -177,16 +177,16 @@ class MongoCurationStore { _formatCurations(curations: CurationData[]): Record { return curations.reduce((result: Record, entry) => { - for (const revision of Object.keys(entry.revisions)) { - const coordinates = EntityCoordinates.fromObject({ ...entry.coordinates, revision }).toString() - result[coordinates] = entry.revisions[revision] + for (const revision of Object.keys(entry.revisions!)) { + const coordinates = EntityCoordinates.fromObject({ ...entry.coordinates!, revision })!.toString() + result[coordinates] = entry.revisions![revision] } return result }, {}) } _lowercaseCoordinates(input: EntityCoordinatesSpec) { - return EntityCoordinates.fromString(EntityCoordinates.fromObject(input).toString().toLowerCase()) + return EntityCoordinates.fromString(EntityCoordinates.fromObject(input)!.toString().toLowerCase())! } _escapeRegex(string: string) { return string.replace(/[.*+?^${}()|[\]\\]/g, '\\$&') diff --git a/providers/harvest/azureQueueConfig.ts b/providers/harvest/azureQueueConfig.ts index dc9139be..35b0f08e 100644 --- a/providers/harvest/azureQueueConfig.ts +++ b/providers/harvest/azureQueueConfig.ts @@ -6,8 +6,8 @@ import type { AzureStorageQueueOptions } from '../queueing/azureStorageQueue.ts' import AzureStorageQueue from '../queueing/azureStorageQueue.ts' function azure(options?: AzureStorageQueueOptions): AzureStorageQueue { - const realOptions = options || { - connectionString: config.get('HARVEST_QUEUE_CONNECTION_STRING') || config.get('HARVEST_AZBLOB_CONNECTION_STRING'), + const realOptions: AzureStorageQueueOptions = options || { + connectionString: (config.get('HARVEST_QUEUE_CONNECTION_STRING') || config.get('HARVEST_AZBLOB_CONNECTION_STRING'))!, queueName: config.get('HARVEST_QUEUE_NAME') || 'harvests', dequeueOptions: { numOfMessages: 32, diff --git a/providers/harvest/crawlerConfig.ts b/providers/harvest/crawlerConfig.ts index a77421f5..1e09a80f 100644 --- a/providers/harvest/crawlerConfig.ts +++ b/providers/harvest/crawlerConfig.ts @@ -12,17 +12,17 @@ export interface CrawlerConfigOptions extends Partial { cachingService: ICache } -const crawlerConfig = { - authToken: config.get('CRAWLER_API_AUTH_TOKEN'), +const crawlerConfig: CrawlerOptions = { + authToken: config.get('CRAWLER_API_AUTH_TOKEN')!, url: config.get('CRAWLER_API_URL') || 'http://localhost:5000' } function serviceFactory(options?: CrawlerConfigOptions): CacheBasedHarvester { const crawlerOptions = { ...crawlerConfig, ...options } const harvester = crawler(crawlerOptions) - const cacheTTLSeconds = Number.parseInt(config.get('HARVEST_CACHE_TTL_IN_SECONDS'), 10) + const cacheTTLSeconds = Number.parseInt(config.get('HARVEST_CACHE_TTL_IN_SECONDS')!, 10) const cacheTTLInSeconds = Number.isFinite(cacheTTLSeconds) && cacheTTLSeconds > 0 ? cacheTTLSeconds : undefined - return cacheBasedCrawler({ ...options, cacheTTLInSeconds, harvester }) + return cacheBasedCrawler({ ...options, cacheTTLInSeconds, harvester } as import('./cacheBasedCrawler.ts').Options) } export default serviceFactory diff --git a/providers/harvest/crawlerQueueConfig.ts b/providers/harvest/crawlerQueueConfig.ts index 1eba73e8..2a6dcf41 100644 --- a/providers/harvest/crawlerQueueConfig.ts +++ b/providers/harvest/crawlerQueueConfig.ts @@ -15,16 +15,16 @@ export interface CrawlerQueueConfigOptions extends Partial } function later(options?: AzureStorageQueueOptions): AzureStorageQueue { - const realOptions = options || { - connectionString: config.get('HARVEST_QUEUE_CONNECTION_STRING') || config.get('HARVEST_AZBLOB_CONNECTION_STRING'), + const realOptions: AzureStorageQueueOptions = options || { + connectionString: (config.get('HARVEST_QUEUE_CONNECTION_STRING') || config.get('HARVEST_AZBLOB_CONNECTION_STRING'))!, queueName: `${config.get('HARVEST_QUEUE_PREFIX') || 'cdcrawlerdev'}-later` } return new AzureStorageQueue(realOptions) } function normal(options?: AzureStorageQueueOptions): AzureStorageQueue { - const realOptions = options || { - connectionString: config.get('HARVEST_QUEUE_CONNECTION_STRING') || config.get('HARVEST_AZBLOB_CONNECTION_STRING'), + const realOptions: AzureStorageQueueOptions = options || { + connectionString: (config.get('HARVEST_QUEUE_CONNECTION_STRING') || config.get('HARVEST_AZBLOB_CONNECTION_STRING'))!, queueName: `${config.get('HARVEST_QUEUE_PREFIX') || 'cdcrawlerdev'}-normal` } return new AzureStorageQueue(realOptions) @@ -38,9 +38,9 @@ function serviceFactory(options?: CrawlerQueueConfigOptions): CacheBasedHarveste crawlerOptions.later.initialize() crawlerOptions.normal.initialize() const harvester = crawler(crawlerOptions) - const cacheTTLSeconds = Number.parseInt(config.get('HARVEST_CACHE_TTL_IN_SECONDS'), 10) + const cacheTTLSeconds = Number.parseInt(config.get('HARVEST_CACHE_TTL_IN_SECONDS')!, 10) const cacheTTLInSeconds = Number.isFinite(cacheTTLSeconds) && cacheTTLSeconds > 0 ? cacheTTLSeconds : undefined - return cacheBasedCrawler({ ...options, cacheTTLInSeconds, harvester }) + return cacheBasedCrawler({ ...options, cacheTTLInSeconds, harvester } as import('./cacheBasedCrawler.ts').Options) } export default serviceFactory diff --git a/providers/harvest/throttling/listBasedFilter.ts b/providers/harvest/throttling/listBasedFilter.ts index 28b156cf..1c9aec36 100644 --- a/providers/harvest/throttling/listBasedFilter.ts +++ b/providers/harvest/throttling/listBasedFilter.ts @@ -22,9 +22,9 @@ class ListBasedFilter { this.logger = options.logger || loggerFactory() const raw = options.blacklist || [] // Normalize blacklist entries to versionless coordinates for broad matching - const versionlessCoordinates = raw.map(c => this._toVersionless(c)).filter(Boolean) + const versionlessCoordinates = raw.map(c => this._toVersionless(c)).filter((c): c is EntityCoordinates => c !== null) // Store as a Set for quick type lookup - this._targetTypes = new Set(versionlessCoordinates.map(c => c.type)) + this._targetTypes = new Set(versionlessCoordinates.map(c => c.type!)) this._blacklist = new Set(versionlessCoordinates.map(c => c.toString())) this.logger.info('ListBasedFilter initialized', { blockedCount: this._blacklist.size, @@ -37,7 +37,7 @@ class ListBasedFilter { if (!coord || this._blacklist.size === 0) { return false } - if (!this._targetTypes.has(coord.type)) { + if (!this._targetTypes.has(coord.type!)) { return false } const versionless = coord.asRevisionless().toString() @@ -48,10 +48,10 @@ class ListBasedFilter { try { const coordinates = EntityCoordinates.fromString(coordString) if (!validator.validate('versionless-coordinates-1.0', coordinates)) { - const errorMessage = validator.errors.map(e => `${e.instancePath} ${e.message}`).join(', ') + const errorMessage = validator.errors!.map(e => `${e.instancePath} ${e.message}`).join(', ') throw new Error(errorMessage) } - return coordinates.asRevisionless() + return coordinates!.asRevisionless() } catch (e) { this.logger.warn( `Invalid coordinates in blacklist, ignoring: ${coordString}, ${e instanceof Error ? e.message : String(e)}` diff --git a/providers/logging/winstonConfig.ts b/providers/logging/winstonConfig.ts index bd2e0422..0508b8bf 100644 --- a/providers/logging/winstonConfig.ts +++ b/providers/logging/winstonConfig.ts @@ -157,16 +157,16 @@ function factory(options?: WinstonLoggerOptions): winston.Logger { if (info.stack) { const exception = info.cause ? new Error(info.message, { cause: info.cause }) : new Error(info.message) exception.stack = info.stack - aiClient.trackException({ exception, properties }) + aiClient!.trackException({ exception, properties }) } else { - aiClient.trackTrace({ + aiClient!.trackTrace({ message: info.message, severity: appInsights.KnownSeverityLevel.Error, properties }) } } else { - aiClient.trackTrace({ message: info.message, severity: mapLevel(info.level), properties }) + aiClient!.trackTrace({ message: info.message, severity: mapLevel(info.level), properties }) } }) diff --git a/providers/queueing/azureStorageQueue.ts b/providers/queueing/azureStorageQueue.ts index 0faf0b55..7c741a6d 100644 --- a/providers/queueing/azureStorageQueue.ts +++ b/providers/queueing/azureStorageQueue.ts @@ -49,10 +49,10 @@ class AzureStorageQueue implements IQueue { if (!message) { return null } - if (message.dequeueCount <= 5) { + if (message.dequeueCount! <= 5) { return { original: message as unknown as QueueMessage, - data: JSON.parse(Buffer.from(message.messageText, 'base64').toString('utf8')) + data: JSON.parse(Buffer.from(message.messageText!, 'base64').toString('utf8')) } } await this.delete({ original: message as unknown as QueueMessage }) @@ -93,7 +93,7 @@ class AzureStorageQueue implements IQueue { await promisify(this.queueService.deleteMessage).bind(this.queueService)( this.options.queueName, String(message.original.messageId), - message.original.popReceipt + message.original.popReceipt! ) } } diff --git a/providers/queueing/memoryQueue.ts b/providers/queueing/memoryQueue.ts index 2fb4ffac..d0e47c10 100644 --- a/providers/queueing/memoryQueue.ts +++ b/providers/queueing/memoryQueue.ts @@ -20,7 +20,7 @@ export class MemoryQueue implements IQueue { constructor(options: MemoryQueueOptions) { this.options = options this.logger = this.options.logger || logger() - this.data = [] + this.data = [] as QueueMessage[] this.messageId = 0 this.decoder = options.decoder || ((text: string) => text) } @@ -60,7 +60,7 @@ export class MemoryQueue implements IQueue { } _parseData({ messageText }: QueueMessage) { - return JSON.parse(this.decoder(messageText)) + return JSON.parse(this.decoder(messageText!)) } /** Similar to dequeue() but returns an array instead. See AzureStorageQueue.dequeueMultiple() */ @@ -74,7 +74,7 @@ export class MemoryQueue implements IQueue { * pass dequeue() result as the message to delete */ async delete(message: DequeuedMessage): Promise { - const newData = [] + const newData: QueueMessage[] = [] for (let i = 0; i < this.data.length; i++) { if (this.data[i].messageId !== message.original.messageId) { newData.push(this.data[i]) diff --git a/providers/search/abstractSearch.ts b/providers/search/abstractSearch.ts index 3feabd62..a43a0e22 100644 --- a/providers/search/abstractSearch.ts +++ b/providers/search/abstractSearch.ts @@ -44,7 +44,7 @@ class AbstractSearch { } // TODO probably need to use a better comparison here that compares actual expressions rather than just the strings return uniq( - values(facets).reduce((result, facet) => result.concat(get(facet, 'discovered.expressions')), []) + values(facets).reduce((result, facet) => result.concat(get(facet, 'discovered.expressions') || []), [] as string[]) ).filter(e => e) } @@ -53,7 +53,7 @@ class AbstractSearch { if (!facets) { return [] } - return uniq(values(facets).reduce((result, facet) => result.concat(get(facet, 'attribution.parties')), [])).filter( + return uniq(values(facets).reduce((result, facet) => result.concat(get(facet, 'attribution.parties') || []), [] as string[])).filter( e => e ) } diff --git a/providers/search/azureConfig.ts b/providers/search/azureConfig.ts index 0a4a17e6..36fcfabc 100644 --- a/providers/search/azureConfig.ts +++ b/providers/search/azureConfig.ts @@ -7,12 +7,12 @@ import search from './azureSearch.ts' function serviceFactory(options?: AzureSearchOptions) { const realOptions: AzureSearchOptions = options || { - service: config.get('SEARCH_AZURE_SERVICE'), - apiKey: config.get('SEARCH_AZURE_API_KEY'), + service: config.get('SEARCH_AZURE_SERVICE')!, + apiKey: config.get('SEARCH_AZURE_API_KEY')!, dataSourceConnectionString: - config.get('SEARCH_AZURE_DATASOURCE_CONNECTION_STRING') || + (config.get('SEARCH_AZURE_DATASOURCE_CONNECTION_STRING') || config.get('DEFINITION_AZBLOB_CONNECTION_STRING') || - config.get('HARVEST_AZBLOB_CONNECTION_STRING'), + config.get('HARVEST_AZBLOB_CONNECTION_STRING'))!, dataSourceContainerName: config.get('SEARCH_AZURE_DATASOURCE_CONTAINER_NAME') || config.get('DEFINITION_AZBLOB_CONTAINER_NAME') || diff --git a/providers/search/memory.ts b/providers/search/memory.ts index 38648659..849aef32 100644 --- a/providers/search/memory.ts +++ b/providers/search/memory.ts @@ -59,7 +59,7 @@ class MemorySearch extends AbstractSearch { _getEntries(definitions: any[]) { return definitions.map((definition: any) => { return { - coordinates: EntityCoordinates.fromObject(definition.coordinates).toString(), + coordinates: EntityCoordinates.fromObject(definition.coordinates)!.toString(), releaseDate: get(definition, 'described.releaseDate'), declaredLicense: get(definition, 'licensed.declared'), discoveredLicenses: this._getLicenses(definition), diff --git a/providers/stores/abstractFileStore.ts b/providers/stores/abstractFileStore.ts index e240fa6b..f44b5410 100644 --- a/providers/stores/abstractFileStore.ts +++ b/providers/stores/abstractFileStore.ts @@ -85,7 +85,7 @@ class AbstractFileStore { return data ? visitor(JSON.parse(data.toString())) : null }) ) - ).filter(x => x) + ).filter((x): x is Awaited => x != null) } catch (error) { // If there is just no entry, that's fine, there is no content. const nodeError = error as NodeJS.ErrnoException @@ -206,7 +206,7 @@ class AbstractFileStore { static toResultCoordinatesFromStoragePath(path: string): ResultCoordinates { const trimmed = AbstractFileStore.trimStoragePath(path) - return ResultCoordinates.fromString(trimmed) + return ResultCoordinates.fromString(trimmed)! } static trimStoragePath(path: string): string { diff --git a/providers/stores/abstractMongoDefinitionStore.ts b/providers/stores/abstractMongoDefinitionStore.ts index 7bf6024a..b1e92846 100644 --- a/providers/stores/abstractMongoDefinitionStore.ts +++ b/providers/stores/abstractMongoDefinitionStore.ts @@ -240,7 +240,7 @@ class AbstractMongoDefinitionStore { if (!coordinates) { return '' } - return EntityCoordinatesClass.fromObject(coordinates).toString().toLowerCase() + return EntityCoordinatesClass.fromObject(coordinates)!.toString().toLowerCase() } buildQuery(parameters: MongoDefinitionQuery): Filter { diff --git a/providers/stores/azblobConfig.ts b/providers/stores/azblobConfig.ts index e4834112..6c7e16ac 100644 --- a/providers/stores/azblobConfig.ts +++ b/providers/stores/azblobConfig.ts @@ -19,10 +19,10 @@ const attachmentContainerName = config.get('ATTACHMENT_AZBLOB_CONTAINER_NAME') | */ function harvest(options?: AzBlobStoreOptions) { return azblobHarvestStore( - options || { + options || ({ connectionString: harvestConnectionString, containerName: harvestContainerName - } + } as AzBlobStoreOptions) ) } @@ -31,10 +31,10 @@ function harvest(options?: AzBlobStoreOptions) { */ function definition(options?: AzBlobStoreOptions) { return azblobDefinitionStore( - options || { + options || ({ connectionString: definitionConnectionString, containerName: definitionContainerName - } + } as AzBlobStoreOptions) ) } @@ -43,10 +43,10 @@ function definition(options?: AzBlobStoreOptions) { */ function attachment(options?: AzBlobStoreOptions) { return azblobAttachmentStore( - options || { + options || ({ connectionString: attachmentConnectionString, containerName: attachmentContainerName - } + } as AzBlobStoreOptions) ) } diff --git a/providers/stores/azblobDefinitionStore.ts b/providers/stores/azblobDefinitionStore.ts index cef7c872..ba52224a 100644 --- a/providers/stores/azblobDefinitionStore.ts +++ b/providers/stores/azblobDefinitionStore.ts @@ -2,7 +2,7 @@ // SPDX-License-Identifier: MIT import lodash from 'lodash' -import type { Definition, DefinitionStore } from '../../business/definitionService.ts' +import type { Definition, DefinitionFindQuery, DefinitionFindResult, DefinitionStore } from '../../business/definitionService.ts' import type { EntityCoordinates } from '../../lib/entityCoordinates.ts' import EntityCoordinatesClass from '../../lib/entityCoordinates.ts' import type { AzBlobStoreOptions, BlobEntry } from './abstractAzblobStore.ts' @@ -28,7 +28,7 @@ export class AzBlobDefinitionStore extends AbstractAzBlobStore implements Defini if (!path) { return null } - const entryCoordinates = EntityCoordinatesClass.fromString(path) + const entryCoordinates = EntityCoordinatesClass.fromString(path)! return AbstractFileStore.isInterestingCoordinates(entryCoordinates) ? path : null }) return sortedUniq(list.filter((x: string | null) => x)) @@ -64,6 +64,11 @@ export class AzBlobDefinitionStore extends AbstractAzBlobStore implements Defini } } } + + // @ts-expect-error - AzBlob store does not support find; satisfies DefinitionStore interface + override async find(_query: DefinitionFindQuery, _continuationToken?: string): Promise { + return super.find() as unknown as DefinitionFindResult + } } /** diff --git a/providers/stores/azblobHarvestStore.ts b/providers/stores/azblobHarvestStore.ts index 8fb261a6..d60fb18f 100644 --- a/providers/stores/azblobHarvestStore.ts +++ b/providers/stores/azblobHarvestStore.ts @@ -46,7 +46,7 @@ export class AzHarvestBlobStore extends AbstractAzBlobStore { if (!urn) { return null } - const entryCoordinates = ResultCoordinatesClass.fromUrn(urn) + const entryCoordinates = ResultCoordinatesClass.fromUrn(urn)! return AbstractFileStore.isInterestingCoordinates(entryCoordinates) ? entryCoordinates.toString() : null }) return sortedUniq(list.filter((x: any) => x)) diff --git a/providers/stores/dispatchDefinitionStore.ts b/providers/stores/dispatchDefinitionStore.ts index 9a73d2f0..398d4585 100644 --- a/providers/stores/dispatchDefinitionStore.ts +++ b/providers/stores/dispatchDefinitionStore.ts @@ -50,8 +50,8 @@ export class DispatchDefinitionStore implements DefinitionStore { /** * List definitions from the first store that returns results. */ - list(coordinates: EntityCoordinates): Promise { - return this._performInSequence(store => store.list(coordinates)) + list(coordinates: EntityCoordinates): Promise { + return this._performInSequence(store => store.list(coordinates)) as Promise } /** @@ -72,18 +72,18 @@ export class DispatchDefinitionStore implements DefinitionStore { * Find definitions from the first store that returns results. */ find(query: DefinitionFindQuery, continuationToken = ''): Promise { - return this._performInSequence(store => store.find(query, continuationToken)) + return this._performInSequence(store => store.find(query, continuationToken)) as Promise } async _performInSequence(operation: (store: DefinitionStore) => Promise, first = true): Promise { - let result = null + let result: T | null = null for (let i = 0; i < this.stores.length; i++) { const store = this.stores[i] try { const opResult = await operation(store) result = result || opResult if (result && first) { - return result + return result as T } } catch (error) { this.logger.error('DispatchDefinitionStore failure', error) diff --git a/providers/stores/fileHarvestStore.ts b/providers/stores/fileHarvestStore.ts index ff191ed3..b47e6eab 100644 --- a/providers/stores/fileHarvestStore.ts +++ b/providers/stores/fileHarvestStore.ts @@ -35,7 +35,7 @@ export class FileHarvestStore extends AbstractFileStore { if (!link) { return null } - return ResultCoordinatesClass.fromUrn(link).toString() + return ResultCoordinatesClass.fromUrn(link)!.toString() }) return sortedUniq(list.filter(x => x)) } @@ -90,9 +90,9 @@ export class FileHarvestStore extends AbstractFileStore { ) return contents.reduce((result, entry) => { const { tool, toolVersion } = this._toResultCoordinatesFromStoragePath(entry.name) - result[tool] = result[tool] || {} - const current = result[tool] - current[toolVersion] = entry.content + result[tool!] = result[tool!] || {} + const current = result[tool!] + current[toolVersion!] = entry.content return result }, {} as ToolOutputs) } diff --git a/providers/stores/mongo.ts b/providers/stores/mongo.ts index 89e8cee3..e8909b9b 100644 --- a/providers/stores/mongo.ts +++ b/providers/stores/mongo.ts @@ -45,7 +45,7 @@ export class MongoStore extends AbstractMongoDefinitionStore implements Definiti * Get and return the object at the given coordinates. * Reassembles paginated definitions automatically. */ - override async get(coordinates: EntityCoordinates): Promise { + override async get(coordinates: EntityCoordinates): Promise { const cursor = await this.collection.find( { '_mongo.partitionKey': this.getId(coordinates) }, { projection: { _id: 0, _mongo: 0 }, sort: { '_mongo.page': 1 } } @@ -55,10 +55,10 @@ export class MongoStore extends AbstractMongoDefinitionStore implements Definiti if (!definition) { definition = page } else { - definition.files = definition.files.concat(page['files']) + definition.files = definition.files!.concat(page['files']) } } - return definition + return definition ?? null } /** @@ -102,7 +102,7 @@ export class MongoStore extends AbstractMongoDefinitionStore implements Definiti page: index + 1, totalPages: pages }, - files: definition.files.slice(index * pageSize, index * pageSize + pageSize) + files: definition.files!.slice(index * pageSize, index * pageSize + pageSize) } }, { ordered: false } @@ -115,9 +115,8 @@ export class MongoStore extends AbstractMongoDefinitionStore implements Definiti * Delete a definition from MongoDB. * Removes all pages of the definition. */ - override async delete(coordinates: EntityCoordinates): Promise { + override async delete(coordinates: EntityCoordinates): Promise { await this.collection.deleteMany({ '_mongo.partitionKey': this.getId(coordinates) }) - return null } /** diff --git a/providers/stores/mongoConfig.ts b/providers/stores/mongoConfig.ts index 4dae45f5..52648b9e 100644 --- a/providers/stores/mongoConfig.ts +++ b/providers/stores/mongoConfig.ts @@ -17,10 +17,10 @@ const dbOptions = { */ function definitionPaged(options?: MongoDefinitionStoreOptions) { return mongo( - options || { + options || ({ ...dbOptions, collectionName: config.get('DEFINITION_MONGO_COLLECTION_NAME') || 'definitions-paged' - } + } as MongoDefinitionStoreOptions) ) } @@ -36,10 +36,10 @@ function definitionTrimmed(options?: MongoDefinitionStoreOptions) { ) } return TrimmedMongoDefinitionStore( - options || { + options || ({ ...dbOptions, collectionName: config.get('DEFINITION_MONGO_TRIMMED_COLLECTION_NAME') || oldConfig || 'definitions-trimmed' - } + } as MongoDefinitionStoreOptions) ) } diff --git a/providers/summary/clearlydefined.ts b/providers/summary/clearlydefined.ts index 1a8a0349..55d8fd1d 100644 --- a/providers/summary/clearlydefined.ts +++ b/providers/summary/clearlydefined.ts @@ -280,7 +280,7 @@ export class ClearlyDescribedSummarizer { } const spec = data.sourceInfo updateSourceLocation(spec) - spec.url = buildSourceUrl(spec) + spec.url = buildSourceUrl(spec) ?? undefined set(result, 'described.sourceLocation', spec) } @@ -316,7 +316,7 @@ export class ClearlyDescribedSummarizer { const newDefinition = cloneDeep(result) const newFiles = cloneDeep(data.interestingFiles) for (const file of newFiles as { license?: string; path: string; natures?: string[] }[]) { - file.license = SPDX.normalize(file.license) + file.license = file.license ? (SPDX.normalize(file.license) ?? undefined) : undefined if (!file.license) { delete file.license } else if (isLicenseFile(file.path, coordinates)) { @@ -352,8 +352,8 @@ export class ClearlyDescribedSummarizer { break default: - urls.registry = `${mavenBasedUrls[coordinates.provider]}/${namespaceAsFolders}/${coordinates.name}` - urls.download = `${mavenBasedUrls[coordinates.provider]}/${namespaceAsFolders}/${coordinates.name}/${coordinates.revision}/${coordinates.name}-${coordinates.revision}.jar` + urls.registry = `${mavenBasedUrls[coordinates.provider!]}/${namespaceAsFolders}/${coordinates.name}` + urls.download = `${mavenBasedUrls[coordinates.provider!]}/${namespaceAsFolders}/${coordinates.name}/${coordinates.revision}/${coordinates.name}-${coordinates.revision}.jar` } return urls @@ -373,9 +373,9 @@ export class ClearlyDescribedSummarizer { ...flatten(projectSummaryLicenses.map((x: MavenLicenseInfo) => x.url)) ]).filter((x: unknown) => x) const licenseNames = uniq(flatten(licenseSummaries.map((license: MavenLicenseInfo) => license.name))) - let licenses = licenseUrls.map((url: string) => extractLicenseFromLicenseUrl(url)).filter((x: unknown) => x) + let licenses = licenseUrls.map(url => extractLicenseFromLicenseUrl(url!)).filter((x): x is string => !!x) if (!licenses.length) { - licenses = licenseNames.map((x: string) => SPDX.lookupByName(x) || x).filter((x: unknown) => x) + licenses = licenseNames.map(x => SPDX.lookupByName(x!) || x!).filter((x): x is string => !!x) } return licenses } @@ -396,23 +396,23 @@ export class ClearlyDescribedSummarizer { addCondaData(result: SummaryResult, data: ClearlyDefinedHarvestedData, coordinates: EntityCoordinates) { setIfValue(result, 'described.releaseDate', extractDate(get(data, 'releaseDate'))) setIfValue(result, 'described.urls.download', get(data, 'registryData.downloadUrl')) - setIfValue(result, 'described.urls.registry', new URL(`${condaChannels[coordinates.provider]}`).href) + setIfValue(result, 'described.urls.registry', new URL(`${condaChannels[coordinates.provider!]}`).href) setIfValue(result, 'described.projectWebsite', get(data, 'registryData.channelData.home')) const condaLicense = Array.isArray(data.declaredLicenses) ? data.declaredLicenses.join(' AND ') : data.declaredLicenses - setIfValue(result, 'licensed.declared', SPDX.normalize(condaLicense)) + if (condaLicense) setIfValue(result, 'licensed.declared', SPDX.normalize(condaLicense)) } addCondaSrcData(result: SummaryResult, data: ClearlyDefinedHarvestedData, coordinates: EntityCoordinates) { setIfValue(result, 'described.releaseDate', extractDate(data.releaseDate)) setIfValue(result, 'described.urls.download', get(data, 'registryData.channelData.source_url')) - setIfValue(result, 'described.urls.registry', new URL(`${condaChannels[coordinates.provider]}`).href) + setIfValue(result, 'described.urls.registry', new URL(`${condaChannels[coordinates.provider!]}`).href) setIfValue(result, 'described.projectWebsite', get(data, 'registryData.channelData.home')) const condaSrcLicense = Array.isArray(data.declaredLicenses) ? data.declaredLicenses.join(' AND ') : data.declaredLicenses - setIfValue(result, 'licensed.declared', SPDX.normalize(condaSrcLicense)) + if (condaSrcLicense) setIfValue(result, 'licensed.declared', SPDX.normalize(condaSrcLicense)) } addCrateData(result: SummaryResult, data: ClearlyDefinedHarvestedData, coordinates: EntityCoordinates) { @@ -453,10 +453,11 @@ export class ClearlyDescribedSummarizer { addNuGetData(result: SummaryResult, data: ClearlyDefinedHarvestedData, coordinates: EntityCoordinates) { setIfValue(result, 'described.releaseDate', extractDate(data.releaseDate)) - const licenseExpression = SPDX.normalize(get(data, 'manifest.licenseExpression') as string | undefined) + const licenseExpression = get(data, 'manifest.licenseExpression') as string | undefined + const normalizedLicenseExpression = licenseExpression ? SPDX.normalize(licenseExpression) : null const licenseUrl = get(data, 'manifest.licenseUrl') as string | undefined - if (licenseExpression) { - set(result, 'licensed.declared', licenseExpression) + if (normalizedLicenseExpression) { + set(result, 'licensed.declared', normalizedLicenseExpression) } else if (licenseUrl?.trim()) { set(result, 'licensed.declared', extractLicenseFromLicenseUrl(licenseUrl) || 'NOASSERTION') } @@ -505,7 +506,7 @@ export class ClearlyDescribedSummarizer { } return ( stringObjectArray(manifest.license) || - (packageType === 'npm' && stringObjectArray((manifest as NpmManifest).licenses)) + (packageType === 'npm' ? stringObjectArray((manifest as NpmManifest).licenses) : null) ) } @@ -588,7 +589,8 @@ export class ClearlyDescribedSummarizer { setIfValue(result, 'described.projectWebsite', get(data, 'registryData.homepage')) const license = get(data, 'registryData.license') as string | { type?: string } | undefined if (license) { - setIfValue(result, 'licensed.declared', SPDX.normalize(typeof license === 'string' ? license : license.type)) + const licenseStr = typeof license === 'string' ? license : license.type + if (licenseStr) setIfValue(result, 'licensed.declared', SPDX.normalize(licenseStr)) } setIfValue(result, 'described.urls.registry', `https://cocoapods.org/pods/${coordinates.name}`) @@ -608,7 +610,8 @@ export class ClearlyDescribedSummarizer { addGemData(result: SummaryResult, data: ClearlyDefinedHarvestedData, coordinates: EntityCoordinates) { setIfValue(result, 'described.releaseDate', extractDate(data.releaseDate)) - const license = SPDX.normalize(get(data, 'registryData.license') as string | undefined) + const gemLicenseRaw = get(data, 'registryData.license') as string | undefined + const license = gemLicenseRaw ? SPDX.normalize(gemLicenseRaw) : null if (license) { set(result, 'licensed.declared', license) } else { @@ -640,7 +643,7 @@ export class ClearlyDescribedSummarizer { | Record | undefined if (releases) { - const revision = find(releases[coordinates.revision], revision => + const revision = find(releases[coordinates.revision!], revision => revision.filename ? revision.filename.includes('tar.gz') || revision.filename.includes('zip') : false ) if (revision) { @@ -689,13 +692,13 @@ export class ClearlyDescribedSummarizer { if (registryUrl) { set(result, 'described.urls.registry', registryUrl) set(result, 'described.urls.version', registryUrl) - if (result.described.sourceLocation) { + if (result.described?.sourceLocation) { result.described.sourceLocation.url = registryUrl } } - const architecture = coordinates.revision.split('_')[1] + const architecture = coordinates.revision!.split('_')[1] const downloadUrl = new URL( - `http://ftp.debian.org/debian/${registryData.find((entry: DebianRegistryEntry) => entry.Architecture === architecture).Path}` + `http://ftp.debian.org/debian/${registryData.find((entry: DebianRegistryEntry) => entry.Architecture === architecture)!.Path}` ).href setIfValue(result, 'described.urls.download', downloadUrl) const license = uniq(data.declaredLicenses || []).join(' AND ') @@ -712,10 +715,10 @@ export class ClearlyDescribedSummarizer { if (registryUrl) { set(result, 'described.urls.registry', registryUrl) set(result, 'described.urls.version', registryUrl) - result.described.sourceLocation = { ...coordinates, url: registryUrl } + result.described!.sourceLocation = { ...coordinates, url: registryUrl } } const downloadUrl = new URL( - `http://ftp.debian.org/debian/${registryData.find((entry: DebianRegistryEntry) => entry.Path.includes('.orig.tar.')).Path}` + `http://ftp.debian.org/debian/${registryData.find((entry: DebianRegistryEntry) => entry.Path.includes('.orig.tar.'))!.Path}` ).href // There is also patches URL which is related to sources but it's not part of the schema setIfValue(result, 'described.urls.download', downloadUrl) @@ -757,4 +760,4 @@ export class ClearlyDescribedSummarizer { } } -export default (options?: SummarizerOptions) => new ClearlyDescribedSummarizer(options) +export default (options?: SummarizerOptions) => new ClearlyDescribedSummarizer(options!) diff --git a/providers/summary/fossology.ts b/providers/summary/fossology.ts index 7c43a016..294fd9e5 100644 --- a/providers/summary/fossology.ts +++ b/providers/summary/fossology.ts @@ -65,7 +65,7 @@ export class FOSSologySummarizer { declare options: SummarizerOptions constructor(options?: SummarizerOptions) { - this.options = options + this.options = options! } summarize(coordinates: EntityCoordinates, harvested: FossologyHarvestedData): FossologySummaryResult { diff --git a/providers/summary/licensee.ts b/providers/summary/licensee.ts index f617c66c..c05efdf8 100644 --- a/providers/summary/licensee.ts +++ b/providers/summary/licensee.ts @@ -91,17 +91,17 @@ export class LicenseeSummarizer { } return files .map(file => { - if (get(file, 'matcher.name') !== 'exact') { + if (file.matcher?.name !== 'exact') { return null } - if (80 > +get(file, 'matcher.confidence')) { + if (80 > +(file.matcher?.confidence ?? 0)) { return null } const path = file.filename const attachment = attachments.find(x => x.path === path) - const license = SPDX.normalize(file.matched_license) + const license = file.matched_license ? SPDX.normalize(file.matched_license) : null if (path && isDeclaredLicense(license)) { - const resultFile: FileEntry = { path, license, natures: ['license'] } + const resultFile: FileEntry = { path, license: license!, natures: ['license'] } setIfValue(resultFile, 'token', get(attachment, 'token')) return resultFile } diff --git a/providers/summary/reuse.ts b/providers/summary/reuse.ts index 09fa3ab4..e8a2d7b3 100644 --- a/providers/summary/reuse.ts +++ b/providers/summary/reuse.ts @@ -75,7 +75,7 @@ export class ReuseSummarizer { } summarize(_coordinates: EntityCoordinates, harvested: ReuseHarvestedData): ReuseSummaryResult { - if (!harvested?.reuse?.metadata.CreatorTool) { + if (!harvested?.reuse?.metadata!.CreatorTool) { throw new Error('Invalid REUSE data') } const result = {} @@ -95,10 +95,10 @@ export class ReuseSummarizer { const licenses = get(harvested, 'reuse.licenses') as ReuseLicense[] | undefined if (licenses) { for (const license of licenses) { - const licenseSpdxId = SPDX.normalize(license.spdxId) + const licenseSpdxId = license.spdxId ? SPDX.normalize(license.spdxId) : null if (license.filePath && isDeclaredLicense(licenseSpdxId)) { const attachment = attachments.find(x => x.path === license.filePath) - const licenseFile: FileEntry = { path: license.filePath, license: licenseSpdxId, natures: ['license'] } + const licenseFile: FileEntry = { path: license.filePath, license: licenseSpdxId!, natures: ['license'] } setIfValue(licenseFile, 'token', get(attachment, 'token')) licenseFiles.push(licenseFile) } @@ -111,9 +111,9 @@ export class ReuseSummarizer { if (!isDeclaredLicense(declaredLicense)) { declaredLicense = file.LicenseInfoInFile } - const license = SPDX.normalize(declaredLicense) + const license = declaredLicense ? SPDX.normalize(declaredLicense) : null if (path && isDeclaredLicense(license)) { - const resultFile: FileEntry = { path, license, hashes: { sha1: file.FileChecksumSHA1 } } + const resultFile: FileEntry = { path, license: license!, hashes: { sha1: file.FileChecksumSHA1! } } if (file.FileCopyrightText && file.FileCopyrightText !== 'NONE') { resultFile.attributions = [file.FileCopyrightText] } @@ -130,7 +130,7 @@ export class ReuseSummarizer { return } const declaredLicenses = harvested.reuse.licenses - .map(license => (isDeclaredLicense(SPDX.normalize(license.spdxId)) ? license.spdxId : null)) + .map(license => (license.spdxId && isDeclaredLicense(SPDX.normalize(license.spdxId)) ? license.spdxId : null)) .filter((x): x is string => x !== null) setIfValue(result, 'licensed.declared', uniq(declaredLicenses).join(' AND ')) } diff --git a/providers/summary/scancode.ts b/providers/summary/scancode.ts index 6882b968..7ede1b5f 100644 --- a/providers/summary/scancode.ts +++ b/providers/summary/scancode.ts @@ -146,4 +146,4 @@ export class ScanCodeSummarizer { } } -export default (options?: SummarizerOptions, logger?: Logger) => new ScanCodeSummarizer(options, logger) +export default (options?: SummarizerOptions, logger?: Logger) => new ScanCodeSummarizer(options!, logger) diff --git a/providers/summary/scancode/legacy-summarizer.ts b/providers/summary/scancode/legacy-summarizer.ts index 9c6884a6..2c944491 100644 --- a/providers/summary/scancode/legacy-summarizer.ts +++ b/providers/summary/scancode/legacy-summarizer.ts @@ -63,7 +63,7 @@ export class ScanCodeLegacySummarizer { addDescribedInfo(result: ScanCodeSummaryResult, harvested: ScanCodeHarvestedData) { const releaseDate = harvested._metadata.releaseDate if (releaseDate) { - result.described = { releaseDate: extractDate(releaseDate.trim()) } + result.described = { releaseDate: extractDate(releaseDate.trim())! } } } @@ -83,7 +83,8 @@ export class ScanCodeLegacySummarizer { case '2.9.8': case '3.0.0': case '3.0.2': - return SPDX.normalize(get(harvested, 'content.summary.packages[0].declared_license') as string | undefined) + const declLicense = get(harvested, 'content.summary.packages[0].declared_license') as string | undefined + return declLicense ? SPDX.normalize(declLicense) ?? null : null case '30.1.0': { const rawDeclaredLicense = get(harvested, 'content.summary.packages[0].declared_license') as | string @@ -106,7 +107,8 @@ export class ScanCodeLegacySummarizer { declared_license = declared_license.name || declared_license.license } - return SPDX.normalize(declared_license as string | undefined) + const finalLicense = declared_license as string | undefined + return finalLicense ? SPDX.normalize(finalLicense) ?? null : null } default: throw new Error(`Invalid version of ScanCode: ${scancodeVersion}`) @@ -116,7 +118,7 @@ export class ScanCodeLegacySummarizer { _readLicenseExpressionFromSummary(harvested: ScanCodeHarvestedData): string | null { const licenseExpression = get(harvested, 'content.summary.packages[0].license_expression') as string | undefined const result = licenseExpression && normalizeLicenseExpression(licenseExpression, this.logger, null) - return result?.includes('NOASSERTION') ? null : result + return result?.includes('NOASSERTION') ? null : result ?? null } _getRootFiles(coordinates: EntityCoordinates, files: ScanCodeFile[], packages?: ScanCodePackage[]): ScanCodeFile[] { @@ -210,7 +212,7 @@ export class ScanCodeLegacySummarizer { asserted, new Set(), // TODO, is `license.license` real? - license => license.license || license.spdx_license_key + license => (license.license || license.spdx_license_key)! ) return joinExpressions(packageLicenses) } @@ -264,7 +266,7 @@ export class ScanCodeLegacySummarizer { _createExpressionFromLicense(license: ScanCodeLicense): string | null { const rule = license.matched_rule if (!rule?.license_expression) { - return SPDX.normalize(license.spdx_license_key) + return license.spdx_license_key ? SPDX.normalize(license.spdx_license_key) ?? null : null } return normalizeLicenseExpression(rule.license_expression, this.logger, null) } diff --git a/providers/summary/scancode/new-summarizer.ts b/providers/summary/scancode/new-summarizer.ts index 2b003c69..16ffa2e8 100644 --- a/providers/summary/scancode/new-summarizer.ts +++ b/providers/summary/scancode/new-summarizer.ts @@ -70,7 +70,7 @@ export class ScanCodeNewSummarizer { addDescribedInfo(result: ScanCodeSummaryResult, harvestedData: ScanCodeHarvestedData) { const releaseDate = harvestedData._metadata.releaseDate if (releaseDate) { - result.described = { releaseDate: extractDate(releaseDate.trim()) } + result.described = { releaseDate: extractDate(releaseDate.trim())! } } } @@ -95,7 +95,7 @@ export class ScanCodeNewSummarizer { const licenseExpression = get(content, 'summary.declared_license_expression') as string | undefined const result = licenseExpression && normalizeLicenseExpression(licenseExpression, this.logger) - return result?.includes('NOASSERTION') ? null : result + return result?.includes('NOASSERTION') ? null : result ?? null } _readDeclaredLicenseExpressionFromPackage({ content }: ScanCodeHarvestedData): string | null { @@ -110,12 +110,12 @@ export class ScanCodeNewSummarizer { const licenseExpression = firstPackage.declared_license_expression_spdx - return licenseExpression?.includes('NOASSERTION') ? null : licenseExpression + return licenseExpression?.includes('NOASSERTION') ? null : licenseExpression ?? null } _readExtractedLicenseStatementFromPackage({ content }: ScanCodeHarvestedData): string | null { const declared_license = get(content, 'packages[0].extracted_license_statement') as string | undefined - return SPDX.normalize(declared_license) + return declared_license ? SPDX.normalize(declared_license) ?? null : null } _getRootFiles(coordinates: EntityCoordinates, files: ScanCodeFile[], packages?: ScanCodePackage[]): ScanCodeFile[] { @@ -148,7 +148,7 @@ export class ScanCodeNewSummarizer { _getFileLicensesFromDetectedLicenseExpressions(files: ScanCodeFile[]): string | null { const fullLicenses = new Set( files - .filter((file: ScanCodeFile) => file.percentage_of_license_text >= 90 && file.detected_license_expression_spdx) + .filter((file: ScanCodeFile) => file.percentage_of_license_text! >= 90 && file.detected_license_expression_spdx) .map((file: ScanCodeFile) => file.detected_license_expression_spdx as string) ) return joinExpressions(fullLicenses) @@ -167,7 +167,7 @@ export class ScanCodeNewSummarizer { if (licenseDetection.matches) { for (const match of licenseDetection.matches as { score?: number; spdx_license_expression?: string }[]) { // Only consider matches with high clarity score of 90 or higher - if (match.score >= 90 && match.spdx_license_expression) { + if (match.score! >= 90 && match.spdx_license_expression) { licenses.add(match.spdx_license_expression) } } @@ -190,7 +190,7 @@ export class ScanCodeNewSummarizer { } else if (licenseDetection.matches) { for (const match of licenseDetection.matches as { score?: number; spdx_license_expression?: string }[]) { // Only consider matches with a reasonably high score of 80 or higher - if (match.score >= 80 && match.spdx_license_expression) { + if (match.score! >= 80 && match.spdx_license_expression) { licenseExpressions.add(match.spdx_license_expression) } } diff --git a/providers/upgrade/azureQueueConfig.ts b/providers/upgrade/azureQueueConfig.ts index dde20529..f22b3b20 100644 --- a/providers/upgrade/azureQueueConfig.ts +++ b/providers/upgrade/azureQueueConfig.ts @@ -8,7 +8,7 @@ import AzureStorageQueue from '../queueing/azureStorageQueue.ts' const upgradeDefaultOptions: AzureStorageQueueOptions = { connectionString: - config.get('DEFINITION_UPGRADE_QUEUE_CONNECTION_STRING') || config.get('HARVEST_AZBLOB_CONNECTION_STRING'), + (config.get('DEFINITION_UPGRADE_QUEUE_CONNECTION_STRING') || config.get('HARVEST_AZBLOB_CONNECTION_STRING'))!, queueName: config.get('DEFINITION_UPGRADE_QUEUE_NAME') || 'definitions-upgrade', dequeueOptions: { numOfMessages: config.get('DEFINITION_UPGRADE_DEQUEUE_BATCH_SIZE') || 16, @@ -18,9 +18,9 @@ const upgradeDefaultOptions: AzureStorageQueueOptions = { const computeDefaultOptions: AzureStorageQueueOptions = { connectionString: - config.get('DEFINITION_COMPUTE_QUEUE_CONNECTION_STRING') || + (config.get('DEFINITION_COMPUTE_QUEUE_CONNECTION_STRING') || config.get('DEFINITION_UPGRADE_QUEUE_CONNECTION_STRING') || - config.get('HARVEST_AZBLOB_CONNECTION_STRING'), + config.get('HARVEST_AZBLOB_CONNECTION_STRING'))!, queueName: config.get('DEFINITION_COMPUTE_QUEUE_NAME') || 'recompute', dequeueOptions: { numOfMessages: 32, // Azure Storage Queue maximum; compute queue is high-traffic (~10K/hr) diff --git a/providers/upgrade/defVersionCheck.ts b/providers/upgrade/defVersionCheck.ts index 8120ed51..9c09026a 100644 --- a/providers/upgrade/defVersionCheck.ts +++ b/providers/upgrade/defVersionCheck.ts @@ -41,10 +41,10 @@ class DefinitionVersionChecker implements UpgradeHandler { } const defSchemaVersion = get(definition, '_meta.schemaVersion') this.logger.debug( - `Definition version: ${defSchemaVersion}, Current schema version: ${this._currentSchema}, Coordinates: ${DefinitionVersionChecker.getCoordinates(definition)}` + `Definition version: ${defSchemaVersion}, Current schema version: ${this._currentSchema}, Coordinates: ${DefinitionVersionChecker.getCoordinates(definition!)}` ) if (defSchemaVersion && gte(defSchemaVersion, this._currentSchema)) { - return definition + return definition! } return undefined } @@ -57,8 +57,8 @@ class DefinitionVersionChecker implements UpgradeHandler { //do nothing for set up processing } - static getCoordinates(definition: Definition): string | undefined { - return definition?.coordinates && EntityCoordinates.fromObject(definition.coordinates).toString() + static getCoordinates(definition: Definition | null): string | undefined { + return definition?.coordinates && EntityCoordinates.fromObject(definition.coordinates)!.toString() } } diff --git a/providers/upgrade/recomputeHandler.ts b/providers/upgrade/recomputeHandler.ts index 6eae6430..66e72ca0 100644 --- a/providers/upgrade/recomputeHandler.ts +++ b/providers/upgrade/recomputeHandler.ts @@ -60,7 +60,7 @@ class RecomputeHandler implements IRecomputeHandler { } async validate(definition: Definition | null): Promise { - return this._upgradePolicy.validate(definition) + return this._upgradePolicy.validate(definition) as Promise } async initialize(): Promise { diff --git a/routes/auth.ts b/routes/auth.ts index 0b895ff2..5d040c8c 100644 --- a/routes/auth.ts +++ b/routes/auth.ts @@ -73,11 +73,11 @@ let endpoints: AuthEndpoints | null = null function passportOrPat(): RequestHandler { let passportAuth: RequestHandler | null = null function handler(request: Request, response: Response, next: NextFunction): void { - if (options.clientId) { + if (options!.clientId) { passportAuth = passportAuth || passport.authenticate('github', { session: false }) - passportAuth(request, response, next) + passportAuth!(request, response, next) } else { - request.user = { githubAccessToken: options.token } + request.user = { githubAccessToken: options!.token } next() } } @@ -108,21 +108,21 @@ router.get('/github', (req, res) => { router.get('/github/start', passportOrPat(), (_req, res) => { // this only runs if passport didn't kick in above, but double // check for sanity in case upstream changes - if (!options.clientId) { + if (!options!.clientId) { res.redirect('finalize') } }) router.get('/github/finalize', passportOrPat(), async (req, res) => { - const token = req.user.githubAccessToken - const { publicEmails, permissions } = await getUserDetails(token, options.org) - const username = req.user.username + const token = req.user!.githubAccessToken + const { publicEmails, permissions } = await getUserDetails(token, options!.org) + const username = req.user!.username const result = JSON.stringify({ type: 'github-token', token, permissions, username, publicEmails }) // allow for sending auth responses to localhost on dev site; see /github // route above. real origin is stored in cookie. - let origin = endpoints.website - if (endpoints.service.includes('dev-api') && req.cookies.localhostOrigin) { + let origin = endpoints!.website + if (endpoints!.service.includes('dev-api') && req.cookies.localhostOrigin) { origin = req.cookies.localhostOrigin } @@ -154,7 +154,7 @@ async function getUserDetails(token: string, org: string): Promise .filter(entry => entry.organization.login === org) .map(entry => entry.name) .map(findPermissions) - .filter(e => e) + .filter((e): e is string => e !== null) return { publicEmails, permissions } } catch (err) { @@ -180,7 +180,7 @@ async function getUserDetails(token: string, org: string): Promise * Finds the permission name associated with a team. */ function findPermissions(team: string): string | null { - const permissions = options.permissions + const permissions = options!.permissions for (const permission in permissions) { if (permissions[permission].includes(team)) { return permission @@ -202,7 +202,7 @@ function setup(authOptions: AuthOptions, authEndpoints: AuthEndpoints): void { * Returns whether passport should be used for OAuth authentication. */ function usePassport(): boolean { - return !!options.clientId + return !!options!.clientId } /** @@ -212,10 +212,10 @@ function usePassport(): boolean { function getStrategy(): GitHubStrategy { return new GitHubStrategy( { - clientID: options.clientId, - clientSecret: options.clientSecret, + clientID: options!.clientId!, + clientSecret: options!.clientSecret!, // this needs to match the callback url on the oauth app on github - callbackURL: `${endpoints.service}/auth/github/finalize`, + callbackURL: `${endpoints!.service}/auth/github/finalize`, scope: ['public_repo', 'read:user', 'read:org', 'user:email'] }, (access, _refresh, profile, done) =>