Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions bin/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down
34 changes: 17 additions & 17 deletions business/definitionService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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 */
Expand Down Expand Up @@ -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
}

Expand Down Expand Up @@ -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])
}

Expand All @@ -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()
)
}

Expand Down Expand Up @@ -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)!
}
}
}
Expand Down Expand Up @@ -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 {
Expand Down Expand Up @@ -847,7 +847,7 @@ export class DefinitionService {

_collectLicenseTexts(definition: Definition): string[] {
const result: Set<string> = 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)
Expand All @@ -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. */
Expand All @@ -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', {
Expand Down Expand Up @@ -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)
Expand All @@ -999,7 +999,7 @@ export class DefinitionService {
return
}
this._ensureDescribed(definition)
definition.described.sourceLocation = { ...coordinates, url }
definition.described!.sourceLocation = { ...coordinates, url }
break
}
default:
Expand All @@ -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()}`
}
}

Expand Down
2 changes: 1 addition & 1 deletion business/suggestionService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ export class SuggestionService {
*/
async _getRelatedDefinitions(coordinates: EntityCoordinates): Promise<RelatedDefinitions | null> {
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)
Comment on lines 88 to 91
Copy link

Copilot AI Apr 15, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

query.namespace is being assigned null via (null as unknown as string), which defeats type checking and makes it hard to reason about the query shape. Since downstream query logic appears to intentionally treat namespace: null as "explicitly match no-namespace definitions", consider updating the query type to allow namespace?: string | null (e.g., DefinitionFindQuery.namespace) or introducing a dedicated query type for this use case, rather than casting null to string.

Copilot uses AI. Check for mistakes.
const definitions = results.data.sort((a, b) =>
compareDates(get(a, 'described.releaseDate'), get(b, 'described.releaseDate'))
Expand Down
8 changes: 4 additions & 4 deletions lib/licenseMatcher.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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
}

Expand Down Expand Up @@ -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)
}
Expand Down Expand Up @@ -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 }
22 changes: 11 additions & 11 deletions middleware/github.ts
Original file line number Diff line number Diff line change
Expand Up @@ -73,29 +73,29 @@ 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)

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<string[]> => {
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()
Expand Down Expand Up @@ -128,11 +128,11 @@ async function setupUserClient(req: Request, token: string | null): Promise<Octo

// Get GitHub user info and attach it to the request
async function setupInfo(req: Request, cacheKey: string, client: Octokit): Promise<void> {
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
}
Expand All @@ -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
}
Expand Down
4 changes: 2 additions & 2 deletions middleware/githubConfig.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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 */ })
Expand Down
6 changes: 3 additions & 3 deletions providers/caching/redisConfig.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
4 changes: 2 additions & 2 deletions providers/curation/azureQueueConfig.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
Loading
Loading