mirror of
https://github.com/Kaelio/ktx.git
synced 2026-07-04 10:52:13 +02:00
chore(workspace): gate dead-code with knip production mode
Turn on production-mode knip plus an autofix run in pre-commit and the `pnpm dead-code` script, document the `/** @internal */` convention for test-only exports in AGENTS.md, annotate test-only exports across the CLI with that JSDoc, and drop dead exports/wrappers the new gate surfaced (e.g. `cli-project.ts`, `lookerRuntimeSourceToFileAdapterSource`, `createLocalScanEnrichmentProvidersFromConfig`, `PGLITE_OWNER_PROCESS_BACKEND_CAPABILITIES`, stale type re-exports). Replace the loose `ignoreIssues` allowlist in `knip.json` with explicit production entries so cross-package barrel leaks are caught.
This commit is contained in:
parent
ac3885b652
commit
b690e6988b
71 changed files with 211 additions and 279 deletions
|
|
@ -3,6 +3,7 @@ import { join, relative } from 'node:path';
|
|||
|
||||
const YAML_EXT_RE = /\.(ya?ml)$/i;
|
||||
|
||||
/** @internal */
|
||||
export function normalizeDbtPath(path: string): string {
|
||||
return path.replaceAll('\\', '/');
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,13 +1,14 @@
|
|||
import { Buffer } from 'node:buffer';
|
||||
import type { StagedPatternsInput } from './types.js';
|
||||
|
||||
export const HISTORIC_SQL_PATTERN_WORKUNIT_DIR = 'patterns-input';
|
||||
const HISTORIC_SQL_PATTERN_WORKUNIT_DIR = 'patterns-input';
|
||||
/** @internal */
|
||||
export const HISTORIC_SQL_PATTERN_WORKUNIT_MAX_BYTES = 110_000;
|
||||
export const HISTORIC_SQL_PATTERN_WORKUNIT_PATH_RE = /^patterns-input\/part-\d{4}\.json$/;
|
||||
const HISTORIC_SQL_PATTERN_WORKUNIT_PATH_RE = /^patterns-input\/part-\d{4}\.json$/;
|
||||
|
||||
type PatternTemplate = StagedPatternsInput['templates'][number];
|
||||
|
||||
export interface HistoricSqlPatternInputShard {
|
||||
interface HistoricSqlPatternInputShard {
|
||||
path: string;
|
||||
input: StagedPatternsInput;
|
||||
byteLength: number;
|
||||
|
|
@ -27,10 +28,11 @@ export function isHistoricSqlPatternInputShardPath(path: string): boolean {
|
|||
return HISTORIC_SQL_PATTERN_WORKUNIT_PATH_RE.test(path);
|
||||
}
|
||||
|
||||
export function serializeStagedPatternsInput(input: StagedPatternsInput): string {
|
||||
function serializeStagedPatternsInput(input: StagedPatternsInput): string {
|
||||
return `${JSON.stringify(input, null, 2)}\n`;
|
||||
}
|
||||
|
||||
/** @internal */
|
||||
export function serializedStagedPatternsInputByteLength(input: StagedPatternsInput): number {
|
||||
return Buffer.byteLength(serializeStagedPatternsInput(input), 'utf-8');
|
||||
}
|
||||
|
|
|
|||
|
|
@ -33,6 +33,7 @@ function tableSortKey(table: KtxTableRef): string {
|
|||
return `${table.catalog ?? ''}\u0000${table.db ?? ''}\u0000${table.name}`;
|
||||
}
|
||||
|
||||
/** @internal */
|
||||
export function liveDatabaseTablePath(table: KtxTableRef): string {
|
||||
return `${LIVE_DATABASE_TABLES_DIR}/${encodePathPart(table.catalog)}.${encodePathPart(table.db)}.${encodePathPart(
|
||||
table.name,
|
||||
|
|
|
|||
|
|
@ -1,11 +1,11 @@
|
|||
import { mkdir, writeFile } from 'node:fs/promises';
|
||||
import { dirname, join } from 'node:path';
|
||||
import type { ParsedTargetTable } from '../../parsed-target-table.js';
|
||||
import type { FetchContext } from '../../types.js';
|
||||
import { writeLookerEvidenceDocuments } from './evidence-documents.js';
|
||||
import { writeLookerFetchReport } from './fetch-report.js';
|
||||
import {
|
||||
type LookerPullConfig,
|
||||
type ParsedTargetTable,
|
||||
parseLookerPullConfig,
|
||||
STAGED_FILES,
|
||||
type StagedDashboardFile,
|
||||
|
|
|
|||
|
|
@ -1,11 +1,6 @@
|
|||
import type { ParsedTargetTable } from '../../parsed-target-table.js';
|
||||
import type { LookerWarehouseConnectionInfo } from './client.js';
|
||||
import type {
|
||||
LookerPullConfig,
|
||||
LookerRuntimeCursors,
|
||||
ParsedTargetTable,
|
||||
StagedExploreFile,
|
||||
StagedLookmlModelsFile,
|
||||
} from './types.js';
|
||||
import type { LookerPullConfig, LookerRuntimeCursors, StagedExploreFile, StagedLookmlModelsFile } from './types.js';
|
||||
|
||||
export const LOOKER_DIALECT_TO_CONNECTION_TYPE = {
|
||||
bigquery: 'BIGQUERY',
|
||||
|
|
|
|||
|
|
@ -1,17 +1,5 @@
|
|||
import { describe, expect, it } from 'vitest';
|
||||
import { buildLookerReconcileNotes, lookerRuntimeSourceToFileAdapterSource } from './reconcile.js';
|
||||
|
||||
describe('lookerRuntimeSourceToFileAdapterSource', () => {
|
||||
it('maps API-derived Looker source names to file-adapter source names', () => {
|
||||
expect(lookerRuntimeSourceToFileAdapterSource('looker__b2b__sales_pipeline')).toBe('b2b__sales_pipeline');
|
||||
expect(lookerRuntimeSourceToFileAdapterSource('looker__finance__orders')).toBe('finance__orders');
|
||||
});
|
||||
|
||||
it('ignores non-Looker and malformed source names', () => {
|
||||
expect(lookerRuntimeSourceToFileAdapterSource('b2b__sales_pipeline')).toBeNull();
|
||||
expect(lookerRuntimeSourceToFileAdapterSource('looker__missing_explore')).toBeNull();
|
||||
});
|
||||
});
|
||||
import { buildLookerReconcileNotes } from './reconcile.js';
|
||||
|
||||
describe('buildLookerReconcileNotes', () => {
|
||||
it('instructs reconciliation to record subsumed provenance', () => {
|
||||
|
|
|
|||
|
|
@ -1,16 +1,3 @@
|
|||
export function lookerRuntimeSourceToFileAdapterSource(sourceName: string): string | null {
|
||||
if (!sourceName.startsWith('looker__')) {
|
||||
return null;
|
||||
}
|
||||
const stripped = sourceName.slice('looker__'.length);
|
||||
const parts = stripped.split('__');
|
||||
if (parts.length < 2 || parts.some((part) => part.length === 0)) {
|
||||
return null;
|
||||
}
|
||||
const [model, ...exploreParts] = parts;
|
||||
return `${model}__${exploreParts.join('__')}`;
|
||||
}
|
||||
|
||||
export function buildLookerReconcileNotes(): string[] {
|
||||
return [
|
||||
[
|
||||
|
|
|
|||
|
|
@ -1,7 +1,8 @@
|
|||
import { tool } from 'ai';
|
||||
import { z } from 'zod';
|
||||
import type { ToolOutput } from '../../../../tools/index.js';
|
||||
import { type ParsedTargetTable, stagedLookerQuerySchema } from '../types.js';
|
||||
import type { ParsedTargetTable } from '../../../parsed-target-table.js';
|
||||
import { stagedLookerQuerySchema } from '../types.js';
|
||||
|
||||
const lookerUsageInputSchema = z.object({
|
||||
queryCount30d: z.number().int().nonnegative().default(0),
|
||||
|
|
|
|||
|
|
@ -1,8 +1,8 @@
|
|||
import { describe, expect, it } from 'vitest';
|
||||
import { parsedTargetTableSchema } from '../../parsed-target-table.js';
|
||||
import {
|
||||
lookerPullConfigSchema,
|
||||
parseLookerPullConfig,
|
||||
parsedTargetTableSchema,
|
||||
stagedDashboardFileSchema,
|
||||
stagedExploreFileSchema,
|
||||
stagedLookerFetchIssueSchema,
|
||||
|
|
|
|||
|
|
@ -7,8 +7,6 @@ const nullableLookerIdSchema = z.union([lookerIdSchema, z.null()]).default(null)
|
|||
|
||||
export const lookerConnectionIdSchema = z.string().min(1).regex(/^[A-Za-z0-9_-]+$/);
|
||||
|
||||
export { parsedTargetTableSchema, type ParsedTargetTable } from '../../parsed-target-table.js';
|
||||
|
||||
export const lookerRuntimeCursorsSchema = z.object({
|
||||
dashboardsLastSyncedAt: z.iso.datetime().nullable().default(null),
|
||||
looksLastSyncedAt: z.iso.datetime().nullable().default(null),
|
||||
|
|
@ -16,6 +14,7 @@ export const lookerRuntimeCursorsSchema = z.object({
|
|||
|
||||
export type LookerRuntimeCursors = z.infer<typeof lookerRuntimeCursorsSchema>;
|
||||
|
||||
/** @internal */
|
||||
export const lookerPullConfigSchema = z.object({
|
||||
lookerConnectionId: lookerConnectionIdSchema.optional(),
|
||||
instanceBaseUrl: z.url().optional(),
|
||||
|
|
|
|||
|
|
@ -4,7 +4,9 @@ import * as z from 'zod';
|
|||
import type { SourceFetchReport } from '../../types.js';
|
||||
import type { ParsedLookmlProject } from './parse.js';
|
||||
|
||||
/** @internal */
|
||||
export const LOOKML_FETCH_REPORT_FILE = 'lookml-fetch-report.json';
|
||||
/** @internal */
|
||||
export const LOOKML_MISMATCHED_MODELS_FILE = 'lookml-mismatched-models.json';
|
||||
|
||||
const fetchIssueKindSchema = z.enum([
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
import * as z from 'zod';
|
||||
import { parsedTargetTableSchema } from '../../parsed-target-table.js';
|
||||
|
||||
export const lookmlPullConfigSchema = z.object({
|
||||
const lookmlPullConfigSchema = z.object({
|
||||
repoUrl: z.string().url(),
|
||||
branch: z.string().default('main'),
|
||||
path: z.string().nullable().default(null),
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ const CARD_REF_RE = /\{\{#(\d+)\}\}/g;
|
|||
* Input TemplateTag shape mirrors `MetabaseClient.getTemplateTags` output. We keep the
|
||||
* shape loose — only `name`, `type`, and optional `cardReference`/`default` are needed here.
|
||||
*/
|
||||
/** @internal */
|
||||
export interface InputTemplateTag {
|
||||
name: string;
|
||||
type: string;
|
||||
|
|
@ -13,6 +14,7 @@ export interface InputTemplateTag {
|
|||
defaultValue?: string | null;
|
||||
}
|
||||
|
||||
/** @internal */
|
||||
export function extractReferencedCardIds(templateTags: InputTemplateTag[], sql: string): number[] {
|
||||
const ids = new Set<number>();
|
||||
for (const tag of templateTags) {
|
||||
|
|
@ -34,7 +36,7 @@ export function extractReferencedCardIds(templateTags: InputTemplateTag[], sql:
|
|||
* care about. The adapter reads whatever the client returns; this helper stays
|
||||
* duck-typed so the client's type can evolve without churn here.
|
||||
*/
|
||||
export interface InputCard {
|
||||
interface InputCard {
|
||||
id: number;
|
||||
name: string;
|
||||
description?: string | null;
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
import { z } from 'zod';
|
||||
|
||||
export const metabaseSyncModeSchema = z.enum(['ALL', 'ONLY', 'EXCEPT']);
|
||||
const metabaseSyncModeSchema = z.enum(['ALL', 'ONLY', 'EXCEPT']);
|
||||
export type MetabaseSyncMode = z.infer<typeof metabaseSyncModeSchema>;
|
||||
|
||||
export const metabaseLocalConnectionIdSchema = z.string().regex(/^[a-zA-Z0-9][a-zA-Z0-9_-]*$/);
|
||||
|
|
@ -25,7 +25,7 @@ export function parseMetabasePullConfig(raw: unknown): MetabasePullConfig {
|
|||
}
|
||||
|
||||
/** A Metabase column from `card.result_metadata`. Mirrors what the LLM consumes today. */
|
||||
export const stagedResultColumnSchema = z.object({
|
||||
const stagedResultColumnSchema = z.object({
|
||||
name: z.string(),
|
||||
display_name: z.string().optional().nullable(),
|
||||
base_type: z.string(),
|
||||
|
|
@ -37,7 +37,7 @@ export const stagedResultColumnSchema = z.object({
|
|||
|
||||
export type StagedResultColumn = z.infer<typeof stagedResultColumnSchema>;
|
||||
|
||||
export const stagedParameterSchema = z.object({
|
||||
const stagedParameterSchema = z.object({
|
||||
id: z.string(),
|
||||
name: z.string(),
|
||||
type: z.string(),
|
||||
|
|
@ -49,7 +49,7 @@ export const stagedParameterSchema = z.object({
|
|||
export type StagedParameter = z.infer<typeof stagedParameterSchema>;
|
||||
|
||||
/** A template tag pulled from an MBQL card's `dataset_query.stages[0].template-tags`. */
|
||||
export const stagedTemplateTagSchema = z.object({
|
||||
const stagedTemplateTagSchema = z.object({
|
||||
name: z.string(),
|
||||
type: z.string(),
|
||||
defaultValue: z.string().optional().nullable(),
|
||||
|
|
@ -87,7 +87,7 @@ export const stagedCardFileSchema = z.object({
|
|||
export type StagedCardFile = z.infer<typeof stagedCardFileSchema>;
|
||||
|
||||
/** A serialized collection file, `collections/<id>.json`. Minimal — path lives on the card. */
|
||||
export const stagedCollectionFileSchema = z.object({
|
||||
const stagedCollectionFileSchema = z.object({
|
||||
metabaseId: z.union([z.number().int(), z.literal('root')]),
|
||||
name: z.string(),
|
||||
parentId: z.union([z.number().int(), z.literal('root')]).nullable(),
|
||||
|
|
@ -96,7 +96,7 @@ export const stagedCollectionFileSchema = z.object({
|
|||
export type StagedCollectionFile = z.infer<typeof stagedCollectionFileSchema>;
|
||||
|
||||
/** A serialized database-mapping snapshot, `databases/<id>.json`. */
|
||||
export const stagedDatabaseFileSchema = z.object({
|
||||
const stagedDatabaseFileSchema = z.object({
|
||||
metabaseDatabaseId: z.number().int().positive(),
|
||||
metabaseDatabaseName: z.string(),
|
||||
metabaseEngine: z.string().nullable(),
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ import { readdir, readFile } from 'node:fs/promises';
|
|||
import { join, relative } from 'node:path';
|
||||
import { parse as parseYaml } from 'yaml';
|
||||
|
||||
export interface ParsedMetricFlowSemanticModel {
|
||||
interface ParsedMetricFlowSemanticModel {
|
||||
/** Path relative to stagedDir, e.g. "models/orders.yml". */
|
||||
path: string;
|
||||
/** `name:` on the semantic_model. */
|
||||
|
|
@ -24,9 +24,9 @@ export interface ParsedMetricFlowSemanticModel {
|
|||
defaultTimeDimension: string | null;
|
||||
}
|
||||
|
||||
export type MetricFlowMetricType = 'simple' | 'derived' | 'cumulative' | 'ratio' | 'conversion';
|
||||
type MetricFlowMetricType = 'simple' | 'derived' | 'cumulative' | 'ratio' | 'conversion';
|
||||
|
||||
export interface ParsedMetricFlowMetric {
|
||||
interface ParsedMetricFlowMetric {
|
||||
path: string;
|
||||
name: string;
|
||||
type: MetricFlowMetricType;
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ import { kmeans, pickK } from '../../clustering/kmeans.js';
|
|||
import type { WorkUnit } from '../../types.js';
|
||||
import { notionMetadataSchema } from './types.js';
|
||||
|
||||
/** @internal */
|
||||
export const MIN_PAGES_TO_CLUSTER = 5;
|
||||
const CLUSTER_TEXT_BODY_CHARS = 1024;
|
||||
const CLUSTER_SEED = 42;
|
||||
|
|
|
|||
|
|
@ -14,6 +14,7 @@ function richTextToMarkdown(value: unknown): string {
|
|||
.trim();
|
||||
}
|
||||
|
||||
/** @internal */
|
||||
export function propertyValueToText(value: unknown): string {
|
||||
if (!value || typeof value !== 'object' || !('type' in value)) {
|
||||
return '';
|
||||
|
|
|
|||
|
|
@ -89,6 +89,7 @@ function shouldRetryNotionError(error: unknown): boolean {
|
|||
return code === 'rate_limited' || transientErrorCodes.has(code ?? '') || transientStatusCodes.has(status ?? 0);
|
||||
}
|
||||
|
||||
/** @internal */
|
||||
export async function retryNotionRequest<T>(operation: () => Promise<T>, options: RetryOptions = {}): Promise<T> {
|
||||
const maxAttempts = options.maxAttempts ?? 4;
|
||||
const sleep = options.sleep ?? defaultSleep;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue