isthmus-cli 0.4.0 → 0.4.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.ko.md +9 -8
- package/README.md +14 -14
- package/dist/cli/atomic-write.d.ts +5 -2
- package/dist/cli/atomic-write.js +10 -3
- package/dist/cli/atomic-write.js.map +1 -1
- package/dist/cli/check-command.js +3 -1
- package/dist/cli/check-command.js.map +1 -1
- package/dist/exchange/parse.js +12 -3
- package/dist/exchange/parse.js.map +1 -1
- package/dist/join/join.js +6 -1
- package/dist/join/join.js.map +1 -1
- package/dist/report/retentions.d.ts +7 -0
- package/dist/report/retentions.js +20 -5
- package/dist/report/retentions.js.map +1 -1
- package/package.json +1 -1
package/README.ko.md
CHANGED
|
@@ -28,14 +28,15 @@ isthmus는 각 언어 도구가 내보낸 **브리지 사실**(채널 이름 ·
|
|
|
28
28
|
|
|
29
29
|
## 상태
|
|
30
30
|
|
|
31
|
-
**0.4.
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
SARIF 2.1.0 렌더링(`check --format sarif`,
|
|
35
|
-
지문), 브리지가 없는 프로젝트와 아무것도
|
|
36
|
-
관찰량(`observedFacts`·`observedLimitations`),
|
|
37
|
-
— 근거당 상한·명시적 `callersOmitted` 계수,
|
|
38
|
-
인덱스 없이 빌드된 Objective-C 핸들러의 usr 없는
|
|
31
|
+
**0.4.1.** 0.4.0에 구조·보안·성능 리뷰 반영(패치): `mixed-targets` 단어 경계 일치,
|
|
32
|
+
짝 없는 서러게이트 사전 거부(`toWellFormed()`), retentions 호출자 총예산(100만)과
|
|
33
|
+
할당 절감, 빈 플래그 값(exit 64) 거부, atomic-write(0o600) 경화를 적용했다.
|
|
34
|
+
0.4.0의 추가 사항 — GitHub code scanning용 check SARIF 2.1.0 렌더링(`check --format sarif`,
|
|
35
|
+
additive, 소스 줄 이동에 강한 논리 키 지문), 브리지가 없는 프로젝트와 아무것도
|
|
36
|
+
관찰하지 못한 실행을 구분하는 check summary 관찰량(`observedFacts`·`observedLimitations`),
|
|
37
|
+
다중 호출자 보존 근거(`evidence.callers` — 근거당 상한·명시적 `callersOmitted` 계수,
|
|
38
|
+
단일 호출자는 기존과 바이트 동일), 인덱스 없이 빌드된 Objective-C 핸들러의 usr 없는
|
|
39
|
+
`qualifiedName` 신원 — 과 0.3.0의 핵심 계약·명령은 그대로 유지된다. 외부 입력·
|
|
39
40
|
혼합 target·그래프 크기·Dart/Swift Phase 0 추출 경계는 fail-closed를 유지하고,
|
|
40
41
|
조인하지 못한 사실은 소비자 쪽에서 다시 세며 근거를 만들지 못한 보존 대상은 조용히
|
|
41
42
|
사라지는 대신 실패로 보고한다. 수신 측이 신고한 분석 공백은 불일치가 아니라 판정
|
package/README.md
CHANGED
|
@@ -30,20 +30,20 @@ calls it over channel `com.example/camera`".
|
|
|
30
30
|
|
|
31
31
|
## Status
|
|
32
32
|
|
|
33
|
-
**0.4.
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
and the Dart/Swift Phase 0 extraction boundary. Facts that could not be joined
|
|
45
|
-
re-counted on the consumer side, and retention subjects whose evidence cannot be built
|
|
46
|
-
refused loudly, so neither disappears silently. Coverage gaps a receiver reports about
|
|
33
|
+
**0.4.1.** Hardens 0.4.0 with structure, security, and performance review follow-ups:
|
|
34
|
+
word-boundary matching for `mixed-targets`, lone surrogate rejection via `toWellFormed()`,
|
|
35
|
+
a 1,000,000 caller budget for retention documents with pre-slice allocation savings, empty
|
|
36
|
+
flag validation (exit 64), and atomic-write permission hardening (`0o600`).
|
|
37
|
+
The 0.4.0 additions — SARIF 2.1.0 rendering of check results for GitHub code scanning
|
|
38
|
+
(`check --format sarif`, additive, with logic-key fingerprints that survive source line
|
|
39
|
+
moves), observation volume in the check summary (`observedFacts`, `observedLimitations`),
|
|
40
|
+
multi-caller retention evidence (`evidence.callers` with a per-retention cap and an explicit
|
|
41
|
+
`callersOmitted` count, byte-identical for single callers), and usr-less `qualifiedName`
|
|
42
|
+
identity for Objective-C handlers built without an index — and the core 0.3.0 contract and
|
|
43
|
+
commands remain intact. isthmus keeps fail-closed behavior for external input, mixed targets,
|
|
44
|
+
graph size, and the Dart/Swift Phase 0 extraction boundary. Facts that could not be joined
|
|
45
|
+
are re-counted on the consumer side, and retention subjects whose evidence cannot be built
|
|
46
|
+
are refused loudly, so neither disappears silently. Coverage gaps a receiver reports about
|
|
47
47
|
itself come back as undecidable, not as mismatches, and gap mitigation never leaks across
|
|
48
48
|
targets. Next: dogfooding it on a real Flutter app, and React Native support.
|
|
49
49
|
|
|
@@ -2,10 +2,13 @@
|
|
|
2
2
|
* 같은 디렉터리의 배타적 임시 파일에 쓰고 rename으로 원자 교체한다.
|
|
3
3
|
*
|
|
4
4
|
* 중단·디스크 가득 참 중에 기존 베이스라인이 잘린 채 남으면 다음 실행이
|
|
5
|
-
* 코드 2로 실패한다. rename은 같은 파일시스템 안에서
|
|
5
|
+
* 코드 2로 실패한다. rename은 같은 파일시스템 안에서 원자적이지만 fsync가
|
|
6
|
+
* 없어 전원 손실까지의 내구성은 보장하지 않는다.
|
|
6
7
|
*
|
|
7
8
|
* 임시 파일 이름은 pid와 무작위 바이트로 만들어 예측할 수 없고 `wx`로
|
|
8
9
|
* 배타 생성한다. 미리 놓인 심링크를 예측된 이름으로 통한 임의 파일
|
|
9
|
-
* 덮어쓰기로 이어지지 않는다.
|
|
10
|
+
* 덮어쓰기로 이어지지 않는다. 소유자만 읽을 수 있는 모드로 쓰고, 쓰기에
|
|
11
|
+
* 실패하면 임시 파일만 지운다. rename은 대상이 심링크여도 링크 자체를
|
|
12
|
+
* 교체하므로 링크 대상을 건드리지 않는다.
|
|
10
13
|
*/
|
|
11
14
|
export declare function writeTextAtomically(path: string, text: string, temporaryPathFor?: (path: string) => string): Promise<void>;
|
package/dist/cli/atomic-write.js
CHANGED
|
@@ -4,16 +4,23 @@ import { rename, rm, writeFile } from 'node:fs/promises';
|
|
|
4
4
|
* 같은 디렉터리의 배타적 임시 파일에 쓰고 rename으로 원자 교체한다.
|
|
5
5
|
*
|
|
6
6
|
* 중단·디스크 가득 참 중에 기존 베이스라인이 잘린 채 남으면 다음 실행이
|
|
7
|
-
* 코드 2로 실패한다. rename은 같은 파일시스템 안에서
|
|
7
|
+
* 코드 2로 실패한다. rename은 같은 파일시스템 안에서 원자적이지만 fsync가
|
|
8
|
+
* 없어 전원 손실까지의 내구성은 보장하지 않는다.
|
|
8
9
|
*
|
|
9
10
|
* 임시 파일 이름은 pid와 무작위 바이트로 만들어 예측할 수 없고 `wx`로
|
|
10
11
|
* 배타 생성한다. 미리 놓인 심링크를 예측된 이름으로 통한 임의 파일
|
|
11
|
-
* 덮어쓰기로 이어지지 않는다.
|
|
12
|
+
* 덮어쓰기로 이어지지 않는다. 소유자만 읽을 수 있는 모드로 쓰고, 쓰기에
|
|
13
|
+
* 실패하면 임시 파일만 지운다. rename은 대상이 심링크여도 링크 자체를
|
|
14
|
+
* 교체하므로 링크 대상을 건드리지 않는다.
|
|
12
15
|
*/
|
|
13
16
|
export async function writeTextAtomically(path, text, temporaryPathFor = unpredictableTemporaryPath) {
|
|
14
17
|
const temporaryPath = temporaryPathFor(path);
|
|
15
18
|
try {
|
|
16
|
-
await writeFile(temporaryPath, text, {
|
|
19
|
+
await writeFile(temporaryPath, text, {
|
|
20
|
+
encoding: 'utf8',
|
|
21
|
+
mode: 0o600,
|
|
22
|
+
flag: 'wx',
|
|
23
|
+
});
|
|
17
24
|
await rename(temporaryPath, path);
|
|
18
25
|
}
|
|
19
26
|
catch (error) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"atomic-write.js","sourceRoot":"","sources":["../../src/cli/atomic-write.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAC1C,OAAO,EAAE,MAAM,EAAE,EAAE,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAEzD
|
|
1
|
+
{"version":3,"file":"atomic-write.js","sourceRoot":"","sources":["../../src/cli/atomic-write.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAC1C,OAAO,EAAE,MAAM,EAAE,EAAE,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAEzD;;;;;;;;;;;;GAYG;AACH,MAAM,CAAC,KAAK,UAAU,mBAAmB,CACvC,IAAY,EACZ,IAAY,EACZ,mBAA6C,0BAA0B;IAEvE,MAAM,aAAa,GAAG,gBAAgB,CAAC,IAAI,CAAC,CAAC;IAC7C,IAAI,CAAC;QACH,MAAM,SAAS,CAAC,aAAa,EAAE,IAAI,EAAE;YACnC,QAAQ,EAAE,MAAM;YAChB,IAAI,EAAE,KAAK;YACX,IAAI,EAAE,IAAI;SACX,CAAC,CAAC;QACH,MAAM,MAAM,CAAC,aAAa,EAAE,IAAI,CAAC,CAAC;IACpC,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,gDAAgD;QAChD,6BAA6B;QAC7B,IAAK,KAA+B,CAAC,IAAI,KAAK,QAAQ,EAAE,CAAC;YACvD,MAAM,EAAE,CAAC,aAAa,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,SAAS,CAAC,CAAC;QAClE,CAAC;QACD,MAAM,KAAK,CAAC;IACd,CAAC;AACH,CAAC;AAED,wCAAwC;AACxC,SAAS,0BAA0B,CAAC,IAAY;IAC9C,OAAO,GAAG,IAAI,IAAI,OAAO,CAAC,GAAG,IAAI,WAAW,CAAC,EAAE,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,MAAM,CAAC;AACzE,CAAC","sourcesContent":["import { randomBytes } from 'node:crypto';\nimport { rename, rm, writeFile } from 'node:fs/promises';\n\n/**\n * 같은 디렉터리의 배타적 임시 파일에 쓰고 rename으로 원자 교체한다.\n *\n * 중단·디스크 가득 참 중에 기존 베이스라인이 잘린 채 남으면 다음 실행이\n * 코드 2로 실패한다. rename은 같은 파일시스템 안에서 원자적이지만 fsync가\n * 없어 전원 손실까지의 내구성은 보장하지 않는다.\n *\n * 임시 파일 이름은 pid와 무작위 바이트로 만들어 예측할 수 없고 `wx`로\n * 배타 생성한다. 미리 놓인 심링크를 예측된 이름으로 통한 임의 파일\n * 덮어쓰기로 이어지지 않는다. 소유자만 읽을 수 있는 모드로 쓰고, 쓰기에\n * 실패하면 임시 파일만 지운다. rename은 대상이 심링크여도 링크 자체를\n * 교체하므로 링크 대상을 건드리지 않는다.\n */\nexport async function writeTextAtomically(\n path: string,\n text: string,\n temporaryPathFor: (path: string) => string = unpredictableTemporaryPath,\n): Promise<void> {\n const temporaryPath = temporaryPathFor(path);\n try {\n await writeFile(temporaryPath, text, {\n encoding: 'utf8',\n mode: 0o600,\n flag: 'wx',\n });\n await rename(temporaryPath, path);\n } catch (error) {\n // EEXIST는 배타 생성이 거부된 것으로 임시 파일이 우리 것이 아니라는 뜻이다.\n // 남은 오류에서만 직접 만든 임시 파일을 지운다.\n if ((error as NodeJS.ErrnoException).code !== 'EEXIST') {\n await rm(temporaryPath, { force: true }).catch(() => undefined);\n }\n throw error;\n }\n}\n\n/** 같은 디렉터리 안의 예측 불가능한 임시 파일 이름을 만든다. */\nfunction unpredictableTemporaryPath(path: string): string {\n return `${path}.${process.pid}.${randomBytes(12).toString('hex')}.tmp`;\n}\n"]}
|
|
@@ -64,8 +64,10 @@ function parseCheckOptions(rest) {
|
|
|
64
64
|
}
|
|
65
65
|
if (argument === '--format' || argument === '--baseline' || argument === '--update-baseline') {
|
|
66
66
|
const value = rest[index + 1];
|
|
67
|
-
|
|
67
|
+
// 빈 값은 경로가 아니라 호출 오류다. 읽기 실패(코드 2)보다 사용법(64)이 맞다.
|
|
68
|
+
if (value === undefined || value.length === 0 || value.startsWith('-')) {
|
|
68
69
|
return undefined;
|
|
70
|
+
}
|
|
69
71
|
if (argument === '--format') {
|
|
70
72
|
if (format !== undefined || (value !== 'json' && value !== 'sarif')) {
|
|
71
73
|
return undefined;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"check-command.js","sourceRoot":"","sources":["../../src/cli/check-command.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n BridgeFactsValidationError,\n parseBridgeFactsDocument,\n type BridgeFactsDocument,\n} from '../exchange/parse.ts';\nimport {\n BridgeJoinValidationError,\n isBridgeJoinDeferred,\n joinBridgeDocuments,\n MAX_DOCUMENTS_PER_JOIN,\n} from '../join/join.ts';\nimport {\n applyBaseline,\n BridgeBaselineValidationError,\n createBaselineDocument,\n encodeBaselineDocument,\n MAX_BASELINE_ENTRIES,\n parseBaselineDocument,\n type BaselineDocument,\n} from '../report/baseline.ts';\nimport type { CheckIssue } from '../report/check-report.ts';\nimport { createCheckReport, encodeCheckReport } from '../report/check-report.ts';\nimport {\n createSarifLog,\n encodeSarifLog,\n} from '../report/sarif.ts';\n\n/** 파일 경로를 받아 UTF-8 텍스트를 읽는 주입 경계다. */\nexport type ReadTextFile = (path: string) => Promise<string>;\n\n/** 파일 경로에 UTF-8 텍스트를 쓰는 주입 경계다. */\nexport type WriteTextFile = (path: string, text: string) => Promise<void>;\n\n/** 생성 시각을 테스트 가능하게 주입하는 시계다. */\nexport type Clock = () => Date;\n\n/** check가 내는 보고서 형식이다. SARIF는 isthmus 소유의 additive 출력이다. */\nexport type CheckOutputFormat = 'json' | 'sarif';\n\n/** 한 입력 파일에서 허용하는 최대 UTF-16 문자열 길이다. */\nexport const MAX_INPUT_TEXT_LENGTH = 16 * 1024 * 1024;\n\n/** 한 명령에서 허용하는 전체 UTF-16 입력 문자열 길이다. */\nexport const MAX_TOTAL_INPUT_TEXT_LENGTH = 64 * 1024 * 1024;\n\n/** CLI가 프로세스 경계에 쓸 출력과 종료 코드다. */\nexport interface CommandResult {\n readonly standardOutput: string;\n readonly standardError: string;\n readonly exitCode: 0 | 1 | 2 | 64;\n}\n\n/** check 인자를 실행해 프로세스에 독립적인 결과를 반환한다. */\nexport async function runCheckCommand(\n arguments_: readonly string[],\n readTextFile: ReadTextFile,\n writeTextFile?: WriteTextFile,\n now: Clock = () => new Date(),\n producerVersion?: string,\n): Promise<CommandResult> {\n if (arguments_[0] !== 'check') return usageError();\n const options = parseCheckOptions(arguments_.slice(1));\n if (options === undefined) return usageError();\n const { strict, format, baselinePath, updateBaselinePath, inputPaths } = options;\n if (inputPaths.length < 2 || inputPaths.length > MAX_DOCUMENTS_PER_JOIN) {\n return usageError();\n }\n if (updateBaselinePath !== undefined && writeTextFile === undefined) {\n return internalError();\n }\n try {\n const documents = await readBridgeDocuments(inputPaths, readTextFile);\n const joined = joinBridgeDocuments(documents);\n if (isBridgeJoinDeferred(joined)) return bridgeJoinDeferredError();\n let report = createCheckReport(joined);\n if (baselinePath !== undefined) {\n const baseline = await readBaselineDocument(baselinePath, readTextFile);\n report = applyBaseline(report, baseline.entries);\n }\n const standardOutput = format === 'sarif'\n ? encodeSarifLog(createSarifLog(report, producerVersion))\n : encodeCheckReport(report);\n if (updateBaselinePath !== undefined && writeTextFile !== undefined) {\n await writeBaselineDocument(\n updateBaselinePath,\n report.issues,\n now(),\n writeTextFile,\n );\n }\n return {\n standardOutput,\n standardError: '',\n exitCode: strict && report.summary.errors > 0 ? 1 : 0,\n };\n } catch (error) {\n return inputFailureResult(error) ?? internalError();\n }\n}\n\n/** check 플래그와 값·입력 경로를 분리한다. 잘못되면 undefined다. */\nfunction parseCheckOptions(\n rest: readonly string[],\n): {\n strict: boolean;\n format: CheckOutputFormat;\n baselinePath: string | undefined;\n updateBaselinePath: string | undefined;\n inputPaths: string[];\n} | undefined {\n let strict = false;\n let format: CheckOutputFormat | undefined;\n let baselinePath: string | undefined;\n let updateBaselinePath: string | undefined;\n const inputPaths: string[] = [];\n for (let index = 0; index < rest.length; index++) {\n const argument = rest[index];\n if (argument === undefined) return undefined;\n if (argument === '--strict') {\n strict = true;\n continue;\n }\n if (argument === '--format' || argument === '--baseline' || argument === '--update-baseline') {\n const value = rest[index + 1];\n if (value === undefined || value.startsWith('-')) return undefined;\n if (argument === '--format') {\n if (format !== undefined || (value !== 'json' && value !== 'sarif')) {\n return undefined;\n }\n format = value;\n } else if (argument === '--baseline') {\n if (baselinePath !== undefined) return undefined;\n baselinePath = value;\n } else {\n if (updateBaselinePath !== undefined) return undefined;\n updateBaselinePath = value;\n }\n index++;\n continue;\n }\n if (argument.startsWith('-')) return undefined;\n inputPaths.push(argument);\n }\n if (baselinePath !== undefined && updateBaselinePath !== undefined) {\n return undefined;\n }\n return {\n strict,\n format: format ?? 'json',\n baselinePath,\n updateBaselinePath,\n inputPaths,\n };\n}\n\n/** 베이스라인 파일을 읽고 크기 상한 안에서 검증된 문서로 파싱한다. */\nasync function readBaselineDocument(\n path: string,\n readTextFile: ReadTextFile,\n): Promise<BaselineDocument> {\n let text: string;\n try {\n text = await readTextFile(path);\n } catch {\n throw new BridgeBaselineReadError();\n }\n if (text.length > MAX_INPUT_TEXT_LENGTH) {\n throw new BridgeBaselineLimitError();\n }\n // JSON 구문 오류와 문서 검증 실패를 같은 try로 감싸면 검증기의 예외가\n // 구문 오류로 오분류된다. 파싱과 검증을 나눠 분류 경계를 지킨다.\n let parsed: unknown;\n try {\n parsed = JSON.parse(text);\n } catch (error) {\n if (isJsonParseFailure(error)) throw new BridgeBaselineJsonError();\n throw error;\n }\n return parseBaselineDocument(parsed);\n}\n\n/**\n * 사용자 입력 JSON 파싱 실패인지 확인한다.\n *\n * 깊은 중첩은 SyntaxError가 아니라 RangeError(스택 초과)로 실패한다.\n * 둘 다 입력 탓이라 내부 오류 메시지로 오분류하지 않는다.\n */\nfunction isJsonParseFailure(error: unknown): boolean {\n return error instanceof SyntaxError || error instanceof RangeError;\n}\n\n/** 현재 이슈 전체를 결정적 베이스라인 문서로 써서 해결된 항목을 정리한다. */\nasync function writeBaselineDocument(\n path: string,\n issues: readonly CheckIssue[],\n generatedAt: Date,\n writeTextFile: WriteTextFile,\n): Promise<void> {\n let document: BaselineDocument;\n try {\n document = createBaselineDocument(issues, generatedAt.toISOString());\n } catch (error) {\n // 만들 수 없는 문서는 쓰지 않는다. 상한 초과 산출물은 다음 실행이\n // 소비할 수 없어 부분 성공보다 실패가 안전하다.\n if (error instanceof BridgeBaselineValidationError) {\n throw new BridgeBaselineWriteLimitError();\n }\n throw error;\n }\n // 인코딩 결함은 쓰기 실패가 아니라 내부 오류로 분류되어야 한다.\n const encoded = encodeBaselineDocument(document);\n try {\n await writeTextFile(path, encoded);\n } catch {\n throw new BridgeBaselineWriteError();\n }\n}\n\n/** 베이스라인 파일을 읽지 못한 경우를 구분한다. */\nclass BridgeBaselineReadError extends Error {\n constructor() {\n super('BridgeBaselineReadError');\n this.name = 'BridgeBaselineReadError';\n }\n}\n\n/** 베이스라인 파일이 JSON이 아닌 경우를 구분한다. */\nclass BridgeBaselineJsonError extends Error {\n constructor() {\n super('BridgeBaselineJsonError');\n this.name = 'BridgeBaselineJsonError';\n }\n}\n\n/** 베이스라인 파일이 크기 상한을 넘은 경우를 구분한다. */\nclass BridgeBaselineLimitError extends Error {\n constructor() {\n super('BridgeBaselineLimitError');\n this.name = 'BridgeBaselineLimitError';\n }\n}\n\n/** 베이스라인 파일을 쓰지 못한 경우를 구분한다. */\nclass BridgeBaselineWriteError extends Error {\n constructor() {\n super('BridgeBaselineWriteError');\n this.name = 'BridgeBaselineWriteError';\n }\n}\n\n/** 쓸 베이스라인이 항목 상한을 넘는 경우를 구분한다. */\nclass BridgeBaselineWriteLimitError extends Error {\n constructor() {\n super('BridgeBaselineWriteLimitError');\n this.name = 'BridgeBaselineWriteLimitError';\n }\n}\n\n/** 입력을 순서대로 읽어 파일 수·메모리 상한 안에서 교환 문서로 파싱한다. */\nexport async function readBridgeDocuments(\n inputPaths: readonly string[],\n readTextFile: ReadTextFile,\n): Promise<BridgeFactsDocument[]> {\n const documents: BridgeFactsDocument[] = [];\n let totalTextLength = 0;\n for (const [index, path] of inputPaths.entries()) {\n const inputPosition = index + 1;\n let text: string;\n try {\n text = await readTextFile(path);\n } catch {\n throw new BridgeInputReadError(inputPosition);\n }\n totalTextLength += text.length;\n if (\n text.length > MAX_INPUT_TEXT_LENGTH ||\n totalTextLength > MAX_TOTAL_INPUT_TEXT_LENGTH\n ) {\n throw new BridgeInputLimitError(inputPosition);\n }\n // JSON 구문 오류와 문서 검증 실패를 같은 try로 감싸면 검증기의 예외가\n // 구문 오류로 오분류된다. 파싱과 검증을 나눠 분류 경계를 지킨다.\n let parsed: unknown;\n try {\n parsed = JSON.parse(text);\n } catch (error) {\n if (isJsonParseFailure(error)) {\n throw new BridgeInputJsonError(inputPosition);\n }\n throw error;\n }\n try {\n documents.push(parseBridgeFactsDocument(parsed));\n } catch (error) {\n if (error instanceof BridgeFactsValidationError) {\n throw new BridgeInputContractError(inputPosition, error.message);\n }\n throw error;\n }\n }\n return documents;\n}\n\n/** 실패한 입력의 1부터 시작하는 순서를 보존하는 입력 오류다. */\nclass BridgeInputError extends Error {\n readonly inputPosition: number;\n\n constructor(name: string, inputPosition: number) {\n super(`${name} at input ${inputPosition}`);\n this.name = name;\n this.inputPosition = inputPosition;\n }\n}\n\n/** 입력 파일을 읽지 못한 경우를 구분한다. */\nclass BridgeInputReadError extends BridgeInputError {\n constructor(inputPosition: number) {\n super('BridgeInputReadError', inputPosition);\n }\n}\n\n/** 입력 텍스트가 JSON이 아닌 경우를 구분한다. */\nclass BridgeInputJsonError extends BridgeInputError {\n constructor(inputPosition: number) {\n super('BridgeInputJsonError', inputPosition);\n }\n}\n\n/** 입력 문서가 교환 계약을 어긴 경우와 그 이유를 구분한다. */\nclass BridgeInputContractError extends BridgeInputError {\n readonly reason: string;\n\n constructor(inputPosition: number, reason: string) {\n super('BridgeInputContractError', inputPosition);\n this.reason = reason;\n }\n}\n\n/** 입력 텍스트의 크기만 계약을 넘은 경우를 구분한다. */\nclass BridgeInputLimitError extends BridgeInputError {\n constructor(inputPosition: number) {\n super('BridgeInputLimitError', inputPosition);\n }\n}\n\n/** 알려진 입력·조인 실패를 원인별 해결 방향을 담은 코드 2 결과로 바꾼다. */\nexport function inputFailureResult(error: unknown): CommandResult | undefined {\n if (error instanceof BridgeInputReadError) {\n return inputFailure(\n `Unable to read bridge facts input ${error.inputPosition}; `\n + 'check that the file exists and is readable.\\n',\n );\n }\n if (error instanceof BridgeInputJsonError) {\n return inputFailure(\n `Bridge facts input ${error.inputPosition} is not valid JSON; `\n + 'regenerate it with a bridge-facts producer.\\n',\n );\n }\n if (error instanceof BridgeInputContractError) {\n return inputFailure(\n `Bridge facts input ${error.inputPosition} violates the bridge-facts `\n + `contract: ${error.reason}\\n`,\n );\n }\n if (error instanceof BridgeInputLimitError) {\n return inputFailure(\n `Bridge facts input ${error.inputPosition} exceeds the input size limits; `\n + 'split the extraction into smaller documents.\\n',\n );\n }\n if (error instanceof BridgeBaselineReadError) {\n return inputFailure(\n 'Unable to read the baseline file; check that it exists and is readable.\\n',\n );\n }\n if (error instanceof BridgeBaselineJsonError) {\n return inputFailure(\n 'The baseline file is not valid JSON; regenerate it with '\n + 'check --update-baseline.\\n',\n );\n }\n if (error instanceof BridgeBaselineLimitError) {\n return inputFailure(\n 'The baseline file exceeds the input size limits; regenerate it with '\n + 'check --update-baseline.\\n',\n );\n }\n if (error instanceof BridgeBaselineWriteError) {\n return inputFailure(\n 'Unable to write the baseline file; check that the path is writable.\\n',\n );\n }\n if (error instanceof BridgeBaselineWriteLimitError) {\n return inputFailure(\n `Cannot write a baseline with more than ${MAX_BASELINE_ENTRIES} entries; `\n + 'narrow the join inputs.\\n',\n );\n }\n if (error instanceof BridgeBaselineValidationError) {\n return inputFailure(\n `The baseline file is not a valid isthmus-baseline document: `\n + `${error.message}\\n`,\n );\n }\n if (error instanceof BridgeJoinValidationError) {\n return inputFailure(`${error.message}\\n`);\n }\n return undefined;\n}\n\n/** 원인 메시지만 stdout 없이 코드 2로 내보낸다. */\nfunction inputFailure(standardError: string): CommandResult {\n return { standardOutput: '', standardError, exitCode: 2 };\n}\n\n/** 전체 조인 보류를 깨끗한 결과와 구분하는 코드 2 결과로 바꾼다. */\nexport function bridgeJoinDeferredError(): CommandResult {\n return {\n standardOutput: '',\n standardError:\n 'Bridge facts could not be joined; split mixed bridge targets and retry.\\n',\n exitCode: 2,\n };\n}\n\n/** 내부 결함을 입력 탓으로 돌리지 않는 경로 없는 코드 2 결과다. */\nexport function internalError(): CommandResult {\n return {\n standardOutput: '',\n standardError: 'Internal isthmus error; retry with a current version.\\n',\n exitCode: 2,\n };\n}\n\n/** 잘못된 CLI 호출을 경로 없는 사용법과 코드 64로 바꾼다. */\nfunction usageError(): CommandResult {\n return {\n standardOutput: '',\n standardError: `${checkUsage}\\n`,\n exitCode: 64,\n };\n}\n\n/** check 명령의 한 줄 사용법이다. */\nexport const checkUsage =\n 'Usage: isthmus check <bridge-facts.json> <bridge-facts.json> '\n + '[more...] [--strict] [--format json|sarif] '\n + '[--baseline <isthmus-baseline.json>] '\n + '[--update-baseline <isthmus-baseline.json>]';\n"]}
|
|
1
|
+
{"version":3,"file":"check-command.js","sourceRoot":"","sources":["../../src/cli/check-command.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n BridgeFactsValidationError,\n parseBridgeFactsDocument,\n type BridgeFactsDocument,\n} from '../exchange/parse.ts';\nimport {\n BridgeJoinValidationError,\n isBridgeJoinDeferred,\n joinBridgeDocuments,\n MAX_DOCUMENTS_PER_JOIN,\n} from '../join/join.ts';\nimport {\n applyBaseline,\n BridgeBaselineValidationError,\n createBaselineDocument,\n encodeBaselineDocument,\n MAX_BASELINE_ENTRIES,\n parseBaselineDocument,\n type BaselineDocument,\n} from '../report/baseline.ts';\nimport type { CheckIssue } from '../report/check-report.ts';\nimport { createCheckReport, encodeCheckReport } from '../report/check-report.ts';\nimport {\n createSarifLog,\n encodeSarifLog,\n} from '../report/sarif.ts';\n\n/** 파일 경로를 받아 UTF-8 텍스트를 읽는 주입 경계다. */\nexport type ReadTextFile = (path: string) => Promise<string>;\n\n/** 파일 경로에 UTF-8 텍스트를 쓰는 주입 경계다. */\nexport type WriteTextFile = (path: string, text: string) => Promise<void>;\n\n/** 생성 시각을 테스트 가능하게 주입하는 시계다. */\nexport type Clock = () => Date;\n\n/** check가 내는 보고서 형식이다. SARIF는 isthmus 소유의 additive 출력이다. */\nexport type CheckOutputFormat = 'json' | 'sarif';\n\n/** 한 입력 파일에서 허용하는 최대 UTF-16 문자열 길이다. */\nexport const MAX_INPUT_TEXT_LENGTH = 16 * 1024 * 1024;\n\n/** 한 명령에서 허용하는 전체 UTF-16 입력 문자열 길이다. */\nexport const MAX_TOTAL_INPUT_TEXT_LENGTH = 64 * 1024 * 1024;\n\n/** CLI가 프로세스 경계에 쓸 출력과 종료 코드다. */\nexport interface CommandResult {\n readonly standardOutput: string;\n readonly standardError: string;\n readonly exitCode: 0 | 1 | 2 | 64;\n}\n\n/** check 인자를 실행해 프로세스에 독립적인 결과를 반환한다. */\nexport async function runCheckCommand(\n arguments_: readonly string[],\n readTextFile: ReadTextFile,\n writeTextFile?: WriteTextFile,\n now: Clock = () => new Date(),\n producerVersion?: string,\n): Promise<CommandResult> {\n if (arguments_[0] !== 'check') return usageError();\n const options = parseCheckOptions(arguments_.slice(1));\n if (options === undefined) return usageError();\n const { strict, format, baselinePath, updateBaselinePath, inputPaths } = options;\n if (inputPaths.length < 2 || inputPaths.length > MAX_DOCUMENTS_PER_JOIN) {\n return usageError();\n }\n if (updateBaselinePath !== undefined && writeTextFile === undefined) {\n return internalError();\n }\n try {\n const documents = await readBridgeDocuments(inputPaths, readTextFile);\n const joined = joinBridgeDocuments(documents);\n if (isBridgeJoinDeferred(joined)) return bridgeJoinDeferredError();\n let report = createCheckReport(joined);\n if (baselinePath !== undefined) {\n const baseline = await readBaselineDocument(baselinePath, readTextFile);\n report = applyBaseline(report, baseline.entries);\n }\n const standardOutput = format === 'sarif'\n ? encodeSarifLog(createSarifLog(report, producerVersion))\n : encodeCheckReport(report);\n if (updateBaselinePath !== undefined && writeTextFile !== undefined) {\n await writeBaselineDocument(\n updateBaselinePath,\n report.issues,\n now(),\n writeTextFile,\n );\n }\n return {\n standardOutput,\n standardError: '',\n exitCode: strict && report.summary.errors > 0 ? 1 : 0,\n };\n } catch (error) {\n return inputFailureResult(error) ?? internalError();\n }\n}\n\n/** check 플래그와 값·입력 경로를 분리한다. 잘못되면 undefined다. */\nfunction parseCheckOptions(\n rest: readonly string[],\n): {\n strict: boolean;\n format: CheckOutputFormat;\n baselinePath: string | undefined;\n updateBaselinePath: string | undefined;\n inputPaths: string[];\n} | undefined {\n let strict = false;\n let format: CheckOutputFormat | undefined;\n let baselinePath: string | undefined;\n let updateBaselinePath: string | undefined;\n const inputPaths: string[] = [];\n for (let index = 0; index < rest.length; index++) {\n const argument = rest[index];\n if (argument === undefined) return undefined;\n if (argument === '--strict') {\n strict = true;\n continue;\n }\n if (argument === '--format' || argument === '--baseline' || argument === '--update-baseline') {\n const value = rest[index + 1];\n // 빈 값은 경로가 아니라 호출 오류다. 읽기 실패(코드 2)보다 사용법(64)이 맞다.\n if (value === undefined || value.length === 0 || value.startsWith('-')) {\n return undefined;\n }\n if (argument === '--format') {\n if (format !== undefined || (value !== 'json' && value !== 'sarif')) {\n return undefined;\n }\n format = value;\n } else if (argument === '--baseline') {\n if (baselinePath !== undefined) return undefined;\n baselinePath = value;\n } else {\n if (updateBaselinePath !== undefined) return undefined;\n updateBaselinePath = value;\n }\n index++;\n continue;\n }\n if (argument.startsWith('-')) return undefined;\n inputPaths.push(argument);\n }\n if (baselinePath !== undefined && updateBaselinePath !== undefined) {\n return undefined;\n }\n return {\n strict,\n format: format ?? 'json',\n baselinePath,\n updateBaselinePath,\n inputPaths,\n };\n}\n\n/** 베이스라인 파일을 읽고 크기 상한 안에서 검증된 문서로 파싱한다. */\nasync function readBaselineDocument(\n path: string,\n readTextFile: ReadTextFile,\n): Promise<BaselineDocument> {\n let text: string;\n try {\n text = await readTextFile(path);\n } catch {\n throw new BridgeBaselineReadError();\n }\n if (text.length > MAX_INPUT_TEXT_LENGTH) {\n throw new BridgeBaselineLimitError();\n }\n // JSON 구문 오류와 문서 검증 실패를 같은 try로 감싸면 검증기의 예외가\n // 구문 오류로 오분류된다. 파싱과 검증을 나눠 분류 경계를 지킨다.\n let parsed: unknown;\n try {\n parsed = JSON.parse(text);\n } catch (error) {\n if (isJsonParseFailure(error)) throw new BridgeBaselineJsonError();\n throw error;\n }\n return parseBaselineDocument(parsed);\n}\n\n/**\n * 사용자 입력 JSON 파싱 실패인지 확인한다.\n *\n * 깊은 중첩은 SyntaxError가 아니라 RangeError(스택 초과)로 실패한다.\n * 둘 다 입력 탓이라 내부 오류 메시지로 오분류하지 않는다.\n */\nfunction isJsonParseFailure(error: unknown): boolean {\n return error instanceof SyntaxError || error instanceof RangeError;\n}\n\n/** 현재 이슈 전체를 결정적 베이스라인 문서로 써서 해결된 항목을 정리한다. */\nasync function writeBaselineDocument(\n path: string,\n issues: readonly CheckIssue[],\n generatedAt: Date,\n writeTextFile: WriteTextFile,\n): Promise<void> {\n let document: BaselineDocument;\n try {\n document = createBaselineDocument(issues, generatedAt.toISOString());\n } catch (error) {\n // 만들 수 없는 문서는 쓰지 않는다. 상한 초과 산출물은 다음 실행이\n // 소비할 수 없어 부분 성공보다 실패가 안전하다.\n if (error instanceof BridgeBaselineValidationError) {\n throw new BridgeBaselineWriteLimitError();\n }\n throw error;\n }\n // 인코딩 결함은 쓰기 실패가 아니라 내부 오류로 분류되어야 한다.\n const encoded = encodeBaselineDocument(document);\n try {\n await writeTextFile(path, encoded);\n } catch {\n throw new BridgeBaselineWriteError();\n }\n}\n\n/** 베이스라인 파일을 읽지 못한 경우를 구분한다. */\nclass BridgeBaselineReadError extends Error {\n constructor() {\n super('BridgeBaselineReadError');\n this.name = 'BridgeBaselineReadError';\n }\n}\n\n/** 베이스라인 파일이 JSON이 아닌 경우를 구분한다. */\nclass BridgeBaselineJsonError extends Error {\n constructor() {\n super('BridgeBaselineJsonError');\n this.name = 'BridgeBaselineJsonError';\n }\n}\n\n/** 베이스라인 파일이 크기 상한을 넘은 경우를 구분한다. */\nclass BridgeBaselineLimitError extends Error {\n constructor() {\n super('BridgeBaselineLimitError');\n this.name = 'BridgeBaselineLimitError';\n }\n}\n\n/** 베이스라인 파일을 쓰지 못한 경우를 구분한다. */\nclass BridgeBaselineWriteError extends Error {\n constructor() {\n super('BridgeBaselineWriteError');\n this.name = 'BridgeBaselineWriteError';\n }\n}\n\n/** 쓸 베이스라인이 항목 상한을 넘는 경우를 구분한다. */\nclass BridgeBaselineWriteLimitError extends Error {\n constructor() {\n super('BridgeBaselineWriteLimitError');\n this.name = 'BridgeBaselineWriteLimitError';\n }\n}\n\n/** 입력을 순서대로 읽어 파일 수·메모리 상한 안에서 교환 문서로 파싱한다. */\nexport async function readBridgeDocuments(\n inputPaths: readonly string[],\n readTextFile: ReadTextFile,\n): Promise<BridgeFactsDocument[]> {\n const documents: BridgeFactsDocument[] = [];\n let totalTextLength = 0;\n for (const [index, path] of inputPaths.entries()) {\n const inputPosition = index + 1;\n let text: string;\n try {\n text = await readTextFile(path);\n } catch {\n throw new BridgeInputReadError(inputPosition);\n }\n totalTextLength += text.length;\n if (\n text.length > MAX_INPUT_TEXT_LENGTH ||\n totalTextLength > MAX_TOTAL_INPUT_TEXT_LENGTH\n ) {\n throw new BridgeInputLimitError(inputPosition);\n }\n // JSON 구문 오류와 문서 검증 실패를 같은 try로 감싸면 검증기의 예외가\n // 구문 오류로 오분류된다. 파싱과 검증을 나눠 분류 경계를 지킨다.\n let parsed: unknown;\n try {\n parsed = JSON.parse(text);\n } catch (error) {\n if (isJsonParseFailure(error)) {\n throw new BridgeInputJsonError(inputPosition);\n }\n throw error;\n }\n try {\n documents.push(parseBridgeFactsDocument(parsed));\n } catch (error) {\n if (error instanceof BridgeFactsValidationError) {\n throw new BridgeInputContractError(inputPosition, error.message);\n }\n throw error;\n }\n }\n return documents;\n}\n\n/** 실패한 입력의 1부터 시작하는 순서를 보존하는 입력 오류다. */\nclass BridgeInputError extends Error {\n readonly inputPosition: number;\n\n constructor(name: string, inputPosition: number) {\n super(`${name} at input ${inputPosition}`);\n this.name = name;\n this.inputPosition = inputPosition;\n }\n}\n\n/** 입력 파일을 읽지 못한 경우를 구분한다. */\nclass BridgeInputReadError extends BridgeInputError {\n constructor(inputPosition: number) {\n super('BridgeInputReadError', inputPosition);\n }\n}\n\n/** 입력 텍스트가 JSON이 아닌 경우를 구분한다. */\nclass BridgeInputJsonError extends BridgeInputError {\n constructor(inputPosition: number) {\n super('BridgeInputJsonError', inputPosition);\n }\n}\n\n/** 입력 문서가 교환 계약을 어긴 경우와 그 이유를 구분한다. */\nclass BridgeInputContractError extends BridgeInputError {\n readonly reason: string;\n\n constructor(inputPosition: number, reason: string) {\n super('BridgeInputContractError', inputPosition);\n this.reason = reason;\n }\n}\n\n/** 입력 텍스트의 크기만 계약을 넘은 경우를 구분한다. */\nclass BridgeInputLimitError extends BridgeInputError {\n constructor(inputPosition: number) {\n super('BridgeInputLimitError', inputPosition);\n }\n}\n\n/** 알려진 입력·조인 실패를 원인별 해결 방향을 담은 코드 2 결과로 바꾼다. */\nexport function inputFailureResult(error: unknown): CommandResult | undefined {\n if (error instanceof BridgeInputReadError) {\n return inputFailure(\n `Unable to read bridge facts input ${error.inputPosition}; `\n + 'check that the file exists and is readable.\\n',\n );\n }\n if (error instanceof BridgeInputJsonError) {\n return inputFailure(\n `Bridge facts input ${error.inputPosition} is not valid JSON; `\n + 'regenerate it with a bridge-facts producer.\\n',\n );\n }\n if (error instanceof BridgeInputContractError) {\n return inputFailure(\n `Bridge facts input ${error.inputPosition} violates the bridge-facts `\n + `contract: ${error.reason}\\n`,\n );\n }\n if (error instanceof BridgeInputLimitError) {\n return inputFailure(\n `Bridge facts input ${error.inputPosition} exceeds the input size limits; `\n + 'split the extraction into smaller documents.\\n',\n );\n }\n if (error instanceof BridgeBaselineReadError) {\n return inputFailure(\n 'Unable to read the baseline file; check that it exists and is readable.\\n',\n );\n }\n if (error instanceof BridgeBaselineJsonError) {\n return inputFailure(\n 'The baseline file is not valid JSON; regenerate it with '\n + 'check --update-baseline.\\n',\n );\n }\n if (error instanceof BridgeBaselineLimitError) {\n return inputFailure(\n 'The baseline file exceeds the input size limits; regenerate it with '\n + 'check --update-baseline.\\n',\n );\n }\n if (error instanceof BridgeBaselineWriteError) {\n return inputFailure(\n 'Unable to write the baseline file; check that the path is writable.\\n',\n );\n }\n if (error instanceof BridgeBaselineWriteLimitError) {\n return inputFailure(\n `Cannot write a baseline with more than ${MAX_BASELINE_ENTRIES} entries; `\n + 'narrow the join inputs.\\n',\n );\n }\n if (error instanceof BridgeBaselineValidationError) {\n return inputFailure(\n `The baseline file is not a valid isthmus-baseline document: `\n + `${error.message}\\n`,\n );\n }\n if (error instanceof BridgeJoinValidationError) {\n return inputFailure(`${error.message}\\n`);\n }\n return undefined;\n}\n\n/** 원인 메시지만 stdout 없이 코드 2로 내보낸다. */\nfunction inputFailure(standardError: string): CommandResult {\n return { standardOutput: '', standardError, exitCode: 2 };\n}\n\n/** 전체 조인 보류를 깨끗한 결과와 구분하는 코드 2 결과로 바꾼다. */\nexport function bridgeJoinDeferredError(): CommandResult {\n return {\n standardOutput: '',\n standardError:\n 'Bridge facts could not be joined; split mixed bridge targets and retry.\\n',\n exitCode: 2,\n };\n}\n\n/** 내부 결함을 입력 탓으로 돌리지 않는 경로 없는 코드 2 결과다. */\nexport function internalError(): CommandResult {\n return {\n standardOutput: '',\n standardError: 'Internal isthmus error; retry with a current version.\\n',\n exitCode: 2,\n };\n}\n\n/** 잘못된 CLI 호출을 경로 없는 사용법과 코드 64로 바꾼다. */\nfunction usageError(): CommandResult {\n return {\n standardOutput: '',\n standardError: `${checkUsage}\\n`,\n exitCode: 64,\n };\n}\n\n/** check 명령의 한 줄 사용법이다. */\nexport const checkUsage =\n 'Usage: isthmus check <bridge-facts.json> <bridge-facts.json> '\n + '[more...] [--strict] [--format json|sarif] '\n + '[--baseline <isthmus-baseline.json>] '\n + '[--update-baseline <isthmus-baseline.json>]';\n"]}
|
package/dist/exchange/parse.js
CHANGED
|
@@ -133,7 +133,7 @@ function validateFact(value, index, platform) {
|
|
|
133
133
|
if (!bridgeFactKinds.has(value.kind))
|
|
134
134
|
fail(`Invalid fact kind at index ${index}.`);
|
|
135
135
|
if (!supportedBridgeFactKinds.has(value.kind)) {
|
|
136
|
-
fail(`Fact kind is reserved but not supported
|
|
136
|
+
fail(`Fact kind is reserved but not supported by this isthmus version at index ${index}.`);
|
|
137
137
|
}
|
|
138
138
|
if (!isFactKindForPlatform(platform, value.kind)) {
|
|
139
139
|
fail(`Fact kind is not valid for platform at index ${index}.`);
|
|
@@ -179,7 +179,15 @@ export function isBridgeTarget(value) {
|
|
|
179
179
|
}
|
|
180
180
|
/** 조인 키를 깨뜨리는 제어 문자가 없는 비어 있지 않은 문자열인지 확인한다. */
|
|
181
181
|
export function isSafeNonEmptyString(value) {
|
|
182
|
-
return isNonEmptyString(value) && !controlCharacterPattern.test(value)
|
|
182
|
+
return isNonEmptyString(value) && !controlCharacterPattern.test(value) &&
|
|
183
|
+
!hasUnpairedSurrogate(value);
|
|
184
|
+
}
|
|
185
|
+
/** 유효한 UTF-16 문자열인지, 즉 짝 없는 서러게이트가 없는지 확인한다. */
|
|
186
|
+
function hasUnpairedSurrogate(value) {
|
|
187
|
+
// 아스트랄 문자(이모지 등)는 유효한 서러게이트 쌍이므로 그대로 통과한다.
|
|
188
|
+
// 짝 없는 서러게이트는 어떤 인코딩의 파일에도 존재할 수 없어 JSON 이스케이프로만
|
|
189
|
+
// 들어오며, URI 인코딩이 실패하는 등 소비 경로마다 깨진다.
|
|
190
|
+
return value.toWellFormed() !== value;
|
|
183
191
|
}
|
|
184
192
|
/** 사실 위치가 상대 경로와 1부터 시작하는 줄·열을 갖는지 검증한다. */
|
|
185
193
|
function validateLocation(value, index) {
|
|
@@ -196,8 +204,9 @@ function isProjectRelativePath(value) {
|
|
|
196
204
|
return false;
|
|
197
205
|
if (/^(?:[/\\]|[A-Za-z]:)/u.test(value))
|
|
198
206
|
return false;
|
|
199
|
-
if (controlCharacterPattern.test(value))
|
|
207
|
+
if (controlCharacterPattern.test(value) || hasUnpairedSurrogate(value)) {
|
|
200
208
|
return false;
|
|
209
|
+
}
|
|
201
210
|
return !value.split(/[/\\]/u).includes('..');
|
|
202
211
|
}
|
|
203
212
|
/** 선택 symbol의 이름과 USR이 비어 있지 않은지 검증한다. */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"parse.js","sourceRoot":"","sources":["../../src/exchange/parse.ts"],"names":[],"mappings":"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","sourcesContent":["/** bridge-facts 생산 플랫폼이다. */\nexport type BridgePlatform = 'dart' | 'swift' | 'kotlin' | 'js';\n\n/** 언어 경계를 잇는 메커니즘이다. */\nexport type BridgeTarget = 'flutter' | 'react-native' | 'capacitor';\n\n/** Swift 플랫폼 문서에 실린 Objective-C 구현을 Swift 보존 대상과 구분한다. */\nexport type BridgeSourceLanguage = 'objective-c';\n\n/** 특정 한계 전체의 영향을 포함하는 채널 집합. 일부 발견 목록이 아니다. */\nexport interface BridgeLimitationScope {\n readonly limitationIndex: number;\n readonly channels: readonly string[];\n}\n\n/** 확장 메타데이터가 입력 자원 상한을 우회하지 못하게 한다. */\nexport const MAX_LIMITATION_SCOPES = 1_000;\nexport const MAX_SCOPED_CHANNELS = 10_000;\n\n/** 교환 형식의 사실 종류다. */\nexport type BridgeFactKind =\n | 'channel-create'\n | 'channel-register'\n | 'method-invoke'\n | 'method-handle'\n | 'module-export'\n | 'module-import'\n | 'component-export'\n | 'component-require';\n\n/** 한 생산 문서가 담을 수 있는 최대 사실 수다. */\nexport const MAX_FACTS_PER_DOCUMENT = 100_000;\n\n/** 사실의 프로젝트 상대 소스 위치다. */\nexport interface BridgeLocation {\n readonly path: string;\n readonly line: number;\n readonly column: number;\n}\n\n/** 사실을 감싸는 언어별 선언 식별자다. */\nexport interface BridgeSymbol {\n readonly qualifiedName: string;\n readonly usr?: string;\n}\n\n/** 생산 도구 하나가 관찰한 언어 경계 사실이다. */\nexport interface BridgeFact {\n readonly kind: BridgeFactKind;\n readonly channel: string | null;\n readonly method?: string;\n readonly dynamic: boolean;\n readonly location: BridgeLocation;\n readonly symbol?: BridgeSymbol;\n readonly sourceLanguage?: BridgeSourceLanguage;\n}\n\n/** bridge-facts 버전 1 문서다. */\nexport interface BridgeFactsDocument {\n readonly format: 'bridge-facts';\n readonly version: 1;\n readonly tool: Readonly<{ name: string; version: string }>;\n readonly generatedAt: string;\n readonly platform: BridgePlatform;\n readonly target: BridgeTarget | null;\n readonly project: string;\n readonly facts: readonly BridgeFact[];\n readonly limitations: readonly string[];\n readonly limitationScopes?: readonly BridgeLimitationScope[];\n}\n\n/** 외부 교환 문서가 v1 계약을 어겼음을 나타낸다. */\nexport class BridgeFactsValidationError extends Error {\n /** 입력 내용을 노출하지 않는 안전한 메시지를 보존한다. */\n constructor(message: string) {\n super(message);\n this.name = 'BridgeFactsValidationError';\n }\n}\n\n/** 신뢰하지 않는 JSON 값을 검증된 bridge-facts v1 문서로 바꾼다. */\nexport function parseBridgeFactsDocument(input: unknown): BridgeFactsDocument {\n if (!isJsonObject(input)) {\n throw new BridgeFactsValidationError(\n 'Bridge facts must be a JSON object.',\n );\n }\n if (input.format !== 'bridge-facts') {\n throw new BridgeFactsValidationError('Expected format \"bridge-facts\".');\n }\n if (input.version !== 1) {\n throw new BridgeFactsValidationError(\n 'Unsupported bridge-facts version; expected version 1.',\n );\n }\n validateDocumentMetadata(input);\n return normalizeDocument(input);\n}\n\n/** 검증된 입력에서 v1 허용 필드만 복사해 신뢰 경계 밖 데이터를 제거한다. */\nfunction normalizeDocument(document: BridgeFactsDocument): BridgeFactsDocument {\n return {\n format: 'bridge-facts',\n version: 1,\n tool: { name: document.tool.name, version: document.tool.version },\n generatedAt: document.generatedAt,\n platform: document.platform,\n target: document.target,\n project: document.project,\n facts: document.facts.map(normalizeFact),\n limitations: [...document.limitations],\n ...(document.limitationScopes === undefined ? {} : {\n limitationScopes: document.limitationScopes.map((scope) => ({\n limitationIndex: scope.limitationIndex,\n channels: [...new Set(scope.channels)].sort(),\n })).sort((a, b) => a.limitationIndex - b.limitationIndex),\n }),\n };\n}\n\n/** 사실과 중첩 위치·심볼에서 계약 필드만 보존한다. */\nfunction normalizeFact(fact: BridgeFact): BridgeFact {\n const symbol = fact.symbol === undefined\n ? {}\n : {\n symbol: {\n qualifiedName: fact.symbol.qualifiedName,\n ...(fact.symbol.usr === undefined ? {} : { usr: fact.symbol.usr }),\n },\n };\n return {\n kind: fact.kind,\n channel: fact.channel,\n ...(fact.method === undefined ? {} : { method: fact.method }),\n dynamic: fact.dynamic,\n location: {\n path: fact.location.path,\n line: fact.location.line,\n column: fact.location.column,\n },\n ...symbol,\n ...(fact.sourceLanguage === undefined ? {} : { sourceLanguage: fact.sourceLanguage }),\n };\n}\n\n/** 문서 수준 필드가 v1 타입과 허용값을 따르는지 검증한다. */\nfunction validateDocumentMetadata(\n document: Record<string, unknown>,\n): asserts document is Record<string, unknown> & BridgeFactsDocument {\n validateTool(document.tool);\n if (!isBridgeTimestamp(document.generatedAt)) fail('Invalid generatedAt timestamp.');\n if (!bridgePlatforms.has(document.platform)) fail('Unsupported bridge platform.');\n if (document.target !== null && !bridgeTargets.has(document.target)) {\n fail('Unsupported bridge target.');\n }\n if (!isSafeNonEmptyString(document.project)) fail('Invalid project path.');\n if (!Array.isArray(document.facts)) fail('Facts must be an array.');\n if (document.facts.length > MAX_FACTS_PER_DOCUMENT) {\n fail(`Facts exceed the ${MAX_FACTS_PER_DOCUMENT} item limit.`);\n }\n document.facts.forEach((fact, index) =>\n validateFact(fact, index, document.platform),\n );\n if ((document.target === null) !== (document.facts.length === 0)) {\n fail('Target must be set exactly when facts are present.');\n }\n if (!isStringArray(document.limitations)) fail('Limitations must be strings.');\n validateLimitationScopes(document.limitationScopes, document.limitations.length);\n const hasUnattributedHandler = document.facts.some(\n (fact) =>\n isJsonObject(fact) &&\n fact.kind === 'method-handle' &&\n fact.channel === null,\n );\n if (\n hasUnattributedHandler &&\n !document.limitations.some((message) =>\n message.startsWith('unattributed-method-handles:'))\n ) {\n fail('Unattributed method handles require a limitation.');\n }\n}\n\n/** 잘못된 범위를 무시하면 거짓 error가 생기므로 입력 단계에서 명시적으로 거부한다. */\nfunction validateLimitationScopes(value: unknown, limitationCount: number): void {\n if (value === undefined) return;\n if (!Array.isArray(value) || value.length > MAX_LIMITATION_SCOPES) {\n fail('Invalid limitation scopes array.');\n }\n const indices = new Set<number>();\n let channelCount = 0;\n for (const entry of value) {\n if (!isJsonObject(entry) || !Number.isSafeInteger(entry.limitationIndex) ||\n typeof entry.limitationIndex !== 'number' || entry.limitationIndex < 0 ||\n entry.limitationIndex >= limitationCount || indices.has(entry.limitationIndex)) {\n fail('Invalid or duplicate limitation scope index.');\n }\n if (!Array.isArray(entry.channels) || entry.channels.length === 0 ||\n !entry.channels.every(isSafeNonEmptyString)) {\n fail('Limitation scope channels must be non-empty safe strings.');\n }\n channelCount += entry.channels.length;\n if (channelCount > MAX_SCOPED_CHANNELS) fail('Too many scoped channels.');\n indices.add(entry.limitationIndex);\n }\n}\n\n/** 사실 하나의 조인 키와 증거 필드를 검증한다. */\nfunction validateFact(value: unknown, index: number, platform: unknown): void {\n if (!isJsonObject(value)) fail(`Fact at index ${index} must be a JSON object.`);\n if (!bridgeFactKinds.has(value.kind)) fail(`Invalid fact kind at index ${index}.`);\n if (!supportedBridgeFactKinds.has(value.kind)) {\n fail(`Fact kind is reserved but not supported in isthmus 0.1 at index ${index}.`);\n }\n if (!isFactKindForPlatform(platform, value.kind)) {\n fail(`Fact kind is not valid for platform at index ${index}.`);\n }\n if (!methodFactKinds.has(value.kind) && value.method !== undefined) {\n fail(`Unexpected method at index ${index}.`);\n }\n if (\n value.channel === null\n ? value.kind !== 'method-handle'\n : !isSafeNonEmptyString(value.channel)\n ) {\n fail(`Invalid fact channel at index ${index}.`);\n }\n if (methodFactKinds.has(value.kind) && !isSafeNonEmptyString(value.method)) {\n fail(`Method fact at index ${index} requires a method name.`);\n }\n if (typeof value.dynamic !== 'boolean') fail(`Invalid dynamic flag at index ${index}.`);\n validateLocation(value.location, index);\n validateSymbol(value.symbol, index);\n if (value.sourceLanguage !== undefined && (\n value.sourceLanguage !== 'objective-c' || platform !== 'swift' ||\n !/\\.(?:m|mm)$/u.test((value.location as BridgeLocation).path) ||\n (value.symbol !== undefined && (value.symbol as BridgeSymbol).usr !== undefined &&\n !(value.symbol as BridgeSymbol).usr?.startsWith('c:'))\n )) fail(`Invalid source language at index ${index}.`);\n}\n\n/** 호출 측과 수신 측 플랫폼이 생산할 수 있는 fact 종류인지 확인한다. */\nfunction isFactKindForPlatform(platform: unknown, kind: unknown): boolean {\n return isCallerPlatform(platform)\n ? callerFactKinds.has(kind)\n : receiverFactKinds.has(kind);\n}\n\n/** 브리지 호출 측 사실을 생산하는 플랫폼인지 확인한다. */\nexport function isCallerPlatform(platform: unknown): platform is 'dart' | 'js' {\n return platform === 'dart' || platform === 'js';\n}\n\n/** 브리지 수신 측 사실을 생산하는 플랫폼인지 확인한다. */\nexport function isReceiverPlatform(\n platform: unknown,\n): platform is 'swift' | 'kotlin' {\n return platform === 'swift' || platform === 'kotlin';\n}\n\n/** 값이 계약이 정한 브리지 메커니즘 이름인지 확인한다. */\nexport function isBridgeTarget(value: unknown): value is BridgeTarget {\n return bridgeTargets.has(value);\n}\n\n/** 조인 키를 깨뜨리는 제어 문자가 없는 비어 있지 않은 문자열인지 확인한다. */\nexport function isSafeNonEmptyString(value: unknown): value is string {\n return isNonEmptyString(value) && !controlCharacterPattern.test(value);\n}\n\n/** 사실 위치가 상대 경로와 1부터 시작하는 줄·열을 갖는지 검증한다. */\nfunction validateLocation(value: unknown, index: number): void {\n if (\n !isJsonObject(value) ||\n !isProjectRelativePath(value.path) ||\n !isPositiveInteger(value.line) ||\n !isPositiveInteger(value.column)\n ) {\n fail(`Invalid fact location at index ${index}.`);\n }\n}\n\n/** 절대·상위 경로와 제어 문자를 제외한 프로젝트 상대 경로인지 확인한다. */\nfunction isProjectRelativePath(value: unknown): value is string {\n if (!isNonEmptyString(value)) return false;\n if (/^(?:[/\\\\]|[A-Za-z]:)/u.test(value)) return false;\n if (controlCharacterPattern.test(value)) return false;\n return !value.split(/[/\\\\]/u).includes('..');\n}\n\n/** 선택 symbol의 이름과 USR이 비어 있지 않은지 검증한다. */\nfunction validateSymbol(value: unknown, index: number): void {\n if (value === undefined) return;\n if (\n !isJsonObject(value) ||\n !isSafeNonEmptyString(value.qualifiedName) ||\n (value.usr !== undefined && !isSafeNonEmptyString(value.usr))\n ) {\n fail(`Invalid fact symbol at index ${index}.`);\n }\n}\n\n/** 생산 도구 이름과 버전이 비어 있지 않은지 검증한다. */\nfunction validateTool(value: unknown): void {\n if (\n !isJsonObject(value) ||\n !isSafeNonEmptyString(value.name) ||\n !isSafeNonEmptyString(value.version)\n ) {\n fail('Invalid tool metadata.');\n }\n}\n\n/** ISO 계열 생성 시각으로 해석할 수 있는지 확인한다. */\nexport function isBridgeTimestamp(value: unknown): value is string {\n if (typeof value !== 'string') return false;\n const match = timestampPattern.exec(value);\n if (match === null || Number.isNaN(Date.parse(value))) return false;\n const year = Number(match[1]);\n const month = Number(match[2]);\n const day = Number(match[3]);\n const hour = Number(match[4]);\n const minute = Number(match[5]);\n const second = Number(match[6]);\n return (\n month >= 1 &&\n month <= 12 &&\n day >= 1 &&\n day <= daysInMonth(year, month) &&\n hour <= 23 &&\n minute <= 59 &&\n second <= 59\n );\n}\n\n/** 윤년을 포함한 주어진 달의 실제 일수를 반환한다. */\nfunction daysInMonth(year: number, month: number): number {\n if (month === 2) {\n const isLeapYear = year % 4 === 0 && (year % 100 !== 0 || year % 400 === 0);\n return isLeapYear ? 29 : 28;\n }\n return [4, 6, 9, 11].includes(month) ? 30 : 31;\n}\n\n/** 공백만 있지 않은 문자열인지 확인한다. */\nfunction isNonEmptyString(value: unknown): value is string {\n return typeof value === 'string' && value.trim().length > 0;\n}\n\n/** 모든 원소가 문자열인 배열인지 확인한다. */\nfunction isStringArray(value: unknown): value is readonly string[] {\n return Array.isArray(value) && value.every((item) => typeof item === 'string');\n}\n\n/** 1부터 시작하는 정수인지 확인한다. */\nfunction isPositiveInteger(value: unknown): value is number {\n return Number.isSafeInteger(value) && Number(value) >= 1;\n}\n\n/** 입력 값을 포함하지 않는 검증 오류를 던진다. */\nfunction fail(message: string): never {\n throw new BridgeFactsValidationError(message);\n}\n\n/** 지원하는 생산 플랫폼 집합이다. */\nconst bridgePlatforms = new Set<unknown>(['dart', 'swift', 'kotlin', 'js']);\n\n/** 지원하는 브리지 메커니즘 집합이다. */\nconst bridgeTargets = new Set<unknown>([\n 'flutter',\n 'react-native',\n 'capacitor',\n]);\n\n/** 버전 1이 정의한 사실 종류 집합이다. */\nconst bridgeFactKinds = new Set<unknown>([\n 'channel-create',\n 'channel-register',\n 'method-invoke',\n 'method-handle',\n 'module-export',\n 'module-import',\n 'component-export',\n 'component-require',\n]);\n\n/** 0.1 조인과 보고가 실제로 처리하는 사실 종류다. */\nconst supportedBridgeFactKinds = new Set<unknown>([\n 'channel-create',\n 'channel-register',\n 'method-invoke',\n 'method-handle',\n]);\n\nconst callerFactKinds = new Set<unknown>([\n 'channel-create',\n 'method-invoke',\n 'module-import',\n 'component-require',\n]);\nconst receiverFactKinds = new Set<unknown>([\n 'channel-register',\n 'method-handle',\n 'module-export',\n 'component-export',\n]);\n\n/** method 필드가 필수인 사실 종류다. */\nconst methodFactKinds = new Set<unknown>(['method-invoke', 'method-handle']);\n\nconst timestampPattern =\n /^(\\d{4})-(\\d{2})-(\\d{2})T(\\d{2}):(\\d{2}):(\\d{2})(?:\\.\\d+)?(?:Z|[+-]\\d{2}:\\d{2})$/u;\nconst controlCharacterPattern = /[\\u0000-\\u001f\\u007f-\\u009f\\u2028\\u2029]/u;\n\n/** 배열과 null을 제외한 JSON 객체인지 확인한다. isthmus 소유 문서 검증도 재사용한다. */\nexport function isJsonObject(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null && !Array.isArray(value);\n}\n"]}
|
|
1
|
+
{"version":3,"file":"parse.js","sourceRoot":"","sources":["../../src/exchange/parse.ts"],"names":[],"mappings":"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","sourcesContent":["/** bridge-facts 생산 플랫폼이다. */\nexport type BridgePlatform = 'dart' | 'swift' | 'kotlin' | 'js';\n\n/** 언어 경계를 잇는 메커니즘이다. */\nexport type BridgeTarget = 'flutter' | 'react-native' | 'capacitor';\n\n/** Swift 플랫폼 문서에 실린 Objective-C 구현을 Swift 보존 대상과 구분한다. */\nexport type BridgeSourceLanguage = 'objective-c';\n\n/** 특정 한계 전체의 영향을 포함하는 채널 집합. 일부 발견 목록이 아니다. */\nexport interface BridgeLimitationScope {\n readonly limitationIndex: number;\n readonly channels: readonly string[];\n}\n\n/** 확장 메타데이터가 입력 자원 상한을 우회하지 못하게 한다. */\nexport const MAX_LIMITATION_SCOPES = 1_000;\nexport const MAX_SCOPED_CHANNELS = 10_000;\n\n/** 교환 형식의 사실 종류다. */\nexport type BridgeFactKind =\n | 'channel-create'\n | 'channel-register'\n | 'method-invoke'\n | 'method-handle'\n | 'module-export'\n | 'module-import'\n | 'component-export'\n | 'component-require';\n\n/** 한 생산 문서가 담을 수 있는 최대 사실 수다. */\nexport const MAX_FACTS_PER_DOCUMENT = 100_000;\n\n/** 사실의 프로젝트 상대 소스 위치다. */\nexport interface BridgeLocation {\n readonly path: string;\n readonly line: number;\n readonly column: number;\n}\n\n/** 사실을 감싸는 언어별 선언 식별자다. */\nexport interface BridgeSymbol {\n readonly qualifiedName: string;\n readonly usr?: string;\n}\n\n/** 생산 도구 하나가 관찰한 언어 경계 사실이다. */\nexport interface BridgeFact {\n readonly kind: BridgeFactKind;\n readonly channel: string | null;\n readonly method?: string;\n readonly dynamic: boolean;\n readonly location: BridgeLocation;\n readonly symbol?: BridgeSymbol;\n readonly sourceLanguage?: BridgeSourceLanguage;\n}\n\n/** bridge-facts 버전 1 문서다. */\nexport interface BridgeFactsDocument {\n readonly format: 'bridge-facts';\n readonly version: 1;\n readonly tool: Readonly<{ name: string; version: string }>;\n readonly generatedAt: string;\n readonly platform: BridgePlatform;\n readonly target: BridgeTarget | null;\n readonly project: string;\n readonly facts: readonly BridgeFact[];\n readonly limitations: readonly string[];\n readonly limitationScopes?: readonly BridgeLimitationScope[];\n}\n\n/** 외부 교환 문서가 v1 계약을 어겼음을 나타낸다. */\nexport class BridgeFactsValidationError extends Error {\n /** 입력 내용을 노출하지 않는 안전한 메시지를 보존한다. */\n constructor(message: string) {\n super(message);\n this.name = 'BridgeFactsValidationError';\n }\n}\n\n/** 신뢰하지 않는 JSON 값을 검증된 bridge-facts v1 문서로 바꾼다. */\nexport function parseBridgeFactsDocument(input: unknown): BridgeFactsDocument {\n if (!isJsonObject(input)) {\n throw new BridgeFactsValidationError(\n 'Bridge facts must be a JSON object.',\n );\n }\n if (input.format !== 'bridge-facts') {\n throw new BridgeFactsValidationError('Expected format \"bridge-facts\".');\n }\n if (input.version !== 1) {\n throw new BridgeFactsValidationError(\n 'Unsupported bridge-facts version; expected version 1.',\n );\n }\n validateDocumentMetadata(input);\n return normalizeDocument(input);\n}\n\n/** 검증된 입력에서 v1 허용 필드만 복사해 신뢰 경계 밖 데이터를 제거한다. */\nfunction normalizeDocument(document: BridgeFactsDocument): BridgeFactsDocument {\n return {\n format: 'bridge-facts',\n version: 1,\n tool: { name: document.tool.name, version: document.tool.version },\n generatedAt: document.generatedAt,\n platform: document.platform,\n target: document.target,\n project: document.project,\n facts: document.facts.map(normalizeFact),\n limitations: [...document.limitations],\n ...(document.limitationScopes === undefined ? {} : {\n limitationScopes: document.limitationScopes.map((scope) => ({\n limitationIndex: scope.limitationIndex,\n channels: [...new Set(scope.channels)].sort(),\n })).sort((a, b) => a.limitationIndex - b.limitationIndex),\n }),\n };\n}\n\n/** 사실과 중첩 위치·심볼에서 계약 필드만 보존한다. */\nfunction normalizeFact(fact: BridgeFact): BridgeFact {\n const symbol = fact.symbol === undefined\n ? {}\n : {\n symbol: {\n qualifiedName: fact.symbol.qualifiedName,\n ...(fact.symbol.usr === undefined ? {} : { usr: fact.symbol.usr }),\n },\n };\n return {\n kind: fact.kind,\n channel: fact.channel,\n ...(fact.method === undefined ? {} : { method: fact.method }),\n dynamic: fact.dynamic,\n location: {\n path: fact.location.path,\n line: fact.location.line,\n column: fact.location.column,\n },\n ...symbol,\n ...(fact.sourceLanguage === undefined ? {} : { sourceLanguage: fact.sourceLanguage }),\n };\n}\n\n/** 문서 수준 필드가 v1 타입과 허용값을 따르는지 검증한다. */\nfunction validateDocumentMetadata(\n document: Record<string, unknown>,\n): asserts document is Record<string, unknown> & BridgeFactsDocument {\n validateTool(document.tool);\n if (!isBridgeTimestamp(document.generatedAt)) fail('Invalid generatedAt timestamp.');\n if (!bridgePlatforms.has(document.platform)) fail('Unsupported bridge platform.');\n if (document.target !== null && !bridgeTargets.has(document.target)) {\n fail('Unsupported bridge target.');\n }\n if (!isSafeNonEmptyString(document.project)) fail('Invalid project path.');\n if (!Array.isArray(document.facts)) fail('Facts must be an array.');\n if (document.facts.length > MAX_FACTS_PER_DOCUMENT) {\n fail(`Facts exceed the ${MAX_FACTS_PER_DOCUMENT} item limit.`);\n }\n document.facts.forEach((fact, index) =>\n validateFact(fact, index, document.platform),\n );\n if ((document.target === null) !== (document.facts.length === 0)) {\n fail('Target must be set exactly when facts are present.');\n }\n if (!isStringArray(document.limitations)) fail('Limitations must be strings.');\n validateLimitationScopes(document.limitationScopes, document.limitations.length);\n const hasUnattributedHandler = document.facts.some(\n (fact) =>\n isJsonObject(fact) &&\n fact.kind === 'method-handle' &&\n fact.channel === null,\n );\n if (\n hasUnattributedHandler &&\n !document.limitations.some((message) =>\n message.startsWith('unattributed-method-handles:'))\n ) {\n fail('Unattributed method handles require a limitation.');\n }\n}\n\n/** 잘못된 범위를 무시하면 거짓 error가 생기므로 입력 단계에서 명시적으로 거부한다. */\nfunction validateLimitationScopes(value: unknown, limitationCount: number): void {\n if (value === undefined) return;\n if (!Array.isArray(value) || value.length > MAX_LIMITATION_SCOPES) {\n fail('Invalid limitation scopes array.');\n }\n const indices = new Set<number>();\n let channelCount = 0;\n for (const entry of value) {\n if (!isJsonObject(entry) || !Number.isSafeInteger(entry.limitationIndex) ||\n typeof entry.limitationIndex !== 'number' || entry.limitationIndex < 0 ||\n entry.limitationIndex >= limitationCount || indices.has(entry.limitationIndex)) {\n fail('Invalid or duplicate limitation scope index.');\n }\n if (!Array.isArray(entry.channels) || entry.channels.length === 0 ||\n !entry.channels.every(isSafeNonEmptyString)) {\n fail('Limitation scope channels must be non-empty safe strings.');\n }\n channelCount += entry.channels.length;\n if (channelCount > MAX_SCOPED_CHANNELS) fail('Too many scoped channels.');\n indices.add(entry.limitationIndex);\n }\n}\n\n/** 사실 하나의 조인 키와 증거 필드를 검증한다. */\nfunction validateFact(value: unknown, index: number, platform: unknown): void {\n if (!isJsonObject(value)) fail(`Fact at index ${index} must be a JSON object.`);\n if (!bridgeFactKinds.has(value.kind)) fail(`Invalid fact kind at index ${index}.`);\n if (!supportedBridgeFactKinds.has(value.kind)) {\n fail(`Fact kind is reserved but not supported by this isthmus version at index ${index}.`);\n }\n if (!isFactKindForPlatform(platform, value.kind)) {\n fail(`Fact kind is not valid for platform at index ${index}.`);\n }\n if (!methodFactKinds.has(value.kind) && value.method !== undefined) {\n fail(`Unexpected method at index ${index}.`);\n }\n if (\n value.channel === null\n ? value.kind !== 'method-handle'\n : !isSafeNonEmptyString(value.channel)\n ) {\n fail(`Invalid fact channel at index ${index}.`);\n }\n if (methodFactKinds.has(value.kind) && !isSafeNonEmptyString(value.method)) {\n fail(`Method fact at index ${index} requires a method name.`);\n }\n if (typeof value.dynamic !== 'boolean') fail(`Invalid dynamic flag at index ${index}.`);\n validateLocation(value.location, index);\n validateSymbol(value.symbol, index);\n if (value.sourceLanguage !== undefined && (\n value.sourceLanguage !== 'objective-c' || platform !== 'swift' ||\n !/\\.(?:m|mm)$/u.test((value.location as BridgeLocation).path) ||\n (value.symbol !== undefined && (value.symbol as BridgeSymbol).usr !== undefined &&\n !(value.symbol as BridgeSymbol).usr?.startsWith('c:'))\n )) fail(`Invalid source language at index ${index}.`);\n}\n\n/** 호출 측과 수신 측 플랫폼이 생산할 수 있는 fact 종류인지 확인한다. */\nfunction isFactKindForPlatform(platform: unknown, kind: unknown): boolean {\n return isCallerPlatform(platform)\n ? callerFactKinds.has(kind)\n : receiverFactKinds.has(kind);\n}\n\n/** 브리지 호출 측 사실을 생산하는 플랫폼인지 확인한다. */\nexport function isCallerPlatform(platform: unknown): platform is 'dart' | 'js' {\n return platform === 'dart' || platform === 'js';\n}\n\n/** 브리지 수신 측 사실을 생산하는 플랫폼인지 확인한다. */\nexport function isReceiverPlatform(\n platform: unknown,\n): platform is 'swift' | 'kotlin' {\n return platform === 'swift' || platform === 'kotlin';\n}\n\n/** 값이 계약이 정한 브리지 메커니즘 이름인지 확인한다. */\nexport function isBridgeTarget(value: unknown): value is BridgeTarget {\n return bridgeTargets.has(value);\n}\n\n/** 조인 키를 깨뜨리는 제어 문자가 없는 비어 있지 않은 문자열인지 확인한다. */\nexport function isSafeNonEmptyString(value: unknown): value is string {\n return isNonEmptyString(value) && !controlCharacterPattern.test(value) &&\n !hasUnpairedSurrogate(value);\n}\n\n/** 유효한 UTF-16 문자열인지, 즉 짝 없는 서러게이트가 없는지 확인한다. */\nfunction hasUnpairedSurrogate(value: string): boolean {\n // 아스트랄 문자(이모지 등)는 유효한 서러게이트 쌍이므로 그대로 통과한다.\n // 짝 없는 서러게이트는 어떤 인코딩의 파일에도 존재할 수 없어 JSON 이스케이프로만\n // 들어오며, URI 인코딩이 실패하는 등 소비 경로마다 깨진다.\n return value.toWellFormed() !== value;\n}\n\n/** 사실 위치가 상대 경로와 1부터 시작하는 줄·열을 갖는지 검증한다. */\nfunction validateLocation(value: unknown, index: number): void {\n if (\n !isJsonObject(value) ||\n !isProjectRelativePath(value.path) ||\n !isPositiveInteger(value.line) ||\n !isPositiveInteger(value.column)\n ) {\n fail(`Invalid fact location at index ${index}.`);\n }\n}\n\n/** 절대·상위 경로와 제어 문자를 제외한 프로젝트 상대 경로인지 확인한다. */\nfunction isProjectRelativePath(value: unknown): value is string {\n if (!isNonEmptyString(value)) return false;\n if (/^(?:[/\\\\]|[A-Za-z]:)/u.test(value)) return false;\n if (controlCharacterPattern.test(value) || hasUnpairedSurrogate(value)) {\n return false;\n }\n return !value.split(/[/\\\\]/u).includes('..');\n}\n\n/** 선택 symbol의 이름과 USR이 비어 있지 않은지 검증한다. */\nfunction validateSymbol(value: unknown, index: number): void {\n if (value === undefined) return;\n if (\n !isJsonObject(value) ||\n !isSafeNonEmptyString(value.qualifiedName) ||\n (value.usr !== undefined && !isSafeNonEmptyString(value.usr))\n ) {\n fail(`Invalid fact symbol at index ${index}.`);\n }\n}\n\n/** 생산 도구 이름과 버전이 비어 있지 않은지 검증한다. */\nfunction validateTool(value: unknown): void {\n if (\n !isJsonObject(value) ||\n !isSafeNonEmptyString(value.name) ||\n !isSafeNonEmptyString(value.version)\n ) {\n fail('Invalid tool metadata.');\n }\n}\n\n/** ISO 계열 생성 시각으로 해석할 수 있는지 확인한다. */\nexport function isBridgeTimestamp(value: unknown): value is string {\n if (typeof value !== 'string') return false;\n const match = timestampPattern.exec(value);\n if (match === null || Number.isNaN(Date.parse(value))) return false;\n const year = Number(match[1]);\n const month = Number(match[2]);\n const day = Number(match[3]);\n const hour = Number(match[4]);\n const minute = Number(match[5]);\n const second = Number(match[6]);\n return (\n month >= 1 &&\n month <= 12 &&\n day >= 1 &&\n day <= daysInMonth(year, month) &&\n hour <= 23 &&\n minute <= 59 &&\n second <= 59\n );\n}\n\n/** 윤년을 포함한 주어진 달의 실제 일수를 반환한다. */\nfunction daysInMonth(year: number, month: number): number {\n if (month === 2) {\n const isLeapYear = year % 4 === 0 && (year % 100 !== 0 || year % 400 === 0);\n return isLeapYear ? 29 : 28;\n }\n return [4, 6, 9, 11].includes(month) ? 30 : 31;\n}\n\n/** 공백만 있지 않은 문자열인지 확인한다. */\nfunction isNonEmptyString(value: unknown): value is string {\n return typeof value === 'string' && value.trim().length > 0;\n}\n\n/** 모든 원소가 문자열인 배열인지 확인한다. */\nfunction isStringArray(value: unknown): value is readonly string[] {\n return Array.isArray(value) && value.every((item) => typeof item === 'string');\n}\n\n/** 1부터 시작하는 정수인지 확인한다. */\nfunction isPositiveInteger(value: unknown): value is number {\n return Number.isSafeInteger(value) && Number(value) >= 1;\n}\n\n/** 입력 값을 포함하지 않는 검증 오류를 던진다. */\nfunction fail(message: string): never {\n throw new BridgeFactsValidationError(message);\n}\n\n/** 지원하는 생산 플랫폼 집합이다. */\nconst bridgePlatforms = new Set<unknown>(['dart', 'swift', 'kotlin', 'js']);\n\n/** 지원하는 브리지 메커니즘 집합이다. */\nconst bridgeTargets = new Set<unknown>([\n 'flutter',\n 'react-native',\n 'capacitor',\n]);\n\n/** 버전 1이 정의한 사실 종류 집합이다. */\nconst bridgeFactKinds = new Set<unknown>([\n 'channel-create',\n 'channel-register',\n 'method-invoke',\n 'method-handle',\n 'module-export',\n 'module-import',\n 'component-export',\n 'component-require',\n]);\n\n/** 0.1 조인과 보고가 실제로 처리하는 사실 종류다. */\nconst supportedBridgeFactKinds = new Set<unknown>([\n 'channel-create',\n 'channel-register',\n 'method-invoke',\n 'method-handle',\n]);\n\nconst callerFactKinds = new Set<unknown>([\n 'channel-create',\n 'method-invoke',\n 'module-import',\n 'component-require',\n]);\nconst receiverFactKinds = new Set<unknown>([\n 'channel-register',\n 'method-handle',\n 'module-export',\n 'component-export',\n]);\n\n/** method 필드가 필수인 사실 종류다. */\nconst methodFactKinds = new Set<unknown>(['method-invoke', 'method-handle']);\n\nconst timestampPattern =\n /^(\\d{4})-(\\d{2})-(\\d{2})T(\\d{2}):(\\d{2}):(\\d{2})(?:\\.\\d+)?(?:Z|[+-]\\d{2}:\\d{2})$/u;\nconst controlCharacterPattern = /[\\u0000-\\u001f\\u007f-\\u009f\\u2028\\u2029]/u;\n\n/** 배열과 null을 제외한 JSON 객체인지 확인한다. isthmus 소유 문서 검증도 재사용한다. */\nexport function isJsonObject(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null && !Array.isArray(value);\n}\n"]}
|
package/dist/join/join.js
CHANGED
|
@@ -93,8 +93,13 @@ function validatePlatformComposition(documents) {
|
|
|
93
93
|
}
|
|
94
94
|
/** 사실별 target이 없는 혼합 문서인지 확인한다. */
|
|
95
95
|
function hasMixedTargets(document) {
|
|
96
|
-
|
|
96
|
+
// 단어 경계로 판정한다. 낱말 안에 붙은 표기("non-mixed-targets workspaces",
|
|
97
|
+
// "mixed-targets-like")는 문구 변형이 아니라 다른 낱말이라 보류의 근거가 못 된다.
|
|
98
|
+
// 앞 공백·대소문자·콜론 누락 변형은 계속 보수적으로 인정한다.
|
|
99
|
+
return document.limitations.some((message) => mixedTargetToken.test(message));
|
|
97
100
|
}
|
|
101
|
+
/** 문구 변형을 인정하는 mixed-targets 토큰 경계다. */
|
|
102
|
+
const mixedTargetToken = /(?<![\w-])mixed-targets(?![\w-])/i;
|
|
98
103
|
/**
|
|
99
104
|
* 한계를 귀속시킬 target을 결정한다.
|
|
100
105
|
*
|
package/dist/join/join.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"join.js","sourceRoot":"","sources":["../../src/join/join.ts"],"names":[],"mappings":"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","sourcesContent":["import type {\n BridgeFact,\n BridgeFactsDocument,\n BridgeLocation,\n BridgePlatform,\n BridgeSymbol,\n BridgeSourceLanguage,\n BridgeTarget,\n} from '../exchange/parse.ts';\nimport { compareStrings } from '../compare.ts';\nimport { isCallerPlatform, isReceiverPlatform } from '../exchange/parse.ts';\n\n/** 한 언어 문서가 제공한 브리지 증거 위치다. */\nexport interface BridgeEndpoint {\n readonly platform: BridgePlatform;\n readonly location: BridgeLocation;\n readonly symbol?: BridgeSymbol;\n readonly sourceLanguage?: BridgeSourceLanguage;\n}\n\n/** 논리 채널 하나에 모인 양쪽 생성·등록 증거다. */\nexport interface MatchedChannel {\n readonly target: BridgeTarget;\n readonly channel: string;\n readonly creations: readonly BridgeEndpoint[];\n readonly registrations: readonly BridgeEndpoint[];\n}\n\n/** 등록을 찾지 못한 논리 채널과 모든 생성 증거다. */\nexport interface UnregisteredChannelCreation {\n readonly target: BridgeTarget;\n readonly channel: string;\n readonly creations: readonly BridgeEndpoint[];\n}\n\n/** 생성을 찾지 못한 논리 채널과 모든 등록 증거다. */\nexport interface RegistrationWithoutCreation {\n readonly target: BridgeTarget;\n readonly channel: string;\n readonly registrations: readonly BridgeEndpoint[];\n}\n\n/** 논리 메서드 하나에 모인 양쪽 호출·핸들러 증거다. */\nexport interface MatchedMethod {\n readonly target: BridgeTarget;\n readonly channel: string;\n readonly method: string;\n readonly invocations: readonly BridgeEndpoint[];\n readonly handlers: readonly BridgeEndpoint[];\n}\n\n/** 핸들러를 찾지 못한 논리 호출과 모든 호출 증거다. */\nexport interface UnhandledInvocation {\n readonly target: BridgeTarget;\n readonly channel: string;\n readonly method: string;\n readonly invocations: readonly BridgeEndpoint[];\n}\n\n/** 호출자를 찾지 못한 논리 핸들러와 모든 네이티브 증거다. */\nexport interface HandlerWithoutInvocation {\n readonly target: BridgeTarget;\n readonly channel: string;\n readonly method: string;\n readonly handlers: readonly BridgeEndpoint[];\n}\n\n/**\n * 생산 문서가 밝힌 분석 한계와 출처다.\n *\n * `target`은 이 한계를 신고한 문서의 브리지 메커니즘이다. 사실은 target별로만\n * 조인되므로, 보고서는 이 값으로 한계를 해당 target의 진단에만 귀속시킨다.\n * 사실이 없는 문서의 한계, 선언한 target을 신뢰할 수 없는 mixed-targets 문서의\n * 한계, 교차 입력 한계는 어느 target이 가려졌는지 특정할 수 없어 `null`이다.\n */\nexport interface JoinLimitation {\n readonly platform: BridgePlatform | 'cross-platform';\n readonly target: BridgeTarget | null;\n readonly tool: string;\n readonly message: string;\n readonly channels?: readonly string[];\n /** 소비자가 직접 센 한계에만 부여하며 생산 문서에서는 복사하지 않는다. */\n readonly origin?: 'consumer';\n}\n\n/** 검증된 교환 문서들의 논리 조인 결과다. */\nexport interface BridgeJoinResult {\n readonly deferred: boolean;\n /** 입력 문서 전체가 관찰한 fact 수다. 조인 여부와 무관한 관찰량이다. */\n readonly observedFacts: number;\n readonly matchedChannels: readonly MatchedChannel[];\n readonly unregisteredChannelCreations: readonly UnregisteredChannelCreation[];\n readonly registrationsWithoutCreations: readonly RegistrationWithoutCreation[];\n readonly matchedMethods: readonly MatchedMethod[];\n readonly unhandledInvocations: readonly UnhandledInvocation[];\n readonly handlersWithoutInvocations: readonly HandlerWithoutInvocation[];\n readonly limitations: readonly JoinLimitation[];\n}\n\n/** 한 번의 조인에서 허용하는 최대 생산 문서 수다. */\nexport const MAX_DOCUMENTS_PER_JOIN = 256;\n\n/** 함께 조인할 입력 문서 집합이 논리 계약을 위반했음을 나타낸다. */\nexport class BridgeJoinValidationError extends Error {\n /** 입력 경로를 노출하지 않는 안전한 메시지를 보존한다. */\n constructor(message: string) {\n super(message);\n this.name = 'BridgeJoinValidationError';\n }\n}\n\n/** 위치가 아니라 문자열 키로 검증된 교환 문서를 조인한다. */\nexport function joinBridgeDocuments(\n documents: readonly BridgeFactsDocument[],\n): BridgeJoinResult {\n if (documents.length > MAX_DOCUMENTS_PER_JOIN) {\n throw new BridgeJoinValidationError(\n `Bridge join exceeds the ${MAX_DOCUMENTS_PER_JOIN} document limit.`,\n );\n }\n validateProjects(documents);\n validatePlatformComposition(documents);\n const limitations = collectLimitations(documents);\n const observedFacts = documents.reduce(\n (total, document) => total + document.facts.length,\n 0,\n );\n if (documents.some(hasMixedTargets)) {\n return emptyJoinResult(limitations, observedFacts);\n }\n const groups = collectChannelGroups(documents);\n const matchedChannels = [...groups.values()]\n .filter((group) => group.creations.length > 0 && group.registrations.length > 0)\n .sort(compareChannels);\n const unregisteredChannelCreations = [...groups.values()]\n .filter((group) => group.creations.length > 0 && group.registrations.length === 0)\n .map(({ target, channel, creations }) => ({ target, channel, creations }))\n .sort(compareChannels);\n const registrationsWithoutCreations = [...groups.values()]\n .filter((group) => group.registrations.length > 0 && group.creations.length === 0)\n .map(({ target, channel, registrations }) => ({\n target,\n channel,\n registrations,\n }))\n .sort(compareChannels);\n const methodGroups = collectMethodGroups(documents);\n const matchedMethods = [...methodGroups.values()]\n .filter((group) => group.invocations.length > 0 && group.handlers.length > 0)\n .sort(compareMethodKeys);\n const unhandledInvocations = [...methodGroups.values()]\n .filter((group) => group.invocations.length > 0 && group.handlers.length === 0)\n .map(({ target, channel, method, invocations }) => ({\n target,\n channel,\n method,\n invocations,\n }))\n .sort(compareMethodKeys);\n const handlersWithoutInvocations = [...methodGroups.values()]\n .filter((group) => group.handlers.length > 0 && group.invocations.length === 0)\n .map(({ target, channel, method, handlers }) => ({\n target,\n channel,\n method,\n handlers,\n }))\n .sort(compareMethodKeys);\n return {\n deferred: false,\n observedFacts,\n matchedChannels,\n unregisteredChannelCreations,\n registrationsWithoutCreations,\n matchedMethods,\n unhandledInvocations,\n handlersWithoutInvocations,\n limitations,\n };\n}\n\n/** 입력 한계 때문에 조인 전체가 보류된 결과인지 확인한다. */\nexport function isBridgeJoinDeferred(joined: BridgeJoinResult): boolean {\n return joined.deferred;\n}\n\n/** 한 번의 조인 입력이 정확히 하나의 project를 기술하는지 검증한다. */\nfunction validateProjects(documents: readonly BridgeFactsDocument[]): void {\n if (new Set(documents.map(({ project }) => project)).size > 1) {\n throw new BridgeJoinValidationError(\n 'Bridge documents must describe the same project; regenerate them from one project root.',\n );\n }\n}\n\n/** 호출 측·수신 측 문서가 모두 있어야 경계 사실로 조인할 수 있다. */\nfunction validatePlatformComposition(\n documents: readonly BridgeFactsDocument[],\n): void {\n const hasCaller = documents.some(({ platform }) => isCallerPlatform(platform));\n const hasReceiver = documents.some(({ platform }) =>\n isReceiverPlatform(platform),\n );\n if (!hasCaller || !hasReceiver) {\n throw new BridgeJoinValidationError(\n 'Bridge documents must include at least one caller platform (dart, js) document '\n + 'and one receiver platform (swift, kotlin) document; run a producer for the missing side.',\n );\n }\n}\n\n/** 사실별 target이 없는 혼합 문서인지 확인한다. */\nfunction hasMixedTargets(document: BridgeFactsDocument): boolean {\n return document.limitations.some((message) =>\n /mixed-targets\\b/i.test(message),\n );\n}\n\n/**\n * 한계를 귀속시킬 target을 결정한다.\n *\n * mixed-targets 문서의 선언 target은 대표값일 뿐 사실별 메커니즘을 복원할 수\n * 없으므로, 그 문서의 한계와 조인 제외 사실 계수는 귀속 없이(null) 남긴다.\n * 귀속을 잃어도 관찰 자체는 보존해야 한다.\n */\nfunction limitationTarget(document: BridgeFactsDocument): BridgeTarget | null {\n return hasMixedTargets(document) ? null : document.target;\n}\n\n/** 안전하게 조인을 보류하면서 입력 한계만 전달한다. 관찰량은 보존한다. */\nfunction emptyJoinResult(\n limitations: readonly JoinLimitation[],\n observedFacts: number,\n): BridgeJoinResult {\n return {\n deferred: true,\n observedFacts,\n matchedChannels: [],\n unregisteredChannelCreations: [],\n registrationsWithoutCreations: [],\n matchedMethods: [],\n unhandledInvocations: [],\n handlersWithoutInvocations: [],\n limitations,\n };\n}\n\n/** 입력 limitation에 생산 플랫폼과 도구 이름을 붙이고 조인하지 못한 사실을 함께 센다. */\nfunction collectLimitations(\n documents: readonly BridgeFactsDocument[],\n): JoinLimitation[] {\n const limitations: JoinLimitation[] = documents.flatMap((document) => {\n const scopes = new Map(document.limitationScopes?.map((scope) => [scope.limitationIndex, scope.channels]));\n return document.limitations.map((message, index) => {\n const channels = scopes.get(index);\n return {\n platform: document.platform,\n target: limitationTarget(document),\n tool: document.tool.name,\n message,\n ...(channels === undefined ? {} : { channels }),\n };\n });\n });\n limitations.push(...unjoinedFactLimitations(documents));\n const freshness = freshnessLimitation(documents);\n if (freshness !== undefined) limitations.push(freshness);\n return limitations.sort(compareLimitations);\n}\n\n/**\n * 조인에서 제외한 사실을 isthmus 자신의 관찰 한계로 남긴다.\n *\n * 생산자가 같은 사실을 limitation으로 신고하지 않아도, 또는 신고한 개수가 실제와\n * 달라도 관찰 공백이 보고서에서 사라지지 않아야 한다. 교환 계약은 이 사실들을\n * 세도록 요구하지만 문서의 limitation 문자열은 생산자의 자발적인 신고라\n * 소비자가 신뢰의 근거로 삼을 수 없다.\n */\nfunction unjoinedFactLimitations(\n documents: readonly BridgeFactsDocument[],\n): JoinLimitation[] {\n return [\n ...unjoinedLimitations(\n documents,\n isUnjoinedDynamicChannel,\n 'unjoined-dynamic-channels',\n 'channel facts with a non-literal name',\n ),\n ...unjoinedLimitations(\n documents,\n isUnjoinedDynamicMethod,\n 'unjoined-dynamic-methods',\n 'method facts with a non-literal name',\n ),\n ...unjoinedLimitations(\n documents,\n isUnattributedHandler,\n 'unjoined-unattributed-handlers',\n 'method handler facts without a channel',\n ),\n ];\n}\n\n/** 조건에 맞는 사실 수를 플랫폼·target별로 세어 한계 문장으로 바꾼다. */\nfunction unjoinedLimitations(\n documents: readonly BridgeFactsDocument[],\n matchesFact: (fact: BridgeFact) => boolean,\n prefix: string,\n subject: string,\n): JoinLimitation[] {\n return countFactsByPlatformTarget(documents, matchesFact).map(\n ({ platform, target, count }) => ({\n platform,\n target,\n tool: 'isthmus',\n origin: 'consumer',\n message: `${prefix}: ${count} ${subject} were not joined`,\n }),\n );\n}\n\n/**\n * 주어진 조건의 서로 다른 사실 수를 생산 플랫폼·target별로 모은다.\n *\n * 사실은 target별로만 조인되므로 다른 target의 사실을 한 한계로 합산하면\n * 관찰 공백의 귀속이 사라진다. mixed-targets 문서의 사실은 귀속 없이(null)\n * 센다. 사실이 없는 문서는 교환 계약상 target이 null이고 사실도 없으므로\n * 여기에서 자연스럽게 제외된다.\n */\nfunction countFactsByPlatformTarget(\n documents: readonly BridgeFactsDocument[],\n matchesFact: (fact: BridgeFact) => boolean,\n): Array<{\n platform: BridgePlatform;\n target: BridgeTarget | null;\n count: number;\n}> {\n const distinctFacts = new Map<\n string,\n {\n platform: BridgePlatform;\n target: BridgeTarget | null;\n keys: Set<string>;\n }\n >();\n for (const document of documents) {\n const target = limitationTarget(document);\n // BridgeTarget은 닫힌 어휘라 문자열화된 null과 충돌하지 않는다.\n const groupKey = `${document.platform}\\u0000${target}`;\n for (const fact of document.facts) {\n if (!matchesFact(fact)) continue;\n const group = distinctFacts.get(groupKey) ?? {\n platform: document.platform,\n target,\n keys: new Set<string>(),\n };\n group.keys.add(unjoinedFactKey(fact));\n distinctFacts.set(groupKey, group);\n }\n }\n return [...distinctFacts.values()].map(({ platform, target, keys }) => ({\n platform,\n target,\n count: keys.size,\n }));\n}\n\n/**\n * 같은 위치의 중복 사실을 한 번만 세는 키를 만든다.\n *\n * 위치 기준은 증거 dedup과 같지만 symbol은 비교하지 않아, 같은 위치의 서로\n * 다른 symbol은 하나로 센다. `channel`은 null일 수 있어 구분자 결합 대신\n * JSON으로 만든다. 그래야 미귀속 핸들러와 이름이 `null`인 채널의 사실이\n * 같은 키로 합쳐지지 않는다.\n */\nfunction unjoinedFactKey(fact: BridgeFact): string {\n const { path, line, column } = fact.location;\n return JSON.stringify([\n fact.kind,\n fact.channel,\n fact.method ?? null,\n path,\n line,\n column,\n ]);\n}\n\n/** 이름이 리터럴이 아니어서 조인하지 못한 채널 사실인지 확인한다. */\nfunction isUnjoinedDynamicChannel(fact: BridgeFact): boolean {\n return (\n fact.dynamic &&\n (fact.kind === 'channel-create' || fact.kind === 'channel-register')\n );\n}\n\n/** 이름이 리터럴이 아니어서 조인하지 못한 메서드 사실인지 확인한다. */\nfunction isUnjoinedDynamicMethod(fact: BridgeFact): boolean {\n return (\n fact.dynamic &&\n (fact.kind === 'method-invoke' || fact.kind === 'method-handle')\n );\n}\n\n/**\n * 어느 채널에 속하는지 몰라 조인하지 못한 핸들러 사실인지 확인한다.\n *\n * dynamic 사실은 위에서 이미 세므로 여기서 다시 세지 않는다.\n */\nfunction isUnattributedHandler(fact: BridgeFact): boolean {\n return fact.kind === 'method-handle' && fact.channel === null && !fact.dynamic;\n}\n\n/** 생성 시각 차이가 하루를 넘을 때 교차 입력 한계를 만든다. */\nfunction freshnessLimitation(\n documents: readonly BridgeFactsDocument[],\n): JoinLimitation | undefined {\n if (documents.length < 2) return undefined;\n let earliest = Number.POSITIVE_INFINITY;\n let latest = Number.NEGATIVE_INFINITY;\n for (const document of documents) {\n const timestamp = Date.parse(document.generatedAt);\n earliest = Math.min(earliest, timestamp);\n latest = Math.max(latest, timestamp);\n }\n const difference = latest - earliest;\n if (difference <= millisecondsPerDay) return undefined;\n const hours = Math.round(difference / millisecondsPerHour);\n return {\n platform: 'cross-platform',\n target: null,\n tool: 'isthmus',\n origin: 'consumer',\n message: `input-freshness: bridge documents differ by ${hours} hours`,\n };\n}\n\n/** limitation을 플랫폼·target·도구·문장 순으로 고정한다. */\nfunction compareLimitations(left: JoinLimitation, right: JoinLimitation): number {\n return (\n compareStrings(left.platform, right.platform) ||\n compareTargets(left.target, right.target) ||\n compareStrings(left.tool, right.tool) ||\n compareStrings(left.message, right.message) ||\n compareOptionalStrings(left.origin, right.origin) ||\n compareStrings(JSON.stringify(left.channels ?? null), JSON.stringify(right.channels ?? null))\n );\n}\n\n/** target을 문자열 순으로 고정하고 귀속이 없는(null) 한계를 뒤에 둔다. */\nfunction compareTargets(\n left: BridgeTarget | null,\n right: BridgeTarget | null,\n): number {\n if (left === right) return 0;\n if (left === null) return 1;\n if (right === null) return -1;\n return compareStrings(left, right);\n}\n\n/** 메서드 키별로 호출과 핸들러 증거를 모은다. */\nfunction collectMethodGroups(\n documents: readonly BridgeFactsDocument[],\n): Map<string, MutableMethodGroup> {\n const groups = new Map<string, MutableMethodGroup>();\n for (const document of documents) collectDocumentMethods(document, groups);\n for (const group of groups.values()) {\n sortUniqueEndpoints(group.invocations);\n sortUniqueEndpoints(group.handlers);\n }\n return groups;\n}\n\n/** 증거 위치와 심볼을 정렬하고 같은 증거를 한 번만 남긴다. */\nfunction sortUniqueEndpoints(endpoints: BridgeEndpoint[]): void {\n endpoints.sort(compareEndpoints);\n if (endpoints.length < 2) return;\n let writeIndex = 1;\n for (let readIndex = 1; readIndex < endpoints.length; readIndex++) {\n const previous = endpoints[writeIndex - 1];\n const current = endpoints[readIndex];\n if (\n previous !== undefined &&\n current !== undefined &&\n compareEndpoints(previous, current) !== 0\n ) {\n endpoints[writeIndex] = current;\n writeIndex++;\n }\n }\n endpoints.length = writeIndex;\n}\n\n/** 증거 위치와 선택 심볼을 완전한 결정 순서로 비교한다. */\nfunction compareEndpoints(left: BridgeEndpoint, right: BridgeEndpoint): number {\n const locationOrder =\n compareStrings(left.platform, right.platform) ||\n compareStrings(left.location.path, right.location.path) ||\n left.location.line - right.location.line ||\n left.location.column - right.location.column;\n if (locationOrder !== 0) return locationOrder;\n const languageOrder = compareOptionalStrings(left.sourceLanguage, right.sourceLanguage);\n if (languageOrder !== 0) return languageOrder;\n if (left.symbol === undefined) return right.symbol === undefined ? 0 : 1;\n if (right.symbol === undefined) return -1;\n return (\n compareStrings(left.symbol.qualifiedName, right.symbol.qualifiedName) ||\n compareOptionalStrings(left.symbol.usr, right.symbol.usr)\n );\n}\n\n/** 존재하는 선택 문자열을 없는 값보다 먼저 두고 비교한다. */\nfunction compareOptionalStrings(\n left: string | undefined,\n right: string | undefined,\n): number {\n if (left === undefined) return right === undefined ? 0 : 1;\n if (right === undefined) return -1;\n return compareStrings(left, right);\n}\n\n/** 문서 하나의 정적 메서드 사실을 그룹에 추가한다. */\nfunction collectDocumentMethods(\n document: BridgeFactsDocument,\n groups: Map<string, MutableMethodGroup>,\n): void {\n if (document.target === null) return;\n for (const fact of document.facts) {\n if (!isStaticMethodFact(fact)) continue;\n const key = `${document.target}\\u0000${fact.channel}\\u0000${fact.method}`;\n const group = groups.get(key) ?? createMethodGroup(document.target, fact.channel, fact.method);\n const endpoints = fact.kind === 'method-invoke' ? group.invocations : group.handlers;\n endpoints.push(toEndpoint(document.platform, fact));\n groups.set(key, group);\n }\n}\n\n/** 조인 가능한 정적 메서드 호출·핸들러 사실인지 확인한다. */\nfunction isStaticMethodFact(\n fact: BridgeFactsDocument['facts'][number],\n): fact is BridgeFactsDocument['facts'][number] & {\n channel: string;\n method: string;\n} {\n return (\n (fact.kind === 'method-invoke' || fact.kind === 'method-handle') &&\n !fact.dynamic &&\n fact.channel !== null &&\n fact.method !== undefined\n );\n}\n\n/** 빈 메서드 그룹을 만든다. */\nfunction createMethodGroup(\n target: BridgeTarget,\n channel: string,\n method: string,\n): MutableMethodGroup {\n return { target, channel, method, invocations: [], handlers: [] };\n}\n\n/** 채널 키별로 생성과 등록 증거를 모은다. */\nfunction collectChannelGroups(\n documents: readonly BridgeFactsDocument[],\n): Map<string, MutableChannelGroup> {\n const groups = new Map<string, MutableChannelGroup>();\n for (const document of documents) collectDocumentChannels(document, groups);\n for (const group of groups.values()) {\n sortUniqueEndpoints(group.creations);\n sortUniqueEndpoints(group.registrations);\n }\n return groups;\n}\n\n/** 문서 하나의 정적 채널 사실을 그룹에 추가한다. */\nfunction collectDocumentChannels(\n document: BridgeFactsDocument,\n groups: Map<string, MutableChannelGroup>,\n): void {\n if (document.target === null) return;\n for (const fact of document.facts) {\n if (!isStaticChannelFact(fact)) continue;\n const key = `${document.target}\\u0000${fact.channel}`;\n const group = groups.get(key) ?? createChannelGroup(document.target, fact.channel);\n const endpoints = fact.kind === 'channel-create' ? group.creations : group.registrations;\n endpoints.push(toEndpoint(document.platform, fact));\n groups.set(key, group);\n }\n}\n\n/** 조인 가능한 정적 채널 생성·등록 사실인지 확인한다. */\nfunction isStaticChannelFact(\n fact: BridgeFactsDocument['facts'][number],\n): fact is BridgeFactsDocument['facts'][number] & { channel: string } {\n return (\n (fact.kind === 'channel-create' || fact.kind === 'channel-register') &&\n !fact.dynamic &&\n fact.channel !== null\n );\n}\n\n/** 빈 채널 그룹을 만든다. */\nfunction createChannelGroup(\n target: BridgeTarget,\n channel: string,\n): MutableChannelGroup {\n return { target, channel, creations: [], registrations: [] };\n}\n\n/** 사실을 플랫폼이 포함된 증거 위치로 바꾼다. */\nfunction toEndpoint(\n platform: BridgePlatform,\n fact: BridgeFactsDocument['facts'][number],\n): BridgeEndpoint {\n return {\n platform, location: fact.location,\n ...(fact.symbol === undefined ? {} : { symbol: fact.symbol }),\n ...(fact.sourceLanguage === undefined ? {} : { sourceLanguage: fact.sourceLanguage }),\n };\n}\n\n/** 채널 결과를 target과 이름 순으로 고정한다. */\nfunction compareChannels(left: ChannelKey, right: ChannelKey): number {\n return (\n compareStrings(left.target, right.target) ||\n compareStrings(left.channel, right.channel)\n );\n}\n\n/** 결정적 정렬에 필요한 논리 채널 키다. */\ntype ChannelKey = Pick<MatchedChannel, 'target' | 'channel'>;\n\n/** 메서드 결과를 target·채널·메서드 순으로 고정한다. */\nfunction compareMethodKeys(left: MethodKey, right: MethodKey): number {\n return (\n compareStrings(left.target, right.target) ||\n compareStrings(left.channel, right.channel) ||\n compareStrings(left.method, right.method)\n );\n}\n\n/** 결정적 정렬에 필요한 논리 메서드 키다. */\ntype MethodKey = Pick<MatchedMethod, 'target' | 'channel' | 'method'>;\n\n/** 조립 중인 채널 증거 그룹이다. */\ninterface MutableChannelGroup extends MatchedChannel {\n readonly creations: BridgeEndpoint[];\n readonly registrations: BridgeEndpoint[];\n}\n\n/** 조립 중인 메서드 증거 그룹이다. */\ninterface MutableMethodGroup extends MatchedMethod {\n readonly invocations: BridgeEndpoint[];\n readonly handlers: BridgeEndpoint[];\n}\n\nconst millisecondsPerHour = 60 * 60 * 1_000;\nconst millisecondsPerDay = 24 * millisecondsPerHour;\n"]}
|
|
1
|
+
{"version":3,"file":"join.js","sourceRoot":"","sources":["../../src/join/join.ts"],"names":[],"mappings":"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","sourcesContent":["import type {\n BridgeFact,\n BridgeFactsDocument,\n BridgeLocation,\n BridgePlatform,\n BridgeSymbol,\n BridgeSourceLanguage,\n BridgeTarget,\n} from '../exchange/parse.ts';\nimport { compareStrings } from '../compare.ts';\nimport { isCallerPlatform, isReceiverPlatform } from '../exchange/parse.ts';\n\n/** 한 언어 문서가 제공한 브리지 증거 위치다. */\nexport interface BridgeEndpoint {\n readonly platform: BridgePlatform;\n readonly location: BridgeLocation;\n readonly symbol?: BridgeSymbol;\n readonly sourceLanguage?: BridgeSourceLanguage;\n}\n\n/** 논리 채널 하나에 모인 양쪽 생성·등록 증거다. */\nexport interface MatchedChannel {\n readonly target: BridgeTarget;\n readonly channel: string;\n readonly creations: readonly BridgeEndpoint[];\n readonly registrations: readonly BridgeEndpoint[];\n}\n\n/** 등록을 찾지 못한 논리 채널과 모든 생성 증거다. */\nexport interface UnregisteredChannelCreation {\n readonly target: BridgeTarget;\n readonly channel: string;\n readonly creations: readonly BridgeEndpoint[];\n}\n\n/** 생성을 찾지 못한 논리 채널과 모든 등록 증거다. */\nexport interface RegistrationWithoutCreation {\n readonly target: BridgeTarget;\n readonly channel: string;\n readonly registrations: readonly BridgeEndpoint[];\n}\n\n/** 논리 메서드 하나에 모인 양쪽 호출·핸들러 증거다. */\nexport interface MatchedMethod {\n readonly target: BridgeTarget;\n readonly channel: string;\n readonly method: string;\n readonly invocations: readonly BridgeEndpoint[];\n readonly handlers: readonly BridgeEndpoint[];\n}\n\n/** 핸들러를 찾지 못한 논리 호출과 모든 호출 증거다. */\nexport interface UnhandledInvocation {\n readonly target: BridgeTarget;\n readonly channel: string;\n readonly method: string;\n readonly invocations: readonly BridgeEndpoint[];\n}\n\n/** 호출자를 찾지 못한 논리 핸들러와 모든 네이티브 증거다. */\nexport interface HandlerWithoutInvocation {\n readonly target: BridgeTarget;\n readonly channel: string;\n readonly method: string;\n readonly handlers: readonly BridgeEndpoint[];\n}\n\n/**\n * 생산 문서가 밝힌 분석 한계와 출처다.\n *\n * `target`은 이 한계를 신고한 문서의 브리지 메커니즘이다. 사실은 target별로만\n * 조인되므로, 보고서는 이 값으로 한계를 해당 target의 진단에만 귀속시킨다.\n * 사실이 없는 문서의 한계, 선언한 target을 신뢰할 수 없는 mixed-targets 문서의\n * 한계, 교차 입력 한계는 어느 target이 가려졌는지 특정할 수 없어 `null`이다.\n */\nexport interface JoinLimitation {\n readonly platform: BridgePlatform | 'cross-platform';\n readonly target: BridgeTarget | null;\n readonly tool: string;\n readonly message: string;\n readonly channels?: readonly string[];\n /** 소비자가 직접 센 한계에만 부여하며 생산 문서에서는 복사하지 않는다. */\n readonly origin?: 'consumer';\n}\n\n/** 검증된 교환 문서들의 논리 조인 결과다. */\nexport interface BridgeJoinResult {\n readonly deferred: boolean;\n /** 입력 문서 전체가 관찰한 fact 수다. 조인 여부와 무관한 관찰량이다. */\n readonly observedFacts: number;\n readonly matchedChannels: readonly MatchedChannel[];\n readonly unregisteredChannelCreations: readonly UnregisteredChannelCreation[];\n readonly registrationsWithoutCreations: readonly RegistrationWithoutCreation[];\n readonly matchedMethods: readonly MatchedMethod[];\n readonly unhandledInvocations: readonly UnhandledInvocation[];\n readonly handlersWithoutInvocations: readonly HandlerWithoutInvocation[];\n readonly limitations: readonly JoinLimitation[];\n}\n\n/** 한 번의 조인에서 허용하는 최대 생산 문서 수다. */\nexport const MAX_DOCUMENTS_PER_JOIN = 256;\n\n/** 함께 조인할 입력 문서 집합이 논리 계약을 위반했음을 나타낸다. */\nexport class BridgeJoinValidationError extends Error {\n /** 입력 경로를 노출하지 않는 안전한 메시지를 보존한다. */\n constructor(message: string) {\n super(message);\n this.name = 'BridgeJoinValidationError';\n }\n}\n\n/** 위치가 아니라 문자열 키로 검증된 교환 문서를 조인한다. */\nexport function joinBridgeDocuments(\n documents: readonly BridgeFactsDocument[],\n): BridgeJoinResult {\n if (documents.length > MAX_DOCUMENTS_PER_JOIN) {\n throw new BridgeJoinValidationError(\n `Bridge join exceeds the ${MAX_DOCUMENTS_PER_JOIN} document limit.`,\n );\n }\n validateProjects(documents);\n validatePlatformComposition(documents);\n const limitations = collectLimitations(documents);\n const observedFacts = documents.reduce(\n (total, document) => total + document.facts.length,\n 0,\n );\n if (documents.some(hasMixedTargets)) {\n return emptyJoinResult(limitations, observedFacts);\n }\n const groups = collectChannelGroups(documents);\n const matchedChannels = [...groups.values()]\n .filter((group) => group.creations.length > 0 && group.registrations.length > 0)\n .sort(compareChannels);\n const unregisteredChannelCreations = [...groups.values()]\n .filter((group) => group.creations.length > 0 && group.registrations.length === 0)\n .map(({ target, channel, creations }) => ({ target, channel, creations }))\n .sort(compareChannels);\n const registrationsWithoutCreations = [...groups.values()]\n .filter((group) => group.registrations.length > 0 && group.creations.length === 0)\n .map(({ target, channel, registrations }) => ({\n target,\n channel,\n registrations,\n }))\n .sort(compareChannels);\n const methodGroups = collectMethodGroups(documents);\n const matchedMethods = [...methodGroups.values()]\n .filter((group) => group.invocations.length > 0 && group.handlers.length > 0)\n .sort(compareMethodKeys);\n const unhandledInvocations = [...methodGroups.values()]\n .filter((group) => group.invocations.length > 0 && group.handlers.length === 0)\n .map(({ target, channel, method, invocations }) => ({\n target,\n channel,\n method,\n invocations,\n }))\n .sort(compareMethodKeys);\n const handlersWithoutInvocations = [...methodGroups.values()]\n .filter((group) => group.handlers.length > 0 && group.invocations.length === 0)\n .map(({ target, channel, method, handlers }) => ({\n target,\n channel,\n method,\n handlers,\n }))\n .sort(compareMethodKeys);\n return {\n deferred: false,\n observedFacts,\n matchedChannels,\n unregisteredChannelCreations,\n registrationsWithoutCreations,\n matchedMethods,\n unhandledInvocations,\n handlersWithoutInvocations,\n limitations,\n };\n}\n\n/** 입력 한계 때문에 조인 전체가 보류된 결과인지 확인한다. */\nexport function isBridgeJoinDeferred(joined: BridgeJoinResult): boolean {\n return joined.deferred;\n}\n\n/** 한 번의 조인 입력이 정확히 하나의 project를 기술하는지 검증한다. */\nfunction validateProjects(documents: readonly BridgeFactsDocument[]): void {\n if (new Set(documents.map(({ project }) => project)).size > 1) {\n throw new BridgeJoinValidationError(\n 'Bridge documents must describe the same project; regenerate them from one project root.',\n );\n }\n}\n\n/** 호출 측·수신 측 문서가 모두 있어야 경계 사실로 조인할 수 있다. */\nfunction validatePlatformComposition(\n documents: readonly BridgeFactsDocument[],\n): void {\n const hasCaller = documents.some(({ platform }) => isCallerPlatform(platform));\n const hasReceiver = documents.some(({ platform }) =>\n isReceiverPlatform(platform),\n );\n if (!hasCaller || !hasReceiver) {\n throw new BridgeJoinValidationError(\n 'Bridge documents must include at least one caller platform (dart, js) document '\n + 'and one receiver platform (swift, kotlin) document; run a producer for the missing side.',\n );\n }\n}\n\n/** 사실별 target이 없는 혼합 문서인지 확인한다. */\nfunction hasMixedTargets(document: BridgeFactsDocument): boolean {\n // 단어 경계로 판정한다. 낱말 안에 붙은 표기(\"non-mixed-targets workspaces\",\n // \"mixed-targets-like\")는 문구 변형이 아니라 다른 낱말이라 보류의 근거가 못 된다.\n // 앞 공백·대소문자·콜론 누락 변형은 계속 보수적으로 인정한다.\n return document.limitations.some((message) =>\n mixedTargetToken.test(message),\n );\n}\n\n/** 문구 변형을 인정하는 mixed-targets 토큰 경계다. */\nconst mixedTargetToken = /(?<![\\w-])mixed-targets(?![\\w-])/i;\n\n/**\n * 한계를 귀속시킬 target을 결정한다.\n *\n * mixed-targets 문서의 선언 target은 대표값일 뿐 사실별 메커니즘을 복원할 수\n * 없으므로, 그 문서의 한계와 조인 제외 사실 계수는 귀속 없이(null) 남긴다.\n * 귀속을 잃어도 관찰 자체는 보존해야 한다.\n */\nfunction limitationTarget(document: BridgeFactsDocument): BridgeTarget | null {\n return hasMixedTargets(document) ? null : document.target;\n}\n\n/** 안전하게 조인을 보류하면서 입력 한계만 전달한다. 관찰량은 보존한다. */\nfunction emptyJoinResult(\n limitations: readonly JoinLimitation[],\n observedFacts: number,\n): BridgeJoinResult {\n return {\n deferred: true,\n observedFacts,\n matchedChannels: [],\n unregisteredChannelCreations: [],\n registrationsWithoutCreations: [],\n matchedMethods: [],\n unhandledInvocations: [],\n handlersWithoutInvocations: [],\n limitations,\n };\n}\n\n/** 입력 limitation에 생산 플랫폼과 도구 이름을 붙이고 조인하지 못한 사실을 함께 센다. */\nfunction collectLimitations(\n documents: readonly BridgeFactsDocument[],\n): JoinLimitation[] {\n const limitations: JoinLimitation[] = documents.flatMap((document) => {\n const scopes = new Map(document.limitationScopes?.map((scope) => [scope.limitationIndex, scope.channels]));\n return document.limitations.map((message, index) => {\n const channels = scopes.get(index);\n return {\n platform: document.platform,\n target: limitationTarget(document),\n tool: document.tool.name,\n message,\n ...(channels === undefined ? {} : { channels }),\n };\n });\n });\n limitations.push(...unjoinedFactLimitations(documents));\n const freshness = freshnessLimitation(documents);\n if (freshness !== undefined) limitations.push(freshness);\n return limitations.sort(compareLimitations);\n}\n\n/**\n * 조인에서 제외한 사실을 isthmus 자신의 관찰 한계로 남긴다.\n *\n * 생산자가 같은 사실을 limitation으로 신고하지 않아도, 또는 신고한 개수가 실제와\n * 달라도 관찰 공백이 보고서에서 사라지지 않아야 한다. 교환 계약은 이 사실들을\n * 세도록 요구하지만 문서의 limitation 문자열은 생산자의 자발적인 신고라\n * 소비자가 신뢰의 근거로 삼을 수 없다.\n */\nfunction unjoinedFactLimitations(\n documents: readonly BridgeFactsDocument[],\n): JoinLimitation[] {\n return [\n ...unjoinedLimitations(\n documents,\n isUnjoinedDynamicChannel,\n 'unjoined-dynamic-channels',\n 'channel facts with a non-literal name',\n ),\n ...unjoinedLimitations(\n documents,\n isUnjoinedDynamicMethod,\n 'unjoined-dynamic-methods',\n 'method facts with a non-literal name',\n ),\n ...unjoinedLimitations(\n documents,\n isUnattributedHandler,\n 'unjoined-unattributed-handlers',\n 'method handler facts without a channel',\n ),\n ];\n}\n\n/** 조건에 맞는 사실 수를 플랫폼·target별로 세어 한계 문장으로 바꾼다. */\nfunction unjoinedLimitations(\n documents: readonly BridgeFactsDocument[],\n matchesFact: (fact: BridgeFact) => boolean,\n prefix: string,\n subject: string,\n): JoinLimitation[] {\n return countFactsByPlatformTarget(documents, matchesFact).map(\n ({ platform, target, count }) => ({\n platform,\n target,\n tool: 'isthmus',\n origin: 'consumer',\n message: `${prefix}: ${count} ${subject} were not joined`,\n }),\n );\n}\n\n/**\n * 주어진 조건의 서로 다른 사실 수를 생산 플랫폼·target별로 모은다.\n *\n * 사실은 target별로만 조인되므로 다른 target의 사실을 한 한계로 합산하면\n * 관찰 공백의 귀속이 사라진다. mixed-targets 문서의 사실은 귀속 없이(null)\n * 센다. 사실이 없는 문서는 교환 계약상 target이 null이고 사실도 없으므로\n * 여기에서 자연스럽게 제외된다.\n */\nfunction countFactsByPlatformTarget(\n documents: readonly BridgeFactsDocument[],\n matchesFact: (fact: BridgeFact) => boolean,\n): Array<{\n platform: BridgePlatform;\n target: BridgeTarget | null;\n count: number;\n}> {\n const distinctFacts = new Map<\n string,\n {\n platform: BridgePlatform;\n target: BridgeTarget | null;\n keys: Set<string>;\n }\n >();\n for (const document of documents) {\n const target = limitationTarget(document);\n // BridgeTarget은 닫힌 어휘라 문자열화된 null과 충돌하지 않는다.\n const groupKey = `${document.platform}\\u0000${target}`;\n for (const fact of document.facts) {\n if (!matchesFact(fact)) continue;\n const group = distinctFacts.get(groupKey) ?? {\n platform: document.platform,\n target,\n keys: new Set<string>(),\n };\n group.keys.add(unjoinedFactKey(fact));\n distinctFacts.set(groupKey, group);\n }\n }\n return [...distinctFacts.values()].map(({ platform, target, keys }) => ({\n platform,\n target,\n count: keys.size,\n }));\n}\n\n/**\n * 같은 위치의 중복 사실을 한 번만 세는 키를 만든다.\n *\n * 위치 기준은 증거 dedup과 같지만 symbol은 비교하지 않아, 같은 위치의 서로\n * 다른 symbol은 하나로 센다. `channel`은 null일 수 있어 구분자 결합 대신\n * JSON으로 만든다. 그래야 미귀속 핸들러와 이름이 `null`인 채널의 사실이\n * 같은 키로 합쳐지지 않는다.\n */\nfunction unjoinedFactKey(fact: BridgeFact): string {\n const { path, line, column } = fact.location;\n return JSON.stringify([\n fact.kind,\n fact.channel,\n fact.method ?? null,\n path,\n line,\n column,\n ]);\n}\n\n/** 이름이 리터럴이 아니어서 조인하지 못한 채널 사실인지 확인한다. */\nfunction isUnjoinedDynamicChannel(fact: BridgeFact): boolean {\n return (\n fact.dynamic &&\n (fact.kind === 'channel-create' || fact.kind === 'channel-register')\n );\n}\n\n/** 이름이 리터럴이 아니어서 조인하지 못한 메서드 사실인지 확인한다. */\nfunction isUnjoinedDynamicMethod(fact: BridgeFact): boolean {\n return (\n fact.dynamic &&\n (fact.kind === 'method-invoke' || fact.kind === 'method-handle')\n );\n}\n\n/**\n * 어느 채널에 속하는지 몰라 조인하지 못한 핸들러 사실인지 확인한다.\n *\n * dynamic 사실은 위에서 이미 세므로 여기서 다시 세지 않는다.\n */\nfunction isUnattributedHandler(fact: BridgeFact): boolean {\n return fact.kind === 'method-handle' && fact.channel === null && !fact.dynamic;\n}\n\n/** 생성 시각 차이가 하루를 넘을 때 교차 입력 한계를 만든다. */\nfunction freshnessLimitation(\n documents: readonly BridgeFactsDocument[],\n): JoinLimitation | undefined {\n if (documents.length < 2) return undefined;\n let earliest = Number.POSITIVE_INFINITY;\n let latest = Number.NEGATIVE_INFINITY;\n for (const document of documents) {\n const timestamp = Date.parse(document.generatedAt);\n earliest = Math.min(earliest, timestamp);\n latest = Math.max(latest, timestamp);\n }\n const difference = latest - earliest;\n if (difference <= millisecondsPerDay) return undefined;\n const hours = Math.round(difference / millisecondsPerHour);\n return {\n platform: 'cross-platform',\n target: null,\n tool: 'isthmus',\n origin: 'consumer',\n message: `input-freshness: bridge documents differ by ${hours} hours`,\n };\n}\n\n/** limitation을 플랫폼·target·도구·문장 순으로 고정한다. */\nfunction compareLimitations(left: JoinLimitation, right: JoinLimitation): number {\n return (\n compareStrings(left.platform, right.platform) ||\n compareTargets(left.target, right.target) ||\n compareStrings(left.tool, right.tool) ||\n compareStrings(left.message, right.message) ||\n compareOptionalStrings(left.origin, right.origin) ||\n compareStrings(JSON.stringify(left.channels ?? null), JSON.stringify(right.channels ?? null))\n );\n}\n\n/** target을 문자열 순으로 고정하고 귀속이 없는(null) 한계를 뒤에 둔다. */\nfunction compareTargets(\n left: BridgeTarget | null,\n right: BridgeTarget | null,\n): number {\n if (left === right) return 0;\n if (left === null) return 1;\n if (right === null) return -1;\n return compareStrings(left, right);\n}\n\n/** 메서드 키별로 호출과 핸들러 증거를 모은다. */\nfunction collectMethodGroups(\n documents: readonly BridgeFactsDocument[],\n): Map<string, MutableMethodGroup> {\n const groups = new Map<string, MutableMethodGroup>();\n for (const document of documents) collectDocumentMethods(document, groups);\n for (const group of groups.values()) {\n sortUniqueEndpoints(group.invocations);\n sortUniqueEndpoints(group.handlers);\n }\n return groups;\n}\n\n/** 증거 위치와 심볼을 정렬하고 같은 증거를 한 번만 남긴다. */\nfunction sortUniqueEndpoints(endpoints: BridgeEndpoint[]): void {\n endpoints.sort(compareEndpoints);\n if (endpoints.length < 2) return;\n let writeIndex = 1;\n for (let readIndex = 1; readIndex < endpoints.length; readIndex++) {\n const previous = endpoints[writeIndex - 1];\n const current = endpoints[readIndex];\n if (\n previous !== undefined &&\n current !== undefined &&\n compareEndpoints(previous, current) !== 0\n ) {\n endpoints[writeIndex] = current;\n writeIndex++;\n }\n }\n endpoints.length = writeIndex;\n}\n\n/** 증거 위치와 선택 심볼을 완전한 결정 순서로 비교한다. */\nfunction compareEndpoints(left: BridgeEndpoint, right: BridgeEndpoint): number {\n const locationOrder =\n compareStrings(left.platform, right.platform) ||\n compareStrings(left.location.path, right.location.path) ||\n left.location.line - right.location.line ||\n left.location.column - right.location.column;\n if (locationOrder !== 0) return locationOrder;\n const languageOrder = compareOptionalStrings(left.sourceLanguage, right.sourceLanguage);\n if (languageOrder !== 0) return languageOrder;\n if (left.symbol === undefined) return right.symbol === undefined ? 0 : 1;\n if (right.symbol === undefined) return -1;\n return (\n compareStrings(left.symbol.qualifiedName, right.symbol.qualifiedName) ||\n compareOptionalStrings(left.symbol.usr, right.symbol.usr)\n );\n}\n\n/** 존재하는 선택 문자열을 없는 값보다 먼저 두고 비교한다. */\nfunction compareOptionalStrings(\n left: string | undefined,\n right: string | undefined,\n): number {\n if (left === undefined) return right === undefined ? 0 : 1;\n if (right === undefined) return -1;\n return compareStrings(left, right);\n}\n\n/** 문서 하나의 정적 메서드 사실을 그룹에 추가한다. */\nfunction collectDocumentMethods(\n document: BridgeFactsDocument,\n groups: Map<string, MutableMethodGroup>,\n): void {\n if (document.target === null) return;\n for (const fact of document.facts) {\n if (!isStaticMethodFact(fact)) continue;\n const key = `${document.target}\\u0000${fact.channel}\\u0000${fact.method}`;\n const group = groups.get(key) ?? createMethodGroup(document.target, fact.channel, fact.method);\n const endpoints = fact.kind === 'method-invoke' ? group.invocations : group.handlers;\n endpoints.push(toEndpoint(document.platform, fact));\n groups.set(key, group);\n }\n}\n\n/** 조인 가능한 정적 메서드 호출·핸들러 사실인지 확인한다. */\nfunction isStaticMethodFact(\n fact: BridgeFactsDocument['facts'][number],\n): fact is BridgeFactsDocument['facts'][number] & {\n channel: string;\n method: string;\n} {\n return (\n (fact.kind === 'method-invoke' || fact.kind === 'method-handle') &&\n !fact.dynamic &&\n fact.channel !== null &&\n fact.method !== undefined\n );\n}\n\n/** 빈 메서드 그룹을 만든다. */\nfunction createMethodGroup(\n target: BridgeTarget,\n channel: string,\n method: string,\n): MutableMethodGroup {\n return { target, channel, method, invocations: [], handlers: [] };\n}\n\n/** 채널 키별로 생성과 등록 증거를 모은다. */\nfunction collectChannelGroups(\n documents: readonly BridgeFactsDocument[],\n): Map<string, MutableChannelGroup> {\n const groups = new Map<string, MutableChannelGroup>();\n for (const document of documents) collectDocumentChannels(document, groups);\n for (const group of groups.values()) {\n sortUniqueEndpoints(group.creations);\n sortUniqueEndpoints(group.registrations);\n }\n return groups;\n}\n\n/** 문서 하나의 정적 채널 사실을 그룹에 추가한다. */\nfunction collectDocumentChannels(\n document: BridgeFactsDocument,\n groups: Map<string, MutableChannelGroup>,\n): void {\n if (document.target === null) return;\n for (const fact of document.facts) {\n if (!isStaticChannelFact(fact)) continue;\n const key = `${document.target}\\u0000${fact.channel}`;\n const group = groups.get(key) ?? createChannelGroup(document.target, fact.channel);\n const endpoints = fact.kind === 'channel-create' ? group.creations : group.registrations;\n endpoints.push(toEndpoint(document.platform, fact));\n groups.set(key, group);\n }\n}\n\n/** 조인 가능한 정적 채널 생성·등록 사실인지 확인한다. */\nfunction isStaticChannelFact(\n fact: BridgeFactsDocument['facts'][number],\n): fact is BridgeFactsDocument['facts'][number] & { channel: string } {\n return (\n (fact.kind === 'channel-create' || fact.kind === 'channel-register') &&\n !fact.dynamic &&\n fact.channel !== null\n );\n}\n\n/** 빈 채널 그룹을 만든다. */\nfunction createChannelGroup(\n target: BridgeTarget,\n channel: string,\n): MutableChannelGroup {\n return { target, channel, creations: [], registrations: [] };\n}\n\n/** 사실을 플랫폼이 포함된 증거 위치로 바꾼다. */\nfunction toEndpoint(\n platform: BridgePlatform,\n fact: BridgeFactsDocument['facts'][number],\n): BridgeEndpoint {\n return {\n platform, location: fact.location,\n ...(fact.symbol === undefined ? {} : { symbol: fact.symbol }),\n ...(fact.sourceLanguage === undefined ? {} : { sourceLanguage: fact.sourceLanguage }),\n };\n}\n\n/** 채널 결과를 target과 이름 순으로 고정한다. */\nfunction compareChannels(left: ChannelKey, right: ChannelKey): number {\n return (\n compareStrings(left.target, right.target) ||\n compareStrings(left.channel, right.channel)\n );\n}\n\n/** 결정적 정렬에 필요한 논리 채널 키다. */\ntype ChannelKey = Pick<MatchedChannel, 'target' | 'channel'>;\n\n/** 메서드 결과를 target·채널·메서드 순으로 고정한다. */\nfunction compareMethodKeys(left: MethodKey, right: MethodKey): number {\n return (\n compareStrings(left.target, right.target) ||\n compareStrings(left.channel, right.channel) ||\n compareStrings(left.method, right.method)\n );\n}\n\n/** 결정적 정렬에 필요한 논리 메서드 키다. */\ntype MethodKey = Pick<MatchedMethod, 'target' | 'channel' | 'method'>;\n\n/** 조립 중인 채널 증거 그룹이다. */\ninterface MutableChannelGroup extends MatchedChannel {\n readonly creations: BridgeEndpoint[];\n readonly registrations: BridgeEndpoint[];\n}\n\n/** 조립 중인 메서드 증거 그룹이다. */\ninterface MutableMethodGroup extends MatchedMethod {\n readonly invocations: BridgeEndpoint[];\n readonly handlers: BridgeEndpoint[];\n}\n\nconst millisecondsPerHour = 60 * 60 * 1_000;\nconst millisecondsPerDay = 24 * millisecondsPerHour;\n"]}
|
|
@@ -44,6 +44,13 @@ export interface CartographRetentionsDocument {
|
|
|
44
44
|
}
|
|
45
45
|
/** 근거 하나가 실을 수 있는 호출 위치 상한이다. */
|
|
46
46
|
export declare const MAX_RETENTION_CALLERS = 100;
|
|
47
|
+
/**
|
|
48
|
+
* 문서 전체가 실을 수 있는 호출 위치 총상한이다.
|
|
49
|
+
*
|
|
50
|
+
* 호출자 증거는 (심볼 × 채널 × 메서드)마다 다시 실리므로 건당 상한만으로는 출력이
|
|
51
|
+
* 입력보다 커질 수 있다. 베이스라인의 항목 상한과 같은 자원 거버넌스다.
|
|
52
|
+
*/
|
|
53
|
+
export declare const MAX_RETENTION_CALLER_ENTRIES = 1000000;
|
|
47
54
|
/** 불완전한 조인으로 보존 결정을 만들 수 없음을 나타낸다. */
|
|
48
55
|
export declare class RetentionValidationError extends Error {
|
|
49
56
|
constructor(message: string);
|
|
@@ -2,6 +2,13 @@ import { isBridgeJoinDeferred, } from "../join/join.js";
|
|
|
2
2
|
import { encodeSortedJson } from "./sorted-json.js";
|
|
3
3
|
/** 근거 하나가 실을 수 있는 호출 위치 상한이다. */
|
|
4
4
|
export const MAX_RETENTION_CALLERS = 100;
|
|
5
|
+
/**
|
|
6
|
+
* 문서 전체가 실을 수 있는 호출 위치 총상한이다.
|
|
7
|
+
*
|
|
8
|
+
* 호출자 증거는 (심볼 × 채널 × 메서드)마다 다시 실리므로 건당 상한만으로는 출력이
|
|
9
|
+
* 입력보다 커질 수 있다. 베이스라인의 항목 상한과 같은 자원 거버넌스다.
|
|
10
|
+
*/
|
|
11
|
+
export const MAX_RETENTION_CALLER_ENTRIES = 1_000_000;
|
|
5
12
|
/** 불완전한 조인으로 보존 결정을 만들 수 없음을 나타낸다. */
|
|
6
13
|
export class RetentionValidationError extends Error {
|
|
7
14
|
constructor(message) {
|
|
@@ -83,11 +90,16 @@ function rejectUnresolvedSwiftHandlers(joined) {
|
|
|
83
90
|
function collectCartographRetentions(joined) {
|
|
84
91
|
const retentions = [];
|
|
85
92
|
const seen = new Set();
|
|
93
|
+
let callerEntries = 0;
|
|
86
94
|
for (const method of joined.matchedMethods) {
|
|
87
95
|
if (method.invocations.length === 0)
|
|
88
96
|
continue;
|
|
89
|
-
// 결정적 순서(플랫폼·경로·줄·열)의 첫 호출이 대표 증거다.
|
|
90
|
-
|
|
97
|
+
// 결정적 순서(플랫폼·경로·줄·열)의 첫 호출이 대표 증거다. 상한 밖 호출까지
|
|
98
|
+
// 객체로 만들지 않도록 먼저 자른다.
|
|
99
|
+
const callers = method.invocations
|
|
100
|
+
.slice(0, MAX_RETENTION_CALLERS)
|
|
101
|
+
.map(toRetentionCaller);
|
|
102
|
+
const callersOmitted = method.invocations.length - callers.length;
|
|
91
103
|
const representative = callers[0];
|
|
92
104
|
if (representative === undefined)
|
|
93
105
|
continue;
|
|
@@ -101,8 +113,11 @@ function collectCartographRetentions(joined) {
|
|
|
101
113
|
if (seen.has(retentionKey))
|
|
102
114
|
continue;
|
|
103
115
|
seen.add(retentionKey);
|
|
104
|
-
|
|
105
|
-
|
|
116
|
+
callerEntries += callers.length;
|
|
117
|
+
if (callerEntries > MAX_RETENTION_CALLER_ENTRIES) {
|
|
118
|
+
throw new RetentionValidationError(`Cannot produce retention evidence with more than `
|
|
119
|
+
+ `${MAX_RETENTION_CALLER_ENTRIES} caller entries; narrow the join inputs.`);
|
|
120
|
+
}
|
|
106
121
|
retentions.push({
|
|
107
122
|
symbol: handler.symbol,
|
|
108
123
|
reason: 'bridge',
|
|
@@ -110,7 +125,7 @@ function collectCartographRetentions(joined) {
|
|
|
110
125
|
channel: method.channel,
|
|
111
126
|
method: method.method,
|
|
112
127
|
caller: representative,
|
|
113
|
-
...(
|
|
128
|
+
...(callers.length > 1 ? { callers } : {}),
|
|
114
129
|
...(callersOmitted > 0 ? { callersOmitted } : {}),
|
|
115
130
|
},
|
|
116
131
|
});
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"retentions.js","sourceRoot":"","sources":["../../src/report/retentions.ts"],"names":[],"mappings":"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","sourcesContent":["import type {\n BridgeFactsDocument,\n BridgePlatform,\n BridgeSymbol,\n} from '../exchange/parse.ts';\nimport {\n isBridgeJoinDeferred,\n type BridgeJoinResult,\n} from '../join/join.ts';\nimport { encodeSortedJson } from './sorted-json.ts';\n\n/** cartograph가 보존할 Swift 선언 식별자다. */\nexport interface RetentionSymbol extends BridgeSymbol {\n readonly usr?: string;\n}\n\n/** 언어 경계 너머 호출자의 증거 위치다. */\nexport interface RetentionCaller {\n readonly platform: BridgePlatform;\n readonly path: string;\n readonly line: number;\n}\n\n/** 보존 판단을 설명할 채널·메서드·호출자 근거다. */\nexport interface RetentionEvidence {\n readonly channel: string;\n readonly method: string;\n /** 대표 호출 위치다. 결정적 순서의 첫 호출이며 옛 소비자가 읽는 필드다. */\n readonly caller: RetentionCaller;\n /**\n * 이 보존의 전체 호출 위치(대표 포함)다. 결정적 순서를 유지하고 호출이 둘 이상일\n * 때만 실는다. 옛 소비자는 이 필드를 모르고 대표 `caller`만 읽는다.\n */\n readonly callers?: readonly RetentionCaller[];\n /** 상한 때문에 `callers`에 실지 못한 호출 수다. 0이면 실지 않는다. */\n readonly callersOmitted?: number;\n}\n\n/** cartograph 외부 보존 근거 하나다. */\nexport interface ExternalRetention {\n readonly symbol: RetentionSymbol;\n readonly reason: 'bridge';\n readonly evidence: RetentionEvidence;\n}\n\n/** cartograph가 읽는 external-retentions 버전 0 문서다. */\nexport interface CartographRetentionsDocument {\n readonly format: 'external-retentions';\n readonly version: 0;\n readonly producedBy: Readonly<{ name: 'isthmus'; version: string }>;\n readonly generatedAt: string;\n readonly retentions: readonly ExternalRetention[];\n readonly omittedObjectiveCHandlers?: number;\n}\n\n/** 근거 하나가 실을 수 있는 호출 위치 상한이다. */\nexport const MAX_RETENTION_CALLERS = 100;\n\n/** 불완전한 조인으로 보존 결정을 만들 수 없음을 나타낸다. */\nexport class RetentionValidationError extends Error {\n constructor(message: string) {\n super(message);\n this.name = 'RetentionValidationError';\n }\n}\n\n/**\n * cartograph가 소비할 수 있는 수신 측 문서가 입력에 있는지 검증한다.\n *\n * cartograph는 Swift 심볼만 보존한다. Swift 문서가 없는 입력은 조인 자체는\n * 성공하므로, 검증하지 않으면 보존할 근거가 없다는 사실이 빈 목록과 코드 0으로\n * 사라진다. 사실이 없는 Swift 문서도 그 플랫폼을 분석했다는 근거로 인정한다.\n */\nexport function validateCartographRetentionInputs(\n documents: readonly BridgeFactsDocument[],\n): void {\n if (documents.some(({ platform }) => platform === 'swift')) return;\n throw new RetentionValidationError(\n 'Retentions for cartograph require at least one swift bridge facts document; '\n + 'run a swift producer for the receiver side.',\n );\n}\n\n/** cartograph 보존 문서를 결정적인 JSON으로 인코딩한다. */\nexport function encodeCartographRetentionsDocument(\n document: CartographRetentionsDocument,\n): string {\n return encodeSortedJson(document);\n}\n\n/** 매치된 브리지 메서드를 cartograph 보존 근거로 바꾼다. */\nexport function createCartographRetentionsDocument(\n joined: BridgeJoinResult,\n generatedAt: string,\n producerVersion: string,\n): CartographRetentionsDocument {\n if (isBridgeJoinDeferred(joined)) {\n throw new RetentionValidationError(\n 'Cannot create retentions from a deferred bridge join.',\n );\n }\n rejectUnresolvedSwiftHandlers(joined);\n const omittedObjectiveCHandlers = countObjectiveCHandlers(joined);\n return {\n format: 'external-retentions',\n version: 0,\n producedBy: { name: 'isthmus', version: producerVersion },\n generatedAt,\n retentions: collectCartographRetentions(joined),\n ...(omittedObjectiveCHandlers === 0 ? {} : { omittedObjectiveCHandlers }),\n };\n}\n\n/** 그래프 밖의 매치도 사라지지 않게 채널·메서드·위치별로 센다. */\nfunction countObjectiveCHandlers(joined: BridgeJoinResult): number {\n const keys = new Set<string>();\n for (const method of joined.matchedMethods) {\n for (const handler of method.handlers) {\n if (handler.sourceLanguage !== 'objective-c') continue;\n keys.add(JSON.stringify([method.target, method.channel, method.method,\n handler.location.path, handler.location.line, handler.location.column]));\n }\n }\n return keys.size;\n}\n\n/**\n * 심볼이 없어 보존 근거로 바꿀 수 없는 매치 Swift 핸들러를 거부한다.\n * sourceLanguage로 확인된 Objective-C 구현은 Swift 그래프의 보존 대상이 아니다.\n *\n * 교환 계약에서 `symbol`은 선택 필드다. 호출자가 있는데도 근거를 만들지 못한\n * 핸들러를 조용히 빼면 cartograph는 그 핸들러를 계속 미사용으로 보고하고,\n * 소비자는 살아 있는 코드를 지운다. 부분 보존 문서 대신 실패를 돌려준다.\n */\nfunction rejectUnresolvedSwiftHandlers(joined: BridgeJoinResult): void {\n const unresolved = new Set<string>();\n for (const method of joined.matchedMethods) {\n for (const handler of method.handlers) {\n if (handler.platform !== 'swift' || handler.sourceLanguage === 'objective-c' || handler.symbol !== undefined) continue;\n const { path, line, column } = handler.location;\n unresolved.add(`${path}\\u0000${line}\\u0000${column}`);\n }\n }\n if (unresolved.size === 0) return;\n throw new RetentionValidationError(\n `Cannot produce retention evidence for ${unresolved.size} matched swift `\n + 'handlers without a symbol; regenerate the swift document with a producer '\n + 'that attaches handler symbols.',\n );\n}\n\n/** 매치별 Dart 호출자와 Swift 심볼을 cartograph 근거로 결합한다. */\nfunction collectCartographRetentions(\n joined: BridgeJoinResult,\n): ExternalRetention[] {\n const retentions: ExternalRetention[] = [];\n const seen = new Set<string>();\n for (const method of joined.matchedMethods) {\n if (method.invocations.length === 0) continue;\n // 결정적 순서(플랫폼·경로·줄·열)의 첫 호출이 대표 증거다.\n const callers = method.invocations.map(toRetentionCaller);\n const representative = callers[0];\n if (representative === undefined) continue;\n for (const handler of method.handlers) {\n if (handler.platform !== 'swift' || handler.sourceLanguage === 'objective-c' || handler.symbol === undefined) continue;\n const symbolKey = handler.symbol.usr === undefined\n ? `name:${handler.symbol.qualifiedName}`\n : `usr:${handler.symbol.usr}`;\n const retentionKey = `${symbolKey}\\u0000${method.channel}\\u0000${method.method}`;\n if (seen.has(retentionKey)) continue;\n seen.add(retentionKey);\n const capped = callers.slice(0, MAX_RETENTION_CALLERS);\n const callersOmitted = callers.length - capped.length;\n retentions.push({\n symbol: handler.symbol,\n reason: 'bridge',\n evidence: {\n channel: method.channel,\n method: method.method,\n caller: representative,\n ...(capped.length > 1 ? { callers: capped } : {}),\n ...(callersOmitted > 0 ? { callersOmitted } : {}),\n },\n });\n }\n }\n return retentions;\n}\n\n/** 증거 끝점을 external-retentions의 호출자 형태로 바꾼다. */\nfunction toRetentionCaller(endpoint: {\n readonly platform: BridgePlatform;\n readonly location: { readonly path: string; readonly line: number };\n}): RetentionCaller {\n return {\n platform: endpoint.platform,\n path: endpoint.location.path,\n line: endpoint.location.line,\n };\n}\n"]}
|
|
1
|
+
{"version":3,"file":"retentions.js","sourceRoot":"","sources":["../../src/report/retentions.ts"],"names":[],"mappings":"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","sourcesContent":["import type {\n BridgeFactsDocument,\n BridgePlatform,\n BridgeSymbol,\n} from '../exchange/parse.ts';\nimport {\n isBridgeJoinDeferred,\n type BridgeJoinResult,\n} from '../join/join.ts';\nimport { encodeSortedJson } from './sorted-json.ts';\n\n/** cartograph가 보존할 Swift 선언 식별자다. */\nexport interface RetentionSymbol extends BridgeSymbol {\n readonly usr?: string;\n}\n\n/** 언어 경계 너머 호출자의 증거 위치다. */\nexport interface RetentionCaller {\n readonly platform: BridgePlatform;\n readonly path: string;\n readonly line: number;\n}\n\n/** 보존 판단을 설명할 채널·메서드·호출자 근거다. */\nexport interface RetentionEvidence {\n readonly channel: string;\n readonly method: string;\n /** 대표 호출 위치다. 결정적 순서의 첫 호출이며 옛 소비자가 읽는 필드다. */\n readonly caller: RetentionCaller;\n /**\n * 이 보존의 전체 호출 위치(대표 포함)다. 결정적 순서를 유지하고 호출이 둘 이상일\n * 때만 실는다. 옛 소비자는 이 필드를 모르고 대표 `caller`만 읽는다.\n */\n readonly callers?: readonly RetentionCaller[];\n /** 상한 때문에 `callers`에 실지 못한 호출 수다. 0이면 실지 않는다. */\n readonly callersOmitted?: number;\n}\n\n/** cartograph 외부 보존 근거 하나다. */\nexport interface ExternalRetention {\n readonly symbol: RetentionSymbol;\n readonly reason: 'bridge';\n readonly evidence: RetentionEvidence;\n}\n\n/** cartograph가 읽는 external-retentions 버전 0 문서다. */\nexport interface CartographRetentionsDocument {\n readonly format: 'external-retentions';\n readonly version: 0;\n readonly producedBy: Readonly<{ name: 'isthmus'; version: string }>;\n readonly generatedAt: string;\n readonly retentions: readonly ExternalRetention[];\n readonly omittedObjectiveCHandlers?: number;\n}\n\n/** 근거 하나가 실을 수 있는 호출 위치 상한이다. */\nexport const MAX_RETENTION_CALLERS = 100;\n\n/**\n * 문서 전체가 실을 수 있는 호출 위치 총상한이다.\n *\n * 호출자 증거는 (심볼 × 채널 × 메서드)마다 다시 실리므로 건당 상한만으로는 출력이\n * 입력보다 커질 수 있다. 베이스라인의 항목 상한과 같은 자원 거버넌스다.\n */\nexport const MAX_RETENTION_CALLER_ENTRIES = 1_000_000;\n\n/** 불완전한 조인으로 보존 결정을 만들 수 없음을 나타낸다. */\nexport class RetentionValidationError extends Error {\n constructor(message: string) {\n super(message);\n this.name = 'RetentionValidationError';\n }\n}\n\n/**\n * cartograph가 소비할 수 있는 수신 측 문서가 입력에 있는지 검증한다.\n *\n * cartograph는 Swift 심볼만 보존한다. Swift 문서가 없는 입력은 조인 자체는\n * 성공하므로, 검증하지 않으면 보존할 근거가 없다는 사실이 빈 목록과 코드 0으로\n * 사라진다. 사실이 없는 Swift 문서도 그 플랫폼을 분석했다는 근거로 인정한다.\n */\nexport function validateCartographRetentionInputs(\n documents: readonly BridgeFactsDocument[],\n): void {\n if (documents.some(({ platform }) => platform === 'swift')) return;\n throw new RetentionValidationError(\n 'Retentions for cartograph require at least one swift bridge facts document; '\n + 'run a swift producer for the receiver side.',\n );\n}\n\n/** cartograph 보존 문서를 결정적인 JSON으로 인코딩한다. */\nexport function encodeCartographRetentionsDocument(\n document: CartographRetentionsDocument,\n): string {\n return encodeSortedJson(document);\n}\n\n/** 매치된 브리지 메서드를 cartograph 보존 근거로 바꾼다. */\nexport function createCartographRetentionsDocument(\n joined: BridgeJoinResult,\n generatedAt: string,\n producerVersion: string,\n): CartographRetentionsDocument {\n if (isBridgeJoinDeferred(joined)) {\n throw new RetentionValidationError(\n 'Cannot create retentions from a deferred bridge join.',\n );\n }\n rejectUnresolvedSwiftHandlers(joined);\n const omittedObjectiveCHandlers = countObjectiveCHandlers(joined);\n return {\n format: 'external-retentions',\n version: 0,\n producedBy: { name: 'isthmus', version: producerVersion },\n generatedAt,\n retentions: collectCartographRetentions(joined),\n ...(omittedObjectiveCHandlers === 0 ? {} : { omittedObjectiveCHandlers }),\n };\n}\n\n/** 그래프 밖의 매치도 사라지지 않게 채널·메서드·위치별로 센다. */\nfunction countObjectiveCHandlers(joined: BridgeJoinResult): number {\n const keys = new Set<string>();\n for (const method of joined.matchedMethods) {\n for (const handler of method.handlers) {\n if (handler.sourceLanguage !== 'objective-c') continue;\n keys.add(JSON.stringify([method.target, method.channel, method.method,\n handler.location.path, handler.location.line, handler.location.column]));\n }\n }\n return keys.size;\n}\n\n/**\n * 심볼이 없어 보존 근거로 바꿀 수 없는 매치 Swift 핸들러를 거부한다.\n * sourceLanguage로 확인된 Objective-C 구현은 Swift 그래프의 보존 대상이 아니다.\n *\n * 교환 계약에서 `symbol`은 선택 필드다. 호출자가 있는데도 근거를 만들지 못한\n * 핸들러를 조용히 빼면 cartograph는 그 핸들러를 계속 미사용으로 보고하고,\n * 소비자는 살아 있는 코드를 지운다. 부분 보존 문서 대신 실패를 돌려준다.\n */\nfunction rejectUnresolvedSwiftHandlers(joined: BridgeJoinResult): void {\n const unresolved = new Set<string>();\n for (const method of joined.matchedMethods) {\n for (const handler of method.handlers) {\n if (handler.platform !== 'swift' || handler.sourceLanguage === 'objective-c' || handler.symbol !== undefined) continue;\n const { path, line, column } = handler.location;\n unresolved.add(`${path}\\u0000${line}\\u0000${column}`);\n }\n }\n if (unresolved.size === 0) return;\n throw new RetentionValidationError(\n `Cannot produce retention evidence for ${unresolved.size} matched swift `\n + 'handlers without a symbol; regenerate the swift document with a producer '\n + 'that attaches handler symbols.',\n );\n}\n\n/** 매치별 Dart 호출자와 Swift 심볼을 cartograph 근거로 결합한다. */\nfunction collectCartographRetentions(\n joined: BridgeJoinResult,\n): ExternalRetention[] {\n const retentions: ExternalRetention[] = [];\n const seen = new Set<string>();\n let callerEntries = 0;\n for (const method of joined.matchedMethods) {\n if (method.invocations.length === 0) continue;\n // 결정적 순서(플랫폼·경로·줄·열)의 첫 호출이 대표 증거다. 상한 밖 호출까지\n // 객체로 만들지 않도록 먼저 자른다.\n const callers = method.invocations\n .slice(0, MAX_RETENTION_CALLERS)\n .map(toRetentionCaller);\n const callersOmitted = method.invocations.length - callers.length;\n const representative = callers[0];\n if (representative === undefined) continue;\n for (const handler of method.handlers) {\n if (handler.platform !== 'swift' || handler.sourceLanguage === 'objective-c' || handler.symbol === undefined) continue;\n const symbolKey = handler.symbol.usr === undefined\n ? `name:${handler.symbol.qualifiedName}`\n : `usr:${handler.symbol.usr}`;\n const retentionKey = `${symbolKey}\\u0000${method.channel}\\u0000${method.method}`;\n if (seen.has(retentionKey)) continue;\n seen.add(retentionKey);\n callerEntries += callers.length;\n if (callerEntries > MAX_RETENTION_CALLER_ENTRIES) {\n throw new RetentionValidationError(\n `Cannot produce retention evidence with more than `\n + `${MAX_RETENTION_CALLER_ENTRIES} caller entries; narrow the join inputs.`,\n );\n }\n retentions.push({\n symbol: handler.symbol,\n reason: 'bridge',\n evidence: {\n channel: method.channel,\n method: method.method,\n caller: representative,\n ...(callers.length > 1 ? { callers } : {}),\n ...(callersOmitted > 0 ? { callersOmitted } : {}),\n },\n });\n }\n }\n return retentions;\n}\n\n/** 증거 끝점을 external-retentions의 호출자 형태로 바꾼다. */\nfunction toRetentionCaller(endpoint: {\n readonly platform: BridgePlatform;\n readonly location: { readonly path: string; readonly line: number };\n}): RetentionCaller {\n return {\n platform: endpoint.platform,\n path: endpoint.location.path,\n line: endpoint.location.line,\n };\n}\n"]}
|