mirror of
https://github.com/stablyai/orca.git
synced 2026-09-23 00:02:29 +00:00
Enable three unicorn rules — one correctness, two performance — and fix every existing violation repo-wide so the rules pass as errors. prefer-number-properties (76 sites) - parseInt/parseFloat/NaN -> Number.* : safe aliases (autofixed). - isNaN -> Number.isNaN (12 sites, hand-converted): global isNaN coerces its argument, Number.isNaN does not. Verified every call site already passes a number (Number.parseInt results, number-typed fields, Date.getTime()), so the conversion is behavior-preserving today and guards against a future non-numeric argument silently coercing. prefer-array-find (26 sites) - .filter(pred)[0] -> .find(pred); .filter(pred).at(-1) / .pop() -> .findLast(pred). Drops the intermediate array and short-circuits. prefer-array-index-of (5 sites) - .findIndex(x => x === v) -> .indexOf(v). Verified: typecheck (node/cli/web) clean, 53 affected suites pass (1679 tests), oxlint clean repo-wide. mobile/ uses findLast safely (already ships ES2023 .toReversed()); config scripts and e2e helpers run on Node 24.
83 lines
2.4 KiB
TypeScript
83 lines
2.4 KiB
TypeScript
export function buildLinearTeamUrl(args: {
|
|
organizationUrlKey?: string | null
|
|
teamKey?: string | null
|
|
}): string | null {
|
|
const organizationUrlKey = args.organizationUrlKey?.trim()
|
|
const teamKey = args.teamKey?.trim()
|
|
if (!organizationUrlKey || !teamKey) {
|
|
return null
|
|
}
|
|
return `https://linear.app/${encodeURIComponent(organizationUrlKey)}/team/${encodeURIComponent(teamKey)}/all`
|
|
}
|
|
|
|
export function buildLinearPersonalApiKeySettingsUrl(organizationUrlKey?: string | null): string {
|
|
const trimmed = organizationUrlKey?.trim()
|
|
return trimmed
|
|
? `https://linear.app/${encodeURIComponent(trimmed)}/settings/account/security`
|
|
: 'https://linear.app/settings/account/security'
|
|
}
|
|
|
|
export function buildLinearWorkspaceApiSettingsUrl(organizationUrlKey?: string | null): string {
|
|
const trimmed = organizationUrlKey?.trim()
|
|
return trimmed
|
|
? `https://linear.app/${encodeURIComponent(trimmed)}/settings/api`
|
|
: 'https://linear.app/settings/api'
|
|
}
|
|
|
|
export function getLinearOrganizationUrlKeyFromIssueUrl(issueUrl?: string | null): string | null {
|
|
if (!issueUrl) {
|
|
return null
|
|
}
|
|
try {
|
|
const parsed = new URL(issueUrl)
|
|
if (parsed.hostname !== 'linear.app') {
|
|
return null
|
|
}
|
|
return parsed.pathname.split('/').find(Boolean) ?? null
|
|
} catch {
|
|
return null
|
|
}
|
|
}
|
|
|
|
export type ParsedLinearIssueInput = {
|
|
identifier: string
|
|
organizationUrlKey?: string
|
|
}
|
|
|
|
const LINEAR_IDENTIFIER_PATTERN = /^[A-Za-z][A-Za-z0-9_]*-\d+$/
|
|
|
|
export function parseLinearIssueInput(input: string): ParsedLinearIssueInput | null {
|
|
const trimmed = input.trim()
|
|
if (!trimmed) {
|
|
return null
|
|
}
|
|
|
|
if (LINEAR_IDENTIFIER_PATTERN.test(trimmed)) {
|
|
return { identifier: trimmed.toUpperCase() }
|
|
}
|
|
|
|
try {
|
|
const parsed = new URL(trimmed)
|
|
if (parsed.hostname !== 'linear.app') {
|
|
return null
|
|
}
|
|
const parts = parsed.pathname.split('/').filter(Boolean)
|
|
const issueIndex = parts.indexOf('issue')
|
|
const organizationUrlKey = parts[0]
|
|
const rawIdentifier = issueIndex >= 0 ? parts[issueIndex + 1] : undefined
|
|
if (!organizationUrlKey || !rawIdentifier) {
|
|
return null
|
|
}
|
|
const identifier = decodeURIComponent(rawIdentifier).split(/[/?#]/)[0]
|
|
if (!LINEAR_IDENTIFIER_PATTERN.test(identifier)) {
|
|
return null
|
|
}
|
|
return {
|
|
identifier: identifier.toUpperCase(),
|
|
organizationUrlKey: decodeURIComponent(organizationUrlKey)
|
|
}
|
|
} catch {
|
|
return null
|
|
}
|
|
}
|