lemon-devkit
Version:
Lemon Serverless Micro-Service Platform for local development
225 lines (224 loc) • 8.34 kB
TypeScript
/**
* `fields/types.ts`
* - `lemon-fields` 마이그레이션/생성기에서 공유하는 공통 타입.
*
* **NOTE**
* - `field-gen.ts`, `field-migrate.ts`, 테스트에서 같은 옵션/결과 타입을 쓰도록 분리함.
* - 런타임 헬퍼는 각 구현 파일에 두고, 여기서는 타입만 관리한다.
* - `ts-morph`, node API를 import 하지 않는다.
*
* @author Claire <claire@lemoncloud.io>
* @date 2026-04-17 separated field public types.
* @copyright (C) lemoncloud.io 2026 - All Rights Reserved.
*/
/**
* type: `DerivationInput`
* - legacy `keys<T>()` 호출 위치에서 registry property 이름을 만들기 위한 입력값.
*/
export interface DerivationInput {
/** 프로젝트 기준 상대 경로. `/` 로 normalize 된 값 */
relPath: string;
/** generic argument 원문. ex) `UserModel`, `A & B` */
typeArgText: string;
/** 가장 가까운 변수/프로퍼티/함수명. 복합 타입 이름 생성에 이용됨 */
enclosingContext?: string;
}
/**
* type: `FieldSiteSkip`
* - 자동 처리하지 못한 호출 위치.
*/
export interface FieldSiteSkip {
/** 프로젝트 기준 상대 경로. `/` 로 normalize 된 값 */
relPath: string;
/** generic argument 원문. type arg가 없으면 빈 문자열 */
typeArgText: string;
/** CLI 출력용 짧은 사유 */
reason: string;
}
/**
* type: `FieldRewrite`
* - `lemon-fields migrate`가 rewrite 한 legacy 호출 위치.
*/
export interface FieldRewrite {
/** rewrite 된 프로젝트 기준 상대 경로 */
relPath: string;
/** source에 기록된 registry property 이름 */
name: string;
/** 원래 generic argument 원문 */
typeArgText: string;
}
/**
* type: `GenOptions`
* - `lemon-fields gen`에서 사용하는 옵션.
*/
export interface GenOptions {
/** tsconfig 경로. 절대경로 또는 cwd 기준 상대경로 */
tsconfig: string;
/** 생성할 registry 파일 경로. 절대경로 또는 cwd 기준 상대경로 */
out: string;
/** `*.spec.ts` 스캔 여부 */
includeSpec: boolean;
/** 스캔 대상 glob. 타입 해석은 전체 project를 로드한 상태로 수행함 */
paths?: string[];
/** 남아있는 legacy `keys<T>()`를 허용하고 임시 이름을 생성할지 여부 */
allowLegacy: boolean;
/** 호출 위치가 없어도 실패하지 않고 bootstrap stub을 반환할지 여부 */
allowEmpty: boolean;
/** divergent duplicate registry name을 source callsite rewrite로 자동 보정할지 여부 */
repairDuplicateNames?: boolean;
/** 프로젝트 root. 기본값은 dirname(tsconfig) */
cwd?: string;
}
/**
* type: `RegistryEntry`
* - 생성될 registry property 1개.
*/
export interface RegistryEntry {
/** registry property 이름. migrated source에 기록된 이름을 그대로 보존함 */
name: string;
/** TypeScript checker가 해석한 field 이름 목록 */
fields: string[];
/** 호출 위치가 있는 프로젝트 기준 상대 경로 */
relPath: string;
/** generic argument 원문 */
typeArgText: string;
/** `gen --allow-legacy`로 legacy 호출에서 만들어진 entry 여부 */
legacy: boolean;
}
/**
* type: `GenResult`
* - `runGen()` 실행 결과.
*/
export interface GenResult {
/** `fieldKeys`로 render 될 concrete entry 목록 */
entries: RegistryEntry[];
/** 생성될 파일 전체 내용 */
content: string;
/** 기존 output 파일 내용. 파일이 없으면 undefined */
existing?: string;
/** `content !== existing` 이면 true */
changed: boolean;
/** 타입 property 이름을 materialise 하지 못한 호출 위치 */
skipped: FieldSiteSkip[];
/** 스캔 중 발견한 legacy `keys<T>()` 호출 위치 */
legacyLeftovers: Array<Omit<FieldSiteSkip, 'reason'>>;
/** `gen` 중 자동 보정된 duplicate registry name 호출 위치 */
repairs: FieldRewrite[];
/** source가 변경된 파일의 절대 경로 목록 */
changedFiles: string[];
}
/**
* type: `MigrateOptions`
* - `lemon-fields migrate`에서 사용하는 옵션.
*/
export interface MigrateOptions {
/** tsconfig 경로. 절대경로 또는 cwd 기준 상대경로 */
tsconfig: string;
/** 생성될 registry 파일 경로. 절대경로 또는 cwd 기준 상대경로 */
out: string;
/** `*.spec.ts` 스캔 여부 */
includeSpec: boolean;
/** 스캔 대상 glob. 타입 해석은 전체 project를 로드한 상태로 수행함 */
paths?: string[];
/** source 파일과 bootstrap stub을 쓰지 않고 변경 결과만 계산 */
dryRun: boolean;
/** 변경될 source diff를 결과에 포함할지 여부 */
diff?: boolean;
/** 자동 rewrite 불가 위치를 throw 대신 skipped로 보고할지 여부 */
allowSkips: boolean;
/** migration 완료 후 ts-transformer-keys transformer plugin을 tsconfig에서 제거할지 여부 */
updateTsconfig?: boolean;
/** 프로젝트 root. 기본값은 dirname(tsconfig) */
cwd?: string;
}
/**
* type: `FieldRegistryMeta`
* - generated registry 파일에 함께 내보내는 메타데이터.
*/
export interface FieldRegistryMeta {
/** `'concrete'`: 실제 entry가 있는 registry. `'bootstrap'`: 빈 stub. */
kind: 'concrete' | 'bootstrap';
/** 현재 값 1. 의미 변경 시 bump. */
schemaVersion: 1;
/** registry entry 개수. */
entryCount: number;
/** entry name+fields의 canonical JSON sha256 앞 16자. bootstrap은 빈 문자열. */
checksum: string;
generatedBy: 'lemon-fields';
}
/** validate 함수가 반환하는 issue code. */
export type IssueCode = 'META_MISSING' | 'UNSUPPORTED_SCHEMA' | 'BOOTSTRAP_STUB' | 'ENTRY_COUNT_MISMATCH' | 'CHECKSUM_MISMATCH' | 'NON_FUNCTION_ENTRY' | 'ENTRY_EVAL_FAILED' | 'INVALID_FIELD_LIST' | 'EMPTY_CONCRETE_REGISTRY';
/**
* type: `FieldRegistryValidationIssue`
* - `validateFieldRegistry()`가 반환하는 개별 검증 issue.
*/
export interface FieldRegistryValidationIssue {
code: IssueCode;
message: string;
/** 특정 entry key에 귀속되는 issue인 경우. */
entryKey?: string;
}
/**
* type: `FieldRegistryValidationResult`
* - `validateFieldRegistry()` 반환값.
*/
export interface FieldRegistryValidationResult {
ok: boolean;
issues: FieldRegistryValidationIssue[];
}
/**
* type: `MigrateResult`
* - `runMigrate()` 실행 결과.
*/
export interface MigrateResult {
/** rewrite 된 모든 호출 위치 */
rewrites: FieldRewrite[];
/** 자동 rewrite 하지 못한 호출 위치 */
skipped: FieldSiteSkip[];
/** source가 변경된 파일의 절대 경로 목록 */
changedFiles: string[];
/** bootstrap registry stub을 `out`에 썼으면 true */
wroteStub: boolean;
/** `--diff` 출력용 line diff */
diffs?: string[];
/** tsconfig plugin 정리가 수행되었거나 dry-run에서 수행 예정이면 true */
updatedTsconfig?: boolean;
}
/**
* type: `GuardCommonOptions`
* - `lemon-fields guard-common`에서 transformer spec의 common field guard를 삽입/갱신하는 옵션.
*/
export interface GuardCommonOptions {
/** tsconfig 경로. 절대경로 또는 cwd 기준 상대경로 */
tsconfig: string;
/** generated field registry 경로. 절대경로 또는 cwd 기준 상대경로 */
out?: string;
/** scan 대상 glob. 기본값은 spec 파일 glob */
paths?: string[];
/** 찾을 함수/변수명. 기본값은 `checkAllKeys` */
targetName: string;
/** source 파일을 쓰지 않고 변경 결과만 계산 */
dryRun: boolean;
/** 변경될 source diff를 결과에 포함할지 여부 */
diff?: boolean;
/** 프로젝트 root. 기본값은 dirname(tsconfig) */
cwd?: string;
}
/**
* type: `GuardCommonResult`
* - `lemon-fields guard-common` 실행 결과.
*/
export interface GuardCommonResult {
/** 삽입/갱신된 guard 목록 */
guards: Array<{
relPath: string;
targetName: string;
varName: string;
expected: string;
action: 'inserted' | 'updated';
}>;
/** source가 변경된 파일의 절대 경로 목록 */
changedFiles: string[];
/** 변경될 source diff */
diffs?: string[];
}