isthmus-cli 0.5.0 → 0.7.0
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 +170 -45
- package/README.md +178 -36
- package/Skills/isthmus/SKILL.md +104 -5
- package/compatibility.json +10 -0
- package/dist/cli/check-command.d.ts +2 -2
- package/dist/cli/check-command.js +22 -9
- package/dist/cli/check-command.js.map +1 -1
- package/dist/cli/command-support.d.ts +20 -2
- package/dist/cli/command-support.js +38 -9
- package/dist/cli/command-support.js.map +1 -1
- package/dist/cli/diff-command.js +4 -3
- package/dist/cli/diff-command.js.map +1 -1
- package/dist/cli/doctor-command.d.ts +11 -0
- package/dist/cli/doctor-command.js +128 -0
- package/dist/cli/doctor-command.js.map +1 -0
- package/dist/cli/extract-js-command.d.ts +33 -0
- package/dist/cli/extract-js-command.js +233 -0
- package/dist/cli/extract-js-command.js.map +1 -0
- package/dist/cli/graph-command.js +13 -6
- package/dist/cli/graph-command.js.map +1 -1
- package/dist/cli/impact-command.d.ts +5 -0
- package/dist/cli/impact-command.js +111 -0
- package/dist/cli/impact-command.js.map +1 -0
- package/dist/cli/init-command.d.ts +11 -0
- package/dist/cli/init-command.js +115 -0
- package/dist/cli/init-command.js.map +1 -0
- package/dist/cli/main.js +67 -1
- package/dist/cli/main.js.map +1 -1
- package/dist/cli/mcp-server.d.ts +16 -0
- package/dist/cli/mcp-server.js +534 -0
- package/dist/cli/mcp-server.js.map +1 -0
- package/dist/cli/preflight-command.d.ts +5 -0
- package/dist/cli/preflight-command.js +83 -0
- package/dist/cli/preflight-command.js.map +1 -0
- package/dist/cli/query-command.js +13 -6
- package/dist/cli/query-command.js.map +1 -1
- package/dist/cli/retentions-command.js +14 -7
- package/dist/cli/retentions-command.js.map +1 -1
- package/dist/cli/runtime-command.d.ts +5 -0
- package/dist/cli/runtime-command.js +42 -0
- package/dist/cli/runtime-command.js.map +1 -0
- package/dist/cli/runtime-json-reader.d.ts +12 -0
- package/dist/cli/runtime-json-reader.js +37 -0
- package/dist/cli/runtime-json-reader.js.map +1 -0
- package/dist/cli/serve-command.d.ts +13 -0
- package/dist/cli/serve-command.js +43 -0
- package/dist/cli/serve-command.js.map +1 -0
- package/dist/exchange/capture-config.d.ts +18 -0
- package/dist/exchange/capture-config.js +100 -0
- package/dist/exchange/capture-config.js.map +1 -0
- package/dist/exchange/impact-selection.d.ts +13 -0
- package/dist/exchange/impact-selection.js +35 -0
- package/dist/exchange/impact-selection.js.map +1 -0
- package/dist/exchange/kartograph-impact.d.ts +4 -0
- package/dist/exchange/kartograph-impact.js +169 -0
- package/dist/exchange/kartograph-impact.js.map +1 -0
- package/dist/exchange/messages.d.ts +36 -0
- package/dist/exchange/messages.js +96 -0
- package/dist/exchange/messages.js.map +1 -0
- package/dist/exchange/parse.d.ts +69 -0
- package/dist/exchange/parse.js +127 -20
- package/dist/exchange/parse.js.map +1 -1
- package/dist/exchange/preflight-context.d.ts +71 -0
- package/dist/exchange/preflight-context.js +317 -0
- package/dist/exchange/preflight-context.js.map +1 -0
- package/dist/exchange/producer-impact.d.ts +17 -0
- package/dist/exchange/producer-impact.js +226 -0
- package/dist/exchange/producer-impact.js.map +1 -0
- package/dist/exchange/runtime.d.ts +69 -0
- package/dist/exchange/runtime.js +160 -0
- package/dist/exchange/runtime.js.map +1 -0
- package/dist/extract/js-document.d.ts +22 -0
- package/dist/extract/js-document.js +230 -0
- package/dist/extract/js-document.js.map +1 -0
- package/dist/extract/js-scan.d.ts +93 -0
- package/dist/extract/js-scan.js +1205 -0
- package/dist/extract/js-scan.js.map +1 -0
- package/dist/extract/lexer.d.ts +26 -0
- package/dist/extract/lexer.js +316 -0
- package/dist/extract/lexer.js.map +1 -0
- package/dist/join/join.d.ts +66 -1
- package/dist/join/join.js +171 -1
- package/dist/join/join.js.map +1 -1
- package/dist/join/message-address.d.ts +7 -0
- package/dist/join/message-address.js +37 -0
- package/dist/join/message-address.js.map +1 -0
- package/dist/join/messages.d.ts +26 -0
- package/dist/join/messages.js +87 -0
- package/dist/join/messages.js.map +1 -0
- package/dist/report/check-report.d.ts +20 -3
- package/dist/report/check-report.js +240 -8
- package/dist/report/check-report.js.map +1 -1
- package/dist/report/codequality.d.ts +45 -0
- package/dist/report/codequality.js +74 -0
- package/dist/report/codequality.js.map +1 -0
- package/dist/report/diff.d.ts +25 -3
- package/dist/report/diff.js +91 -10
- package/dist/report/diff.js.map +1 -1
- package/dist/report/graph.d.ts +10 -4
- package/dist/report/graph.js +60 -6
- package/dist/report/graph.js.map +1 -1
- package/dist/report/impact.d.ts +62 -0
- package/dist/report/impact.js +168 -0
- package/dist/report/impact.js.map +1 -0
- package/dist/report/preflight-runtime.d.ts +42 -0
- package/dist/report/preflight-runtime.js +193 -0
- package/dist/report/preflight-runtime.js.map +1 -0
- package/dist/report/preflight-view.d.ts +146 -0
- package/dist/report/preflight-view.js +216 -0
- package/dist/report/preflight-view.js.map +1 -0
- package/dist/report/preflight.d.ts +104 -0
- package/dist/report/preflight.js +331 -0
- package/dist/report/preflight.js.map +1 -0
- package/dist/report/query.d.ts +11 -4
- package/dist/report/query.js +84 -17
- package/dist/report/query.js.map +1 -1
- package/dist/report/retentions.d.ts +17 -5
- package/dist/report/retentions.js +85 -8
- package/dist/report/retentions.js.map +1 -1
- package/dist/report/rules.d.ts +16 -0
- package/dist/report/rules.js +30 -0
- package/dist/report/rules.js.map +1 -0
- package/dist/report/runtime-impact.d.ts +38 -0
- package/dist/report/runtime-impact.js +94 -0
- package/dist/report/runtime-impact.js.map +1 -0
- package/dist/report/runtime.d.ts +54 -0
- package/dist/report/runtime.js +137 -0
- package/dist/report/runtime.js.map +1 -0
- package/dist/report/sarif.d.ts +2 -8
- package/dist/report/sarif.js +2 -10
- package/dist/report/sarif.js.map +1 -1
- package/dist/report/sorted-json.d.ts +1 -1
- package/dist/report/sorted-json.js +2 -2
- package/dist/report/sorted-json.js.map +1 -1
- package/docs/BRIDGE-EVENTS.md +87 -0
- package/docs/BRIDGE-MESSAGES.md +117 -0
- package/docs/GRAPH-EXCHANGE.md +382 -0
- package/docs/IMPACT.md +96 -0
- package/docs/MCP.md +62 -0
- package/docs/PREFLIGHT.md +311 -0
- package/docs/RUNTIME.md +172 -0
- package/docs/TOOLCHAIN.md +101 -0
- package/package.json +14 -2
- package/scripts/build-preflight-toolchain.mjs +186 -0
- package/scripts/capture-preflight.mjs +380 -0
- package/scripts/run-child.mjs +17 -0
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { isProjectRelativePath, isSafeNonEmptyString } from "./parse.js";
|
|
2
|
+
import { compareStrings } from "../compare.js";
|
|
3
|
+
/** 변경 목록이 큰 입력을 통한 선택 집합 증폭을 일으키지 않도록 제한한다. */
|
|
4
|
+
export const MAX_IMPACT_SELECTORS = 10_000;
|
|
5
|
+
/** 변경 선택 계약 실패를 소스 값이 없는 메시지로 구분한다. */
|
|
6
|
+
export class ImpactSelectionValidationError extends Error {
|
|
7
|
+
constructor(message) {
|
|
8
|
+
super(message);
|
|
9
|
+
this.name = 'ImpactSelectionValidationError';
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
/** 외부 변경 목록을 검증하고 위치·심볼 문자열을 손대지 않은 채 중복 제거한다. */
|
|
13
|
+
export function parseImpactSelection(input) {
|
|
14
|
+
if (typeof input !== 'object' || input === null || Array.isArray(input)) {
|
|
15
|
+
throw new ImpactSelectionValidationError('Changes must be a JSON object.');
|
|
16
|
+
}
|
|
17
|
+
const value = input;
|
|
18
|
+
if (value.format !== 'isthmus-changes' || value.version !== 1) {
|
|
19
|
+
throw new ImpactSelectionValidationError('Expected isthmus-changes version 1.');
|
|
20
|
+
}
|
|
21
|
+
const files = value.files === undefined ? [] : value.files;
|
|
22
|
+
const symbols = value.symbols === undefined ? [] : value.symbols;
|
|
23
|
+
if (!Array.isArray(files) || !Array.isArray(symbols) ||
|
|
24
|
+
files.length + symbols.length === 0 || files.length + symbols.length > MAX_IMPACT_SELECTORS) {
|
|
25
|
+
throw new ImpactSelectionValidationError('Changes require 1 to 10000 file or symbol selectors.');
|
|
26
|
+
}
|
|
27
|
+
if (!files.every(isProjectRelativePath) || !symbols.every(isSafeNonEmptyString)) {
|
|
28
|
+
throw new ImpactSelectionValidationError('Changes require relative file paths and non-empty safe symbol names.');
|
|
29
|
+
}
|
|
30
|
+
return {
|
|
31
|
+
files: [...new Set(files)].sort(compareStrings),
|
|
32
|
+
symbols: [...new Set(symbols)].sort(compareStrings),
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
//# sourceMappingURL=impact-selection.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"impact-selection.js","sourceRoot":"","sources":["../../src/exchange/impact-selection.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,qBAAqB,EAAE,oBAAoB,EAAE,MAAM,YAAY,CAAC;AACzE,OAAO,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AAQ/C,+CAA+C;AAC/C,MAAM,CAAC,MAAM,oBAAoB,GAAG,MAAM,CAAC;AAE3C,uCAAuC;AACvC,MAAM,OAAO,8BAA+B,SAAQ,KAAK;IACvD,YAAY,OAAe;QACzB,KAAK,CAAC,OAAO,CAAC,CAAC;QACf,IAAI,CAAC,IAAI,GAAG,gCAAgC,CAAC;IAC/C,CAAC;CACF;AAED,kDAAkD;AAClD,MAAM,UAAU,oBAAoB,CAAC,KAAc;IACjD,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,KAAK,IAAI,IAAI,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC;QACxE,MAAM,IAAI,8BAA8B,CAAC,gCAAgC,CAAC,CAAC;IAC7E,CAAC;IACD,MAAM,KAAK,GAAG,KAAgC,CAAC;IAC/C,IAAI,KAAK,CAAC,MAAM,KAAK,iBAAiB,IAAI,KAAK,CAAC,OAAO,KAAK,CAAC,EAAE,CAAC;QAC9D,MAAM,IAAI,8BAA8B,CAAC,qCAAqC,CAAC,CAAC;IAClF,CAAC;IACD,MAAM,KAAK,GAAG,KAAK,CAAC,KAAK,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC;IAC3D,MAAM,OAAO,GAAG,KAAK,CAAC,OAAO,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC;IACjE,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,OAAO,CAAC;QAClD,KAAK,CAAC,MAAM,GAAG,OAAO,CAAC,MAAM,KAAK,CAAC,IAAI,KAAK,CAAC,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,oBAAoB,EAAE,CAAC;QAC9F,MAAM,IAAI,8BAA8B,CAAC,sDAAsD,CAAC,CAAC;IACnG,CAAC;IACD,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,qBAAqB,CAAC,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,oBAAoB,CAAC,EAAE,CAAC;QAChF,MAAM,IAAI,8BAA8B,CAAC,sEAAsE,CAAC,CAAC;IACnH,CAAC;IACD,OAAO;QACL,KAAK,EAAE,CAAC,GAAG,IAAI,GAAG,CAAC,KAAiB,CAAC,CAAC,CAAC,IAAI,CAAC,cAAc,CAAC;QAC3D,OAAO,EAAE,CAAC,GAAG,IAAI,GAAG,CAAC,OAAmB,CAAC,CAAC,CAAC,IAAI,CAAC,cAAc,CAAC;KAChE,CAAC;AACJ,CAAC","sourcesContent":["import { isProjectRelativePath, isSafeNonEmptyString } from './parse.ts';\nimport { compareStrings } from '../compare.ts';\n\n/** 변경 대상의 프로젝트 상대 파일과 정확한 심볼 이름/USR이다. 두 목록은 합집합이다. */\nexport interface ImpactSelection {\n readonly files: readonly string[];\n readonly symbols: readonly string[];\n}\n\n/** 변경 목록이 큰 입력을 통한 선택 집합 증폭을 일으키지 않도록 제한한다. */\nexport const MAX_IMPACT_SELECTORS = 10_000;\n\n/** 변경 선택 계약 실패를 소스 값이 없는 메시지로 구분한다. */\nexport class ImpactSelectionValidationError extends Error {\n constructor(message: string) {\n super(message);\n this.name = 'ImpactSelectionValidationError';\n }\n}\n\n/** 외부 변경 목록을 검증하고 위치·심볼 문자열을 손대지 않은 채 중복 제거한다. */\nexport function parseImpactSelection(input: unknown): ImpactSelection {\n if (typeof input !== 'object' || input === null || Array.isArray(input)) {\n throw new ImpactSelectionValidationError('Changes must be a JSON object.');\n }\n const value = input as Record<string, unknown>;\n if (value.format !== 'isthmus-changes' || value.version !== 1) {\n throw new ImpactSelectionValidationError('Expected isthmus-changes version 1.');\n }\n const files = value.files === undefined ? [] : value.files;\n const symbols = value.symbols === undefined ? [] : value.symbols;\n if (!Array.isArray(files) || !Array.isArray(symbols) ||\n files.length + symbols.length === 0 || files.length + symbols.length > MAX_IMPACT_SELECTORS) {\n throw new ImpactSelectionValidationError('Changes require 1 to 10000 file or symbol selectors.');\n }\n if (!files.every(isProjectRelativePath) || !symbols.every(isSafeNonEmptyString)) {\n throw new ImpactSelectionValidationError('Changes require relative file paths and non-empty safe symbol names.');\n }\n return {\n files: [...new Set(files as string[])].sort(compareStrings),\n symbols: [...new Set(symbols as string[])].sort(compareStrings),\n };\n}\n"]}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import { type LanguageImpact } from './preflight-context.ts';
|
|
2
|
+
import type { ProducerImpactMetadata } from './producer-impact.ts';
|
|
3
|
+
/** Kartograph의 현재 시점 영향 근거를 공통 사전 점검 형식으로 연결한다. */
|
|
4
|
+
export declare function adaptKartographImpact(raw: unknown, metadata: ProducerImpactMetadata): LanguageImpact;
|
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
import { PreflightValidationError, validateLanguageImpact } from "./preflight-context.js";
|
|
2
|
+
import { isProjectRelativePath, isSafeNonEmptyString } from "./parse.js";
|
|
3
|
+
import { compareStrings } from "../compare.js";
|
|
4
|
+
/** Kartograph의 현재 시점 영향 근거를 공통 사전 점검 형식으로 연결한다. */
|
|
5
|
+
export function adaptKartographImpact(raw, metadata) {
|
|
6
|
+
const value = object(raw);
|
|
7
|
+
if (value.format !== 'kartograph-impact' || value.version !== 1)
|
|
8
|
+
fail('Expected kartograph-impact version 1.');
|
|
9
|
+
if (!['found', 'partial', 'notFound', 'noChanges'].includes(string(value.status)))
|
|
10
|
+
fail('Invalid Kartograph impact status.');
|
|
11
|
+
if (!isSafeNonEmptyString(metadata.project))
|
|
12
|
+
fail('Invalid Kartograph project metadata.');
|
|
13
|
+
const inputs = object(value.inputs);
|
|
14
|
+
if (inputs.base !== undefined)
|
|
15
|
+
fail('Kartograph preflight requires a current-only impact report.');
|
|
16
|
+
const limitations = array(value.limitations).map((item) => string(item));
|
|
17
|
+
const flags = object(value.truncated);
|
|
18
|
+
for (const key of ['results', 'depth', 'budget'])
|
|
19
|
+
if (typeof flags[key] !== 'boolean')
|
|
20
|
+
fail('Invalid Kartograph truncation flag.');
|
|
21
|
+
const navigation = value.navigation === undefined ? undefined : object(value.navigation);
|
|
22
|
+
if (navigation !== undefined && (!Number.isSafeInteger(navigation.offset) || navigation.offset < 0 ||
|
|
23
|
+
typeof navigation.hasNext !== 'boolean' || typeof navigation.hasPrevious !== 'boolean'))
|
|
24
|
+
fail('Invalid Kartograph navigation.');
|
|
25
|
+
let truncated = Object.values(flags).some((flag) => flag === true) || value.status === 'partial' ||
|
|
26
|
+
(navigation !== undefined && (navigation.offset !== 0 || navigation.hasNext === true || navigation.hasPrevious === true));
|
|
27
|
+
let missingLocations = 0;
|
|
28
|
+
let partialLocations = 0;
|
|
29
|
+
let omittedPaths = 0;
|
|
30
|
+
let pathItems = 0;
|
|
31
|
+
const symbols = new Map();
|
|
32
|
+
const changed = array(value.changed).map(object);
|
|
33
|
+
const affected = array(value.affected).map(object);
|
|
34
|
+
for (const row of [...changed, ...affected]) {
|
|
35
|
+
const id = string(row.usr);
|
|
36
|
+
if (symbols.has(id))
|
|
37
|
+
fail('Kartograph impact symbol ids must be unique.');
|
|
38
|
+
const current = array(row.presentIn).map(string).includes('current');
|
|
39
|
+
if (!current) {
|
|
40
|
+
omittedPaths++;
|
|
41
|
+
continue;
|
|
42
|
+
}
|
|
43
|
+
let location;
|
|
44
|
+
if (row.location !== null && row.location !== undefined) {
|
|
45
|
+
const source = object(row.location);
|
|
46
|
+
const path = typeof source.path === 'string' && source.path.startsWith(`${metadata.project}/`)
|
|
47
|
+
? source.path.slice(metadata.project.length + 1) : source.path;
|
|
48
|
+
if (isProjectRelativePath(path)) {
|
|
49
|
+
const line = Number.isSafeInteger(source.line) && source.line > 0 ? source.line : undefined;
|
|
50
|
+
const column = line !== undefined && Number.isSafeInteger(source.column) && source.column > 0
|
|
51
|
+
? source.column : undefined;
|
|
52
|
+
location = { path, ...(line === undefined ? {} : { line }), ...(column === undefined ? {} : { column }) };
|
|
53
|
+
if (column === undefined)
|
|
54
|
+
partialLocations++;
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
if (location === undefined)
|
|
58
|
+
missingLocations++;
|
|
59
|
+
symbols.set(id, { id, qualifiedName: string(row.qualifiedName),
|
|
60
|
+
...(row.kind === undefined ? {} : { kind: string(row.kind) }), ...(location === undefined ? {} : { location }) });
|
|
61
|
+
}
|
|
62
|
+
const roots = changed.flatMap((row) => symbols.has(string(row.usr)) ? [symbols.get(string(row.usr))] : []);
|
|
63
|
+
const rootIds = new Set(roots.map(({ id }) => id));
|
|
64
|
+
const adjacency = new Map();
|
|
65
|
+
for (const row of affected) {
|
|
66
|
+
omittedPaths += row.pathOmissions === undefined ? 0 : array(row.pathOmissions).length;
|
|
67
|
+
if (row.pathStatus !== undefined && row.pathStatus !== 'complete')
|
|
68
|
+
truncated = true;
|
|
69
|
+
for (const input of array(row.paths)) {
|
|
70
|
+
const path = object(input);
|
|
71
|
+
const revision = string(path.revision);
|
|
72
|
+
if (revision === 'base') {
|
|
73
|
+
omittedPaths++;
|
|
74
|
+
continue;
|
|
75
|
+
}
|
|
76
|
+
if (revision !== 'current')
|
|
77
|
+
fail('Invalid Kartograph path revision.');
|
|
78
|
+
const nodes = array(path.nodes).map(string);
|
|
79
|
+
const edges = array(path.edges).map(object);
|
|
80
|
+
pathItems += nodes.length + edges.length;
|
|
81
|
+
if (pathItems > 1_000_000)
|
|
82
|
+
fail('Kartograph impact paths exceed their budget.');
|
|
83
|
+
if (nodes.length < 2 || nodes.length > 129 || edges.length !== nodes.length - 1 || nodes[0] !== row.usr ||
|
|
84
|
+
nodes.at(-1) !== path.changed || new Set(nodes).size !== nodes.length)
|
|
85
|
+
fail('Invalid Kartograph impact path.');
|
|
86
|
+
const relationships = edges.map((edge, index) => {
|
|
87
|
+
const source = string(edge.source);
|
|
88
|
+
const target = string(edge.target);
|
|
89
|
+
const forward = source === nodes[index] && target === nodes[index + 1];
|
|
90
|
+
const reverse = target === nodes[index] && source === nodes[index + 1];
|
|
91
|
+
if ((!forward && !reverse) || (reverse && edge.kind !== 'override') ||
|
|
92
|
+
edge.traversal !== (forward ? 'dependency' : 'overrideContract')) {
|
|
93
|
+
fail('Kartograph path edges do not match their traversal.');
|
|
94
|
+
}
|
|
95
|
+
return [string(edge.kind), `origin:${string(edge.origin)}`, `traversal:${string(edge.traversal)}`];
|
|
96
|
+
});
|
|
97
|
+
if (!rootIds.has(string(path.changed)) || nodes.some((id) => !symbols.has(id))) {
|
|
98
|
+
omittedPaths++;
|
|
99
|
+
continue;
|
|
100
|
+
}
|
|
101
|
+
for (let index = 0; index < edges.length; index++) {
|
|
102
|
+
const parent = nodes[index + 1];
|
|
103
|
+
const child = nodes[index];
|
|
104
|
+
let children = adjacency.get(parent);
|
|
105
|
+
if (children === undefined) {
|
|
106
|
+
children = new Map();
|
|
107
|
+
adjacency.set(parent, children);
|
|
108
|
+
}
|
|
109
|
+
let reasons = children.get(child);
|
|
110
|
+
if (reasons === undefined) {
|
|
111
|
+
reasons = new Set();
|
|
112
|
+
children.set(child, reasons);
|
|
113
|
+
}
|
|
114
|
+
for (const reason of relationships[index])
|
|
115
|
+
reasons.add(reason);
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
// 같은 current 그래프의 관찰 간선만 사용한다. 한 정점의 대표 경로는 가장 짧은 경로다.
|
|
120
|
+
const queue = [...rootIds].sort(compareStrings);
|
|
121
|
+
const depth = new Map(queue.map((id) => [id, 0]));
|
|
122
|
+
const rows = [];
|
|
123
|
+
for (let index = 0; index < queue.length; index++) {
|
|
124
|
+
const parent = queue[index];
|
|
125
|
+
for (const [id, reasons] of [...(adjacency.get(parent) ?? [])].sort(([a], [b]) => compareStrings(a, b))) {
|
|
126
|
+
if (depth.has(id))
|
|
127
|
+
continue;
|
|
128
|
+
const distance = depth.get(parent) + 1;
|
|
129
|
+
if (distance > 128) {
|
|
130
|
+
omittedPaths++;
|
|
131
|
+
continue;
|
|
132
|
+
}
|
|
133
|
+
depth.set(id, distance);
|
|
134
|
+
queue.push(id);
|
|
135
|
+
rows.push({ symbol: symbols.get(id), via: parent, depth: distance, relationships: [...reasons].sort(compareStrings) });
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
omittedPaths += affected.filter((row) => symbols.has(string(row.usr)) && !depth.has(string(row.usr))).length;
|
|
139
|
+
const unresolved = array(value.unresolved);
|
|
140
|
+
if (unresolved.length > 0)
|
|
141
|
+
limitations.push(`kartograph-unresolved: ${unresolved.length} requested item(s) require review`);
|
|
142
|
+
if (missingLocations > 0)
|
|
143
|
+
limitations.push(`kartograph-unresolved-locations: ${missingLocations} symbol location(s) omitted`);
|
|
144
|
+
if (partialLocations > 0)
|
|
145
|
+
limitations.push(`kartograph-partial-source-locations: ${partialLocations} JVM symbol location(s) lack exact line or column coordinates`);
|
|
146
|
+
if (omittedPaths > 0)
|
|
147
|
+
limitations.push(`kartograph-unrepresented-paths: ${omittedPaths} path or symbol observation(s) require the original producer report`);
|
|
148
|
+
truncated ||= omittedPaths > 0;
|
|
149
|
+
return validateLanguageImpact({ id: metadata.id, platform: 'kotlin', requested: metadata.requested,
|
|
150
|
+
tool: metadata.tool, ...(metadata.trigger === undefined ? {} : { trigger: metadata.trigger }),
|
|
151
|
+
roots, affected: rows, limitations, truncated });
|
|
152
|
+
}
|
|
153
|
+
function object(value) {
|
|
154
|
+
if (value === null || typeof value !== 'object' || Array.isArray(value))
|
|
155
|
+
fail('Invalid Kartograph impact object.');
|
|
156
|
+
return value;
|
|
157
|
+
}
|
|
158
|
+
function array(value) {
|
|
159
|
+
if (!Array.isArray(value) || value.length > 50_000)
|
|
160
|
+
fail('Invalid Kartograph impact array.');
|
|
161
|
+
return value;
|
|
162
|
+
}
|
|
163
|
+
function string(value) {
|
|
164
|
+
if (!isSafeNonEmptyString(value))
|
|
165
|
+
fail('Invalid Kartograph impact string.');
|
|
166
|
+
return value;
|
|
167
|
+
}
|
|
168
|
+
function fail(message) { throw new PreflightValidationError(message); }
|
|
169
|
+
//# sourceMappingURL=kartograph-impact.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"kartograph-impact.js","sourceRoot":"","sources":["../../src/exchange/kartograph-impact.ts"],"names":[],"mappings":"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","sourcesContent":["import { PreflightValidationError, validateLanguageImpact, type LanguageImpact, type ImpactSymbol } from './preflight-context.ts';\nimport type { ProducerImpactMetadata } from './producer-impact.ts';\nimport { isProjectRelativePath, isSafeNonEmptyString } from './parse.ts';\nimport { compareStrings } from '../compare.ts';\n\n/** Kartograph의 현재 시점 영향 근거를 공통 사전 점검 형식으로 연결한다. */\nexport function adaptKartographImpact(raw: unknown, metadata: ProducerImpactMetadata): LanguageImpact {\n const value = object(raw);\n if (value.format !== 'kartograph-impact' || value.version !== 1) fail('Expected kartograph-impact version 1.');\n if (!['found', 'partial', 'notFound', 'noChanges'].includes(string(value.status))) fail('Invalid Kartograph impact status.');\n if (!isSafeNonEmptyString(metadata.project)) fail('Invalid Kartograph project metadata.');\n const inputs = object(value.inputs);\n if (inputs.base !== undefined) fail('Kartograph preflight requires a current-only impact report.');\n const limitations = array(value.limitations).map((item) => string(item));\n const flags = object(value.truncated);\n for (const key of ['results', 'depth', 'budget']) if (typeof flags[key] !== 'boolean') fail('Invalid Kartograph truncation flag.');\n const navigation = value.navigation === undefined ? undefined : object(value.navigation);\n if (navigation !== undefined && (!Number.isSafeInteger(navigation.offset) || (navigation.offset as number) < 0 ||\n typeof navigation.hasNext !== 'boolean' || typeof navigation.hasPrevious !== 'boolean')) fail('Invalid Kartograph navigation.');\n let truncated = Object.values(flags).some((flag) => flag === true) || value.status === 'partial' ||\n (navigation !== undefined && (navigation.offset !== 0 || navigation.hasNext === true || navigation.hasPrevious === true));\n let missingLocations = 0;\n let partialLocations = 0;\n let omittedPaths = 0;\n let pathItems = 0;\n const symbols = new Map<string, ImpactSymbol>();\n const changed = array(value.changed).map(object);\n const affected = array(value.affected).map(object);\n for (const row of [...changed, ...affected]) {\n const id = string(row.usr);\n if (symbols.has(id)) fail('Kartograph impact symbol ids must be unique.');\n const current = array(row.presentIn).map(string).includes('current');\n if (!current) { omittedPaths++; continue; }\n let location;\n if (row.location !== null && row.location !== undefined) {\n const source = object(row.location);\n const path = typeof source.path === 'string' && source.path.startsWith(`${metadata.project}/`)\n ? source.path.slice(metadata.project.length + 1) : source.path;\n if (isProjectRelativePath(path)) {\n const line = Number.isSafeInteger(source.line) && (source.line as number) > 0 ? source.line as number : undefined;\n const column = line !== undefined && Number.isSafeInteger(source.column) && (source.column as number) > 0\n ? source.column as number : undefined;\n location = { path, ...(line === undefined ? {} : { line }), ...(column === undefined ? {} : { column }) };\n if (column === undefined) partialLocations++;\n }\n }\n if (location === undefined) missingLocations++;\n symbols.set(id, { id, qualifiedName: string(row.qualifiedName),\n ...(row.kind === undefined ? {} : { kind: string(row.kind) }), ...(location === undefined ? {} : { location }) });\n }\n const roots = changed.flatMap((row) => symbols.has(string(row.usr)) ? [symbols.get(string(row.usr))!] : []);\n const rootIds = new Set(roots.map(({ id }) => id));\n const adjacency = new Map<string, Map<string, Set<string>>>();\n for (const row of affected) {\n omittedPaths += row.pathOmissions === undefined ? 0 : array(row.pathOmissions).length;\n if (row.pathStatus !== undefined && row.pathStatus !== 'complete') truncated = true;\n for (const input of array(row.paths)) {\n const path = object(input);\n const revision = string(path.revision);\n if (revision === 'base') { omittedPaths++; continue; }\n if (revision !== 'current') fail('Invalid Kartograph path revision.');\n const nodes = array(path.nodes).map(string);\n const edges = array(path.edges).map(object);\n pathItems += nodes.length + edges.length;\n if (pathItems > 1_000_000) fail('Kartograph impact paths exceed their budget.');\n if (nodes.length < 2 || nodes.length > 129 || edges.length !== nodes.length - 1 || nodes[0] !== row.usr ||\n nodes.at(-1) !== path.changed || new Set(nodes).size !== nodes.length) fail('Invalid Kartograph impact path.');\n const relationships = edges.map((edge, index) => {\n const source = string(edge.source); const target = string(edge.target);\n const forward = source === nodes[index] && target === nodes[index + 1];\n const reverse = target === nodes[index] && source === nodes[index + 1];\n if ((!forward && !reverse) || (reverse && edge.kind !== 'override') ||\n edge.traversal !== (forward ? 'dependency' : 'overrideContract')) {\n fail('Kartograph path edges do not match their traversal.');\n }\n return [string(edge.kind), `origin:${string(edge.origin)}`, `traversal:${string(edge.traversal)}`];\n });\n if (!rootIds.has(string(path.changed)) || nodes.some((id) => !symbols.has(id))) { omittedPaths++; continue; }\n for (let index = 0; index < edges.length; index++) {\n const parent = nodes[index + 1]!; const child = nodes[index]!;\n let children = adjacency.get(parent);\n if (children === undefined) { children = new Map(); adjacency.set(parent, children); }\n let reasons = children.get(child);\n if (reasons === undefined) { reasons = new Set(); children.set(child, reasons); }\n for (const reason of relationships[index]!) reasons.add(reason);\n }\n }\n }\n // 같은 current 그래프의 관찰 간선만 사용한다. 한 정점의 대표 경로는 가장 짧은 경로다.\n const queue = [...rootIds].sort(compareStrings);\n const depth = new Map(queue.map((id) => [id, 0]));\n const rows: Array<LanguageImpact['affected'][number]> = [];\n for (let index = 0; index < queue.length; index++) {\n const parent = queue[index]!;\n for (const [id, reasons] of [...(adjacency.get(parent) ?? [])].sort(([a], [b]) => compareStrings(a, b))) {\n if (depth.has(id)) continue;\n const distance = depth.get(parent)! + 1;\n if (distance > 128) { omittedPaths++; continue; }\n depth.set(id, distance); queue.push(id);\n rows.push({ symbol: symbols.get(id)!, via: parent, depth: distance, relationships: [...reasons].sort(compareStrings) });\n }\n }\n omittedPaths += affected.filter((row) => symbols.has(string(row.usr)) && !depth.has(string(row.usr))).length;\n const unresolved = array(value.unresolved);\n if (unresolved.length > 0) limitations.push(`kartograph-unresolved: ${unresolved.length} requested item(s) require review`);\n if (missingLocations > 0) limitations.push(`kartograph-unresolved-locations: ${missingLocations} symbol location(s) omitted`);\n if (partialLocations > 0) limitations.push(`kartograph-partial-source-locations: ${partialLocations} JVM symbol location(s) lack exact line or column coordinates`);\n if (omittedPaths > 0) limitations.push(`kartograph-unrepresented-paths: ${omittedPaths} path or symbol observation(s) require the original producer report`);\n truncated ||= omittedPaths > 0;\n return validateLanguageImpact({ id: metadata.id, platform: 'kotlin', requested: metadata.requested,\n tool: metadata.tool, ...(metadata.trigger === undefined ? {} : { trigger: metadata.trigger }),\n roots, affected: rows, limitations, truncated });\n}\n\nfunction object(value: unknown): Record<string, unknown> {\n if (value === null || typeof value !== 'object' || Array.isArray(value)) fail('Invalid Kartograph impact object.');\n return value as Record<string, unknown>;\n}\nfunction array(value: unknown): unknown[] {\n if (!Array.isArray(value) || value.length > 50_000) fail('Invalid Kartograph impact array.');\n return value;\n}\nfunction string(value: unknown): string {\n if (!isSafeNonEmptyString(value)) fail('Invalid Kartograph impact string.');\n return value;\n}\nfunction fail(message: string): never { throw new PreflightValidationError(message); }\n"]}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import type { BridgeHandlerDependency, BridgeHandlerScope, BridgeLocation, BridgeSourceLanguage, BridgeSymbol } from './parse.ts';
|
|
2
|
+
export type { BridgeHandlerDependency, BridgeHandlerScope } from './parse.ts';
|
|
3
|
+
/** v2 문서가 다루는 transport다. Basic은 호출/응답, Event는 네이티브→Dart 스트림이다. */
|
|
4
|
+
export type BridgeMessageTransport = 'basic-message-channel' | 'event-channel';
|
|
5
|
+
/** Basic·Event 채널의 발신·수신 사실이며 MethodChannel 메서드를 합성하지 않는다. */
|
|
6
|
+
export interface BridgeMessageFact {
|
|
7
|
+
readonly kind: 'message-send' | 'message-handle' | 'stream-listen' | 'stream-handle';
|
|
8
|
+
readonly channel: string | null;
|
|
9
|
+
readonly dynamic: boolean;
|
|
10
|
+
readonly channelPrefix?: string;
|
|
11
|
+
readonly location: BridgeLocation;
|
|
12
|
+
readonly symbol?: BridgeSymbol;
|
|
13
|
+
readonly sourceLanguage?: BridgeSourceLanguage;
|
|
14
|
+
readonly handlerScope?: BridgeHandlerScope;
|
|
15
|
+
readonly dependencies?: readonly BridgeHandlerDependency[];
|
|
16
|
+
}
|
|
17
|
+
/** v1 전용 소비자가 조용히 무시하지 못하도록 별도 버전으로 전달하는 v2 문서다. */
|
|
18
|
+
export interface BridgeMessageDocument {
|
|
19
|
+
readonly format: 'bridge-facts';
|
|
20
|
+
readonly version: 2;
|
|
21
|
+
readonly transport: BridgeMessageTransport;
|
|
22
|
+
readonly platform: 'dart' | 'swift' | 'kotlin';
|
|
23
|
+
readonly target: 'flutter' | null;
|
|
24
|
+
readonly project: string;
|
|
25
|
+
readonly generatedAt: string;
|
|
26
|
+
readonly tool: {
|
|
27
|
+
readonly name: string;
|
|
28
|
+
readonly version: string;
|
|
29
|
+
};
|
|
30
|
+
readonly facts: readonly BridgeMessageFact[];
|
|
31
|
+
readonly limitations: readonly string[];
|
|
32
|
+
}
|
|
33
|
+
/** 입력 묶음의 역할·프로젝트 범위를 값 조인 없이 검증한다. */
|
|
34
|
+
export declare function validateMessageDocuments(documents: readonly BridgeMessageDocument[], project: string): void;
|
|
35
|
+
/** transport별 v2를 검증하고 알려진 필드만 복사한다. v1 입력 파서는 그대로 유지한다. */
|
|
36
|
+
export declare function parseMessageBridgeDocument(input: unknown): BridgeMessageDocument;
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
import { BridgeFactsValidationError, isBridgeTimestamp, isSafeNonEmptyString, MAX_FACTS_PER_DOCUMENT, MAX_SCOPE_DEPENDENCIES_PER_DOCUMENT, normalizeScopeEvidence, validateLocation, validateScopeEvidence, validateSourceLanguage, validateSymbol } from "./parse.js";
|
|
2
|
+
/** transport·플랫폼별 허용 사실 종류와 미귀속 한계 접두사다. */
|
|
3
|
+
const transportRules = {
|
|
4
|
+
'basic-message-channel': {
|
|
5
|
+
dart: 'message-send', native: 'message-handle', unattributed: 'unattributed-message-handles:',
|
|
6
|
+
},
|
|
7
|
+
'event-channel': {
|
|
8
|
+
dart: 'stream-listen', native: 'stream-handle', unattributed: 'unattributed-stream-handles:',
|
|
9
|
+
},
|
|
10
|
+
};
|
|
11
|
+
/** 입력 묶음의 역할·프로젝트 범위를 값 조인 없이 검증한다. */
|
|
12
|
+
export function validateMessageDocuments(documents, project) {
|
|
13
|
+
if (documents.length === 0)
|
|
14
|
+
return;
|
|
15
|
+
if (documents.length > 256 || documents.some((document) => document.project !== project) ||
|
|
16
|
+
!documents.some(({ platform }) => platform === 'dart') || !documents.some(({ platform }) => platform === 'swift' || platform === 'kotlin')) {
|
|
17
|
+
fail('Message inputs require Dart and native documents for the same project.');
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
/** transport별 v2를 검증하고 알려진 필드만 복사한다. v1 입력 파서는 그대로 유지한다. */
|
|
21
|
+
export function parseMessageBridgeDocument(input) {
|
|
22
|
+
const value = object(input);
|
|
23
|
+
if (value.format !== 'bridge-facts' || value.version !== 2 ||
|
|
24
|
+
(value.transport !== 'basic-message-channel' && value.transport !== 'event-channel')) {
|
|
25
|
+
fail('Expected bridge-facts version 2 for a message transport.');
|
|
26
|
+
}
|
|
27
|
+
const rules = transportRules[value.transport];
|
|
28
|
+
if (value.platform !== 'dart' && value.platform !== 'swift' && value.platform !== 'kotlin')
|
|
29
|
+
fail('Unsupported message bridge platform.');
|
|
30
|
+
if (!Array.isArray(value.facts) || value.facts.length > MAX_FACTS_PER_DOCUMENT)
|
|
31
|
+
fail('Invalid message bridge fact count.');
|
|
32
|
+
if (value.target !== (value.facts.length ? 'flutter' : null))
|
|
33
|
+
fail('Invalid message bridge target.');
|
|
34
|
+
if (!isBridgeTimestamp(value.generatedAt))
|
|
35
|
+
fail('Invalid message bridge timestamp.');
|
|
36
|
+
const project = safe(value.project);
|
|
37
|
+
const tool = object(value.tool);
|
|
38
|
+
const limitations = value.limitations;
|
|
39
|
+
if (!Array.isArray(limitations) || !limitations.every((item) => typeof item === 'string'))
|
|
40
|
+
fail('Invalid message bridge limitations.');
|
|
41
|
+
let dependencyCount = 0;
|
|
42
|
+
const consumeDependencies = (count) => {
|
|
43
|
+
dependencyCount += count;
|
|
44
|
+
if (dependencyCount > MAX_SCOPE_DEPENDENCIES_PER_DOCUMENT)
|
|
45
|
+
fail('Message dependency budget exceeded.');
|
|
46
|
+
};
|
|
47
|
+
const facts = value.facts.map((item, index) => {
|
|
48
|
+
const fact = object(item);
|
|
49
|
+
const expectedKind = value.platform === 'dart' ? rules.dart : rules.native;
|
|
50
|
+
if (fact.kind !== expectedKind || fact.method !== undefined)
|
|
51
|
+
fail('Invalid message bridge fact kind or method.');
|
|
52
|
+
if (fact.channel === null ? fact.kind !== rules.native : !isSafeNonEmptyString(fact.channel))
|
|
53
|
+
fail('Invalid message bridge channel.');
|
|
54
|
+
if (typeof fact.dynamic !== 'boolean')
|
|
55
|
+
fail('Invalid message bridge dynamic flag.');
|
|
56
|
+
if (fact.channelPrefix !== undefined && (!fact.dynamic || fact.channel === null || !isSafeNonEmptyString(fact.channelPrefix))) {
|
|
57
|
+
fail('Message prefix requires a dynamic channel and a non-empty proven prefix.');
|
|
58
|
+
}
|
|
59
|
+
validateLocation(fact.location, index);
|
|
60
|
+
validateSymbol(fact.symbol, index);
|
|
61
|
+
const location = fact.location;
|
|
62
|
+
const symbol = fact.symbol;
|
|
63
|
+
validateSourceLanguage(fact.sourceLanguage, value.platform, location, symbol, index);
|
|
64
|
+
let scoped;
|
|
65
|
+
if (fact.handlerScope !== undefined || fact.dependencies !== undefined) {
|
|
66
|
+
if (expectedKind !== rules.native || fact.sourceLanguage !== undefined)
|
|
67
|
+
fail('Handler dependencies require a native message handler.');
|
|
68
|
+
validateScopeEvidence(fact, location, symbol, index, consumeDependencies);
|
|
69
|
+
scoped = normalizeScopeEvidence(fact.handlerScope, fact.dependencies);
|
|
70
|
+
}
|
|
71
|
+
return { kind: expectedKind, channel: fact.channel, dynamic: fact.dynamic,
|
|
72
|
+
location: { path: location.path, line: location.line, column: location.column },
|
|
73
|
+
...(fact.channelPrefix === undefined ? {} : { channelPrefix: fact.channelPrefix }),
|
|
74
|
+
...(symbol === undefined ? {} : { symbol: { qualifiedName: symbol.qualifiedName, ...(symbol.usr === undefined ? {} : { usr: symbol.usr }) } }),
|
|
75
|
+
...(fact.sourceLanguage === undefined ? {} : { sourceLanguage: fact.sourceLanguage }),
|
|
76
|
+
...(scoped === undefined ? {} : scoped), };
|
|
77
|
+
});
|
|
78
|
+
if (facts.some((fact) => fact.channel === null) && !limitations.some((item) => item.startsWith(rules.unattributed))) {
|
|
79
|
+
fail('Unattributed message handles require a limitation.');
|
|
80
|
+
}
|
|
81
|
+
return { format: 'bridge-facts', version: 2, transport: value.transport, platform: value.platform,
|
|
82
|
+
target: facts.length ? 'flutter' : null, project, generatedAt: value.generatedAt,
|
|
83
|
+
tool: { name: safe(tool.name), version: safe(tool.version) }, facts, limitations: [...limitations] };
|
|
84
|
+
}
|
|
85
|
+
function object(value) {
|
|
86
|
+
if (value === null || typeof value !== 'object' || Array.isArray(value))
|
|
87
|
+
fail('Message bridge input must be a JSON object.');
|
|
88
|
+
return value;
|
|
89
|
+
}
|
|
90
|
+
function safe(value) {
|
|
91
|
+
if (!isSafeNonEmptyString(value))
|
|
92
|
+
fail('Invalid message bridge metadata.');
|
|
93
|
+
return value;
|
|
94
|
+
}
|
|
95
|
+
function fail(message) { throw new BridgeFactsValidationError(message); }
|
|
96
|
+
//# sourceMappingURL=messages.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"messages.js","sourceRoot":"","sources":["../../src/exchange/messages.ts"],"names":[],"mappings":"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","sourcesContent":["import { BridgeFactsValidationError, isBridgeTimestamp, isSafeNonEmptyString, MAX_FACTS_PER_DOCUMENT,\n MAX_SCOPE_DEPENDENCIES_PER_DOCUMENT, normalizeScopeEvidence, validateLocation, validateScopeEvidence,\n validateSourceLanguage, validateSymbol } from './parse.ts';\nimport type { BridgeHandlerDependency, BridgeHandlerScope, BridgeLocation, BridgeSourceLanguage, BridgeSymbol } from './parse.ts';\n\nexport type { BridgeHandlerDependency, BridgeHandlerScope } from './parse.ts';\n\n/** v2 문서가 다루는 transport다. Basic은 호출/응답, Event는 네이티브→Dart 스트림이다. */\nexport type BridgeMessageTransport = 'basic-message-channel' | 'event-channel';\n\n/** Basic·Event 채널의 발신·수신 사실이며 MethodChannel 메서드를 합성하지 않는다. */\nexport interface BridgeMessageFact {\n readonly kind: 'message-send' | 'message-handle' | 'stream-listen' | 'stream-handle';\n readonly channel: string | null;\n readonly dynamic: boolean;\n readonly channelPrefix?: string;\n readonly location: BridgeLocation;\n readonly symbol?: BridgeSymbol;\n readonly sourceLanguage?: BridgeSourceLanguage;\n readonly handlerScope?: BridgeHandlerScope;\n readonly dependencies?: readonly BridgeHandlerDependency[];\n}\n\n/** v1 전용 소비자가 조용히 무시하지 못하도록 별도 버전으로 전달하는 v2 문서다. */\nexport interface BridgeMessageDocument {\n readonly format: 'bridge-facts';\n readonly version: 2;\n readonly transport: BridgeMessageTransport;\n readonly platform: 'dart' | 'swift' | 'kotlin';\n readonly target: 'flutter' | null;\n readonly project: string;\n readonly generatedAt: string;\n readonly tool: { readonly name: string; readonly version: string };\n readonly facts: readonly BridgeMessageFact[];\n readonly limitations: readonly string[];\n}\n\n/** transport·플랫폼별 허용 사실 종류와 미귀속 한계 접두사다. */\nconst transportRules = {\n 'basic-message-channel': {\n dart: 'message-send', native: 'message-handle', unattributed: 'unattributed-message-handles:',\n },\n 'event-channel': {\n dart: 'stream-listen', native: 'stream-handle', unattributed: 'unattributed-stream-handles:',\n },\n} as const;\n\n/** 입력 묶음의 역할·프로젝트 범위를 값 조인 없이 검증한다. */\nexport function validateMessageDocuments(documents: readonly BridgeMessageDocument[], project: string): void {\n if (documents.length === 0) return;\n if (documents.length > 256 || documents.some((document) => document.project !== project) ||\n !documents.some(({ platform }) => platform === 'dart') || !documents.some(({ platform }) => platform === 'swift' || platform === 'kotlin')) {\n fail('Message inputs require Dart and native documents for the same project.');\n }\n}\n\n/** transport별 v2를 검증하고 알려진 필드만 복사한다. v1 입력 파서는 그대로 유지한다. */\nexport function parseMessageBridgeDocument(input: unknown): BridgeMessageDocument {\n const value = object(input);\n if (value.format !== 'bridge-facts' || value.version !== 2 ||\n (value.transport !== 'basic-message-channel' && value.transport !== 'event-channel')) {\n fail('Expected bridge-facts version 2 for a message transport.');\n }\n const rules = transportRules[value.transport];\n if (value.platform !== 'dart' && value.platform !== 'swift' && value.platform !== 'kotlin') fail('Unsupported message bridge platform.');\n if (!Array.isArray(value.facts) || value.facts.length > MAX_FACTS_PER_DOCUMENT) fail('Invalid message bridge fact count.');\n if (value.target !== (value.facts.length ? 'flutter' : null)) fail('Invalid message bridge target.');\n if (!isBridgeTimestamp(value.generatedAt)) fail('Invalid message bridge timestamp.');\n const project = safe(value.project);\n const tool = object(value.tool);\n const limitations = value.limitations;\n if (!Array.isArray(limitations) || !limitations.every((item) => typeof item === 'string')) fail('Invalid message bridge limitations.');\n let dependencyCount = 0;\n const consumeDependencies = (count: number): void => {\n dependencyCount += count;\n if (dependencyCount > MAX_SCOPE_DEPENDENCIES_PER_DOCUMENT) fail('Message dependency budget exceeded.');\n };\n const facts = value.facts.map((item, index): BridgeMessageFact => {\n const fact = object(item);\n const expectedKind = value.platform === 'dart' ? rules.dart : rules.native;\n if (fact.kind !== expectedKind || fact.method !== undefined) fail('Invalid message bridge fact kind or method.');\n if (fact.channel === null ? fact.kind !== rules.native : !isSafeNonEmptyString(fact.channel)) fail('Invalid message bridge channel.');\n if (typeof fact.dynamic !== 'boolean') fail('Invalid message bridge dynamic flag.');\n if (fact.channelPrefix !== undefined && (!fact.dynamic || fact.channel === null || !isSafeNonEmptyString(fact.channelPrefix))) {\n fail('Message prefix requires a dynamic channel and a non-empty proven prefix.');\n }\n validateLocation(fact.location, index);\n validateSymbol(fact.symbol, index);\n const location = fact.location as BridgeLocation;\n const symbol = fact.symbol as BridgeSymbol | undefined;\n validateSourceLanguage(fact.sourceLanguage, value.platform, location, symbol, index);\n let scoped: { handlerScope: BridgeHandlerScope; dependencies: readonly BridgeHandlerDependency[] } | undefined;\n if (fact.handlerScope !== undefined || fact.dependencies !== undefined) {\n if (expectedKind !== rules.native || fact.sourceLanguage !== undefined) fail('Handler dependencies require a native message handler.');\n validateScopeEvidence(fact, location, symbol, index, consumeDependencies);\n scoped = normalizeScopeEvidence(fact.handlerScope as BridgeHandlerScope,\n fact.dependencies as readonly BridgeHandlerDependency[]);\n }\n return { kind: expectedKind, channel: fact.channel as string | null, dynamic: fact.dynamic,\n location: { path: location.path, line: location.line, column: location.column },\n ...(fact.channelPrefix === undefined ? {} : { channelPrefix: fact.channelPrefix as string }),\n ...(symbol === undefined ? {} : { symbol: { qualifiedName: symbol.qualifiedName, ...(symbol.usr === undefined ? {} : { usr: symbol.usr }) } }),\n ...(fact.sourceLanguage === undefined ? {} : { sourceLanguage: fact.sourceLanguage as BridgeSourceLanguage }),\n ...(scoped === undefined ? {} : scoped),\n };\n });\n if (facts.some((fact) => fact.channel === null) && !limitations.some((item) => item.startsWith(rules.unattributed))) {\n fail('Unattributed message handles require a limitation.');\n }\n return { format: 'bridge-facts', version: 2, transport: value.transport, platform: value.platform,\n target: facts.length ? 'flutter' : null, project, generatedAt: value.generatedAt,\n tool: { name: safe(tool.name), version: safe(tool.version) }, facts, limitations: [...limitations] };\n}\n\nfunction object(value: unknown): Record<string, unknown> {\n if (value === null || typeof value !== 'object' || Array.isArray(value)) fail('Message bridge input must be a JSON object.');\n return value as Record<string, unknown>;\n}\nfunction safe(value: unknown): string {\n if (!isSafeNonEmptyString(value)) fail('Invalid message bridge metadata.');\n return value as string;\n}\nfunction fail(message: string): never { throw new BridgeFactsValidationError(message); }\n"]}
|
package/dist/exchange/parse.d.ts
CHANGED
|
@@ -2,6 +2,14 @@
|
|
|
2
2
|
export type BridgePlatform = 'dart' | 'swift' | 'kotlin' | 'js';
|
|
3
3
|
/** 언어 경계를 잇는 메커니즘이다. */
|
|
4
4
|
export type BridgeTarget = 'flutter' | 'react-native' | 'capacitor';
|
|
5
|
+
/**
|
|
6
|
+
* 같은 target 안에서 사실이 통과하는 구체적인 해석 경로다.
|
|
7
|
+
*
|
|
8
|
+
* `react-native` 문서 안에서 코어 RN 경로와 Expo Modules 경로가 공존한다.
|
|
9
|
+
* 생략된 사실은 `core`로 읽는다 — v1 이전 문서가 모두 코어 RN만 기술했기
|
|
10
|
+
* 때문이다. 이 필드는 이름 경계 사실 네 종류에만 허용된다.
|
|
11
|
+
*/
|
|
12
|
+
export type BridgeMechanism = 'core' | 'expo';
|
|
5
13
|
/** Swift 플랫폼 문서에 실린 Objective-C 구현을 Swift 보존 대상과 구분한다. */
|
|
6
14
|
export type BridgeSourceLanguage = 'objective-c';
|
|
7
15
|
/** 특정 한계 전체의 영향을 포함하는 채널 집합. 일부 발견 목록이 아니다. */
|
|
@@ -27,15 +35,55 @@ export interface BridgeSymbol {
|
|
|
27
35
|
readonly qualifiedName: string;
|
|
28
36
|
readonly usr?: string;
|
|
29
37
|
}
|
|
38
|
+
/** producer가 관찰한 사용 관계를 귀속한 실제 native handler 분기 범위다. */
|
|
39
|
+
export interface BridgeHandlerScope {
|
|
40
|
+
readonly start: BridgeLocation;
|
|
41
|
+
readonly end: BridgeLocation;
|
|
42
|
+
readonly complete: boolean;
|
|
43
|
+
}
|
|
44
|
+
/** 실제 참조 위치와 대상, index의 overrides로 확인한 dispatch 후보를 보존한다. */
|
|
45
|
+
export interface BridgeHandlerDependency {
|
|
46
|
+
readonly kind: 'call' | 'reference';
|
|
47
|
+
readonly scope: 'handler' | 'registration';
|
|
48
|
+
readonly location: BridgeLocation;
|
|
49
|
+
readonly symbol: BridgeSymbol & {
|
|
50
|
+
readonly usr: string;
|
|
51
|
+
};
|
|
52
|
+
readonly dispatchTargets?: readonly (BridgeSymbol & {
|
|
53
|
+
readonly usr: string;
|
|
54
|
+
})[];
|
|
55
|
+
}
|
|
56
|
+
/** handler 분기 근거의 원시 상한이다. */
|
|
57
|
+
export declare const MAX_SCOPE_DEPENDENCIES_PER_FACT = 10000;
|
|
58
|
+
export declare const MAX_SCOPE_DEPENDENCIES_PER_DOCUMENT = 1000000;
|
|
30
59
|
/** 생산 도구 하나가 관찰한 언어 경계 사실이다. */
|
|
31
60
|
export interface BridgeFact {
|
|
32
61
|
readonly kind: BridgeFactKind;
|
|
33
62
|
readonly channel: string | null;
|
|
34
63
|
readonly method?: string;
|
|
64
|
+
/**
|
|
65
|
+
* `react-native` target의 이름 경계 사실이 속한 해석 경로다.
|
|
66
|
+
*
|
|
67
|
+
* 생략은 `core`다. Expo의 `requireNativeModule`은 TurboModule 폴백이
|
|
68
|
+
* 있어 호출 측 `expo`가 양쪽 mechanism의 export와 조인되지만,
|
|
69
|
+
* `requireNativeViewManager`에는 그런 폴백이 없다 — 조인 규칙은
|
|
70
|
+
* GRAPH-EXCHANGE.md가 정한다.
|
|
71
|
+
*/
|
|
72
|
+
readonly mechanism?: BridgeMechanism;
|
|
73
|
+
/**
|
|
74
|
+
* 호출 측 API가 모듈 부재를 허용한다는 증거다.
|
|
75
|
+
*
|
|
76
|
+
* `requireOptionalNativeModule`·`TurboModuleRegistry.get` 계열은 부재 시
|
|
77
|
+
* 던지지 않고 `null`을 돌려주므로, 이 표시가 있는 `module-import`의 미수출은
|
|
78
|
+
* 크래시가 아니라 호출자가 감당하는 관찰이다. `module-import`에만 올 수 있다.
|
|
79
|
+
*/
|
|
80
|
+
readonly optional?: boolean;
|
|
35
81
|
readonly dynamic: boolean;
|
|
36
82
|
readonly location: BridgeLocation;
|
|
37
83
|
readonly symbol?: BridgeSymbol;
|
|
38
84
|
readonly sourceLanguage?: BridgeSourceLanguage;
|
|
85
|
+
readonly handlerScope?: BridgeHandlerScope;
|
|
86
|
+
readonly dependencies?: readonly BridgeHandlerDependency[];
|
|
39
87
|
}
|
|
40
88
|
/** bridge-facts 버전 1 문서다. */
|
|
41
89
|
export interface BridgeFactsDocument {
|
|
@@ -60,6 +108,19 @@ export declare class BridgeFactsValidationError extends Error {
|
|
|
60
108
|
}
|
|
61
109
|
/** 신뢰하지 않는 JSON 값을 검증된 bridge-facts v1 문서로 바꾼다. */
|
|
62
110
|
export declare function parseBridgeFactsDocument(input: unknown): BridgeFactsDocument;
|
|
111
|
+
/**
|
|
112
|
+
* v1 `method-handle`과 v2 handler 사실이 공유하는 분기 근거 필드를 검증한다.
|
|
113
|
+
*
|
|
114
|
+
* `handlerScope`는 감싸는 핸들러 선언 안에서 이 사실로 귀속한 분기 범위고,
|
|
115
|
+
* `dependencies`의 `scope`가 그 안(`handler`)인지 공유 부분(`registration`)인지
|
|
116
|
+
* 구분한다. 두 필드는 함께만 올 수 있다.
|
|
117
|
+
*/
|
|
118
|
+
export declare function validateScopeEvidence(fact: Record<string, unknown>, location: BridgeLocation, symbol: BridgeSymbol | undefined, index: number, consumeScopeDependencies: (count: number) => void): void;
|
|
119
|
+
/** 검증된 분기 근거를 계약 필드만 남긴 사본으로 만든다. */
|
|
120
|
+
export declare function normalizeScopeEvidence(handlerScope: BridgeHandlerScope, dependencies: readonly BridgeHandlerDependency[]): {
|
|
121
|
+
handlerScope: BridgeHandlerScope;
|
|
122
|
+
dependencies: BridgeHandlerDependency[];
|
|
123
|
+
};
|
|
63
124
|
/** 브리지 호출 측 사실을 생산하는 플랫폼인지 확인한다. */
|
|
64
125
|
export declare function isCallerPlatform(platform: unknown): platform is 'dart' | 'js';
|
|
65
126
|
/** 브리지 수신 측 사실을 생산하는 플랫폼인지 확인한다. */
|
|
@@ -68,6 +129,14 @@ export declare function isReceiverPlatform(platform: unknown): platform is 'swif
|
|
|
68
129
|
export declare function isBridgeTarget(value: unknown): value is BridgeTarget;
|
|
69
130
|
/** 조인 키를 깨뜨리는 제어 문자가 없는 비어 있지 않은 문자열인지 확인한다. */
|
|
70
131
|
export declare function isSafeNonEmptyString(value: unknown): value is string;
|
|
132
|
+
/** 사실 위치가 상대 경로와 1부터 시작하는 줄·열을 갖는지 검증한다. */
|
|
133
|
+
export declare function validateLocation(value: unknown, index: number): void;
|
|
134
|
+
/** 절대·상위 경로와 제어 문자를 제외한 프로젝트 상대 경로인지 확인한다. */
|
|
135
|
+
export declare function isProjectRelativePath(value: unknown): value is string;
|
|
136
|
+
/** 선택 symbol의 이름과 USR이 비어 있지 않은지 검증한다. */
|
|
137
|
+
export declare function validateSymbol(value: unknown, index: number): void;
|
|
138
|
+
/** 교환 계약별 파서가 Objective-C 출처·경로·실제 Clang 신원 규칙을 공유한다. */
|
|
139
|
+
export declare function validateSourceLanguage(value: unknown, platform: unknown, location: BridgeLocation, symbol: BridgeSymbol | undefined, index: number): void;
|
|
71
140
|
/** ISO 계열 생성 시각으로 해석할 수 있는지 확인한다. */
|
|
72
141
|
export declare function isBridgeTimestamp(value: unknown): value is string;
|
|
73
142
|
/** 배열과 null을 제외한 JSON 객체인지 확인한다. isthmus 소유 문서 검증도 재사용한다. */
|