@intlayer/chokidar 9.0.0-canary.0 → 9.0.0-canary.2
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/dist/assets/initConfig/templates/cjs.txt +2 -2
- package/dist/assets/initConfig/templates/mjs.txt +2 -2
- package/dist/assets/initConfig/templates/ts.txt +2 -2
- package/dist/cjs/docReview/alignBlocks.cjs +79 -0
- package/dist/cjs/docReview/alignBlocks.cjs.map +1 -0
- package/dist/cjs/docReview/computeSimilarity.cjs +42 -0
- package/dist/cjs/docReview/computeSimilarity.cjs.map +1 -0
- package/dist/cjs/docReview/fingerprintBlock.cjs +35 -0
- package/dist/cjs/docReview/fingerprintBlock.cjs.map +1 -0
- package/dist/cjs/docReview/index.cjs +25 -0
- package/dist/cjs/docReview/mapChangedLinesToBlocks.cjs +27 -0
- package/dist/cjs/docReview/mapChangedLinesToBlocks.cjs.map +1 -0
- package/dist/cjs/docReview/normalizeBlock.cjs +34 -0
- package/dist/cjs/docReview/normalizeBlock.cjs.map +1 -0
- package/dist/cjs/docReview/pipeline.cjs +144 -0
- package/dist/cjs/docReview/pipeline.cjs.map +1 -0
- package/dist/cjs/docReview/planActions.cjs +58 -0
- package/dist/cjs/docReview/planActions.cjs.map +1 -0
- package/dist/cjs/docReview/rebuildDocument.cjs +65 -0
- package/dist/cjs/docReview/rebuildDocument.cjs.map +1 -0
- package/dist/cjs/docReview/reviewReport.cjs +200 -0
- package/dist/cjs/docReview/reviewReport.cjs.map +1 -0
- package/dist/cjs/docReview/segmentDocument.cjs +134 -0
- package/dist/cjs/docReview/segmentDocument.cjs.map +1 -0
- package/dist/cjs/docReview/types.cjs +0 -0
- package/dist/cjs/init/index.cjs +46 -17
- package/dist/cjs/init/index.cjs.map +1 -1
- package/dist/cjs/init/utils/fileSystem.cjs +16 -4
- package/dist/cjs/init/utils/fileSystem.cjs.map +1 -1
- package/dist/cjs/init/utils/githubActions.cjs +159 -0
- package/dist/cjs/init/utils/githubActions.cjs.map +1 -0
- package/dist/cjs/init/utils/index.cjs +4 -0
- package/dist/cjs/init/utils/packageManager.cjs +41 -22
- package/dist/cjs/init/utils/packageManager.cjs.map +1 -1
- package/dist/cjs/initConfig/index.cjs +11 -2
- package/dist/cjs/initConfig/index.cjs.map +1 -1
- package/dist/esm/docReview/alignBlocks.mjs +78 -0
- package/dist/esm/docReview/alignBlocks.mjs.map +1 -0
- package/dist/esm/docReview/computeSimilarity.mjs +39 -0
- package/dist/esm/docReview/computeSimilarity.mjs.map +1 -0
- package/dist/esm/docReview/fingerprintBlock.mjs +32 -0
- package/dist/esm/docReview/fingerprintBlock.mjs.map +1 -0
- package/dist/esm/docReview/index.mjs +12 -0
- package/dist/esm/docReview/mapChangedLinesToBlocks.mjs +25 -0
- package/dist/esm/docReview/mapChangedLinesToBlocks.mjs.map +1 -0
- package/dist/esm/docReview/normalizeBlock.mjs +32 -0
- package/dist/esm/docReview/normalizeBlock.mjs.map +1 -0
- package/dist/esm/docReview/pipeline.mjs +142 -0
- package/dist/esm/docReview/pipeline.mjs.map +1 -0
- package/dist/esm/docReview/planActions.mjs +56 -0
- package/dist/esm/docReview/planActions.mjs.map +1 -0
- package/dist/esm/docReview/rebuildDocument.mjs +62 -0
- package/dist/esm/docReview/rebuildDocument.mjs.map +1 -0
- package/dist/esm/docReview/reviewReport.mjs +196 -0
- package/dist/esm/docReview/reviewReport.mjs.map +1 -0
- package/dist/esm/docReview/segmentDocument.mjs +131 -0
- package/dist/esm/docReview/segmentDocument.mjs.map +1 -0
- package/dist/esm/docReview/types.mjs +0 -0
- package/dist/esm/init/index.mjs +46 -17
- package/dist/esm/init/index.mjs.map +1 -1
- package/dist/esm/init/utils/fileSystem.mjs +16 -4
- package/dist/esm/init/utils/fileSystem.mjs.map +1 -1
- package/dist/esm/init/utils/githubActions.mjs +155 -0
- package/dist/esm/init/utils/githubActions.mjs.map +1 -0
- package/dist/esm/init/utils/index.mjs +2 -1
- package/dist/esm/init/utils/packageManager.mjs +41 -22
- package/dist/esm/init/utils/packageManager.mjs.map +1 -1
- package/dist/esm/initConfig/index.mjs +11 -2
- package/dist/esm/initConfig/index.mjs.map +1 -1
- package/dist/types/docReview/alignBlocks.d.ts +18 -0
- package/dist/types/docReview/alignBlocks.d.ts.map +1 -0
- package/dist/types/docReview/computeSimilarity.d.ts +22 -0
- package/dist/types/docReview/computeSimilarity.d.ts.map +1 -0
- package/dist/types/docReview/fingerprintBlock.d.ts +18 -0
- package/dist/types/docReview/fingerprintBlock.d.ts.map +1 -0
- package/dist/types/docReview/index.d.ts +12 -0
- package/dist/types/docReview/mapChangedLinesToBlocks.d.ts +15 -0
- package/dist/types/docReview/mapChangedLinesToBlocks.d.ts.map +1 -0
- package/dist/types/docReview/normalizeBlock.d.ts +18 -0
- package/dist/types/docReview/normalizeBlock.d.ts.map +1 -0
- package/dist/types/docReview/pipeline.d.ts +46 -0
- package/dist/types/docReview/pipeline.d.ts.map +1 -0
- package/dist/types/docReview/planActions.d.ts +18 -0
- package/dist/types/docReview/planActions.d.ts.map +1 -0
- package/dist/types/docReview/rebuildDocument.d.ts +46 -0
- package/dist/types/docReview/rebuildDocument.d.ts.map +1 -0
- package/dist/types/docReview/reviewReport.d.ts +82 -0
- package/dist/types/docReview/reviewReport.d.ts.map +1 -0
- package/dist/types/docReview/segmentDocument.d.ts +40 -0
- package/dist/types/docReview/segmentDocument.d.ts.map +1 -0
- package/dist/types/docReview/types.d.ts +73 -0
- package/dist/types/docReview/types.d.ts.map +1 -0
- package/dist/types/formatDictionary.d.ts +2 -3
- package/dist/types/formatDictionary.d.ts.map +1 -1
- package/dist/types/init/index.d.ts +2 -1
- package/dist/types/init/index.d.ts.map +1 -1
- package/dist/types/init/utils/fileSystem.d.ts +4 -0
- package/dist/types/init/utils/fileSystem.d.ts.map +1 -1
- package/dist/types/init/utils/githubActions.d.ts +19 -0
- package/dist/types/init/utils/githubActions.d.ts.map +1 -0
- package/dist/types/init/utils/index.d.ts +2 -1
- package/dist/types/init/utils/packageManager.d.ts +3 -2
- package/dist/types/init/utils/packageManager.d.ts.map +1 -1
- package/dist/types/initConfig/index.d.ts +1 -1
- package/dist/types/initConfig/index.d.ts.map +1 -1
- package/package.json +17 -9
- package/dist/types/intlayer/dist/types/index.d.ts +0 -4
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rebuildDocument.cjs","names":[],"sources":["../../../src/docReview/rebuildDocument.ts"],"sourcesContent":["import type { AlignmentPlan, FingerprintedBlock } from './types';\n\n/**\n * A block that needs to be translated or re-translated by an external consumer\n * (an AI client, a human, or an agent).\n */\nexport type SegmentToReview = {\n /** The base block to translate. */\n baseBlock: FingerprintedBlock;\n /** Existing target translation, or `null` when the block is new. */\n targetBlockText: string | null;\n /** Index of the originating action within {@link AlignmentPlan.actions}. */\n actionIndex: number;\n};\n\nexport type RebuildInput = {\n baseBlocks: FingerprintedBlock[];\n targetBlocks: FingerprintedBlock[];\n plan: AlignmentPlan;\n};\n\nexport type RebuildResult = {\n segmentsToReview: SegmentToReview[];\n};\n\n/**\n * Analyze the alignment plan and return only the segments that need\n * review/translation. Does not generate output text - that is done by\n * {@link mergeReviewedSegments} once the translations are available.\n *\n * @param input - The base/target blocks and the alignment plan.\n * @returns The list of segments that require translation.\n */\nexport const identifySegmentsToReview = ({\n baseBlocks,\n targetBlocks,\n plan,\n}: RebuildInput): RebuildResult => {\n const segmentsToReview: SegmentToReview[] = [];\n\n plan.actions.forEach((action, actionIndex) => {\n if (action.kind === 'review') {\n const baseBlock = baseBlocks[action.baseIndex];\n const targetBlockText =\n action.targetIndex !== null\n ? targetBlocks[action.targetIndex].content\n : null;\n\n segmentsToReview.push({ baseBlock, targetBlockText, actionIndex });\n } else if (action.kind === 'insert_new') {\n const baseBlock = baseBlocks[action.baseIndex];\n\n segmentsToReview.push({\n baseBlock,\n targetBlockText: null,\n actionIndex,\n });\n }\n });\n\n return { segmentsToReview };\n};\n\n/**\n * Merge reviewed translations back into the final document following the\n * alignment plan, reusing untouched target blocks as-is.\n *\n * @param plan - The alignment plan.\n * @param targetBlocks - Blocks of the existing target document.\n * @param reviewedSegments - Map of action index to its reviewed translation.\n * @returns The rebuilt target document.\n */\nexport const mergeReviewedSegments = (\n plan: AlignmentPlan,\n targetBlocks: FingerprintedBlock[],\n reviewedSegments: Map<number, string>\n): string => {\n const outputParts: string[] = [];\n\n plan.actions.forEach((action, actionIndex) => {\n if (action.kind === 'reuse') {\n outputParts.push(targetBlocks[action.targetIndex].content);\n } else if (action.kind === 'review' || action.kind === 'insert_new') {\n const reviewedContent = reviewedSegments.get(actionIndex);\n\n if (reviewedContent !== undefined) {\n outputParts.push(reviewedContent);\n } else {\n // Fallback: if review failed, use existing or blank\n if (action.kind === 'review' && action.targetIndex !== null) {\n outputParts.push(targetBlocks[action.targetIndex].content);\n } else {\n outputParts.push('\\n');\n }\n }\n } else if (action.kind === 'delete') {\n const reviewedContent = reviewedSegments.get(actionIndex);\n if (reviewedContent !== undefined) {\n // Caller explicitly resolved this block: empty string = actually delete,\n // non-empty string = replacement content.\n if (reviewedContent) outputParts.push(reviewedContent);\n } else {\n // Default: keep verbatim. A target block with no base counterpart may\n // just be a section the aligner could not follow (reordering, split\n // prose) — keeping it prevents accidental data loss in log/read-only mode.\n outputParts.push(targetBlocks[action.targetIndex].content);\n }\n }\n });\n\n return outputParts.join('');\n};\n"],"mappings":";;;;;;;;;;;AAiCA,MAAa,4BAA4B,EACvC,YACA,cACA,WACiC;CACjC,MAAM,mBAAsC,EAAE;AAE9C,MAAK,QAAQ,SAAS,QAAQ,gBAAgB;AAC5C,MAAI,OAAO,SAAS,UAAU;GAC5B,MAAM,YAAY,WAAW,OAAO;GACpC,MAAM,kBACJ,OAAO,gBAAgB,OACnB,aAAa,OAAO,aAAa,UACjC;AAEN,oBAAiB,KAAK;IAAE;IAAW;IAAiB;IAAa,CAAC;aACzD,OAAO,SAAS,cAAc;GACvC,MAAM,YAAY,WAAW,OAAO;AAEpC,oBAAiB,KAAK;IACpB;IACA,iBAAiB;IACjB;IACD,CAAC;;GAEJ;AAEF,QAAO,EAAE,kBAAkB;;;;;;;;;;;AAY7B,MAAa,yBACX,MACA,cACA,qBACW;CACX,MAAM,cAAwB,EAAE;AAEhC,MAAK,QAAQ,SAAS,QAAQ,gBAAgB;AAC5C,MAAI,OAAO,SAAS,QAClB,aAAY,KAAK,aAAa,OAAO,aAAa,QAAQ;WACjD,OAAO,SAAS,YAAY,OAAO,SAAS,cAAc;GACnE,MAAM,kBAAkB,iBAAiB,IAAI,YAAY;AAEzD,OAAI,oBAAoB,OACtB,aAAY,KAAK,gBAAgB;YAG7B,OAAO,SAAS,YAAY,OAAO,gBAAgB,KACrD,aAAY,KAAK,aAAa,OAAO,aAAa,QAAQ;OAE1D,aAAY,KAAK,KAAK;aAGjB,OAAO,SAAS,UAAU;GACnC,MAAM,kBAAkB,iBAAiB,IAAI,YAAY;AACzD,OAAI,oBAAoB,QAGtB;QAAI,gBAAiB,aAAY,KAAK,gBAAgB;SAKtD,aAAY,KAAK,aAAa,OAAO,aAAa,QAAQ;;GAG9D;AAEF,QAAO,YAAY,KAAK,GAAG"}
|
|
@@ -0,0 +1,200 @@
|
|
|
1
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
|
|
2
|
+
const require_runtime = require('../_virtual/_rolldown/runtime.cjs');
|
|
3
|
+
const require_docReview_pipeline = require('./pipeline.cjs');
|
|
4
|
+
let _intlayer_config_logger = require("@intlayer/config/logger");
|
|
5
|
+
let _intlayer_config_colors = require("@intlayer/config/colors");
|
|
6
|
+
_intlayer_config_colors = require_runtime.__toESM(_intlayer_config_colors);
|
|
7
|
+
|
|
8
|
+
//#region src/docReview/reviewReport.ts
|
|
9
|
+
/**
|
|
10
|
+
* Compare a base markdown document with its translation and report only the
|
|
11
|
+
* blocks that need attention, with their line ranges and content.
|
|
12
|
+
*
|
|
13
|
+
* Reusable across the CLI (`doc review --log`), the backend (comparing two
|
|
14
|
+
* translation contents stored in database), and agents that generate the
|
|
15
|
+
* missing translations.
|
|
16
|
+
*
|
|
17
|
+
* @param input - The base/target texts and optional changed lines.
|
|
18
|
+
* @returns The divergent blocks and a per-action summary.
|
|
19
|
+
*/
|
|
20
|
+
const buildReviewReport = ({ baseText, targetText, changedLines }) => {
|
|
21
|
+
const { baseBlocks, targetBlocks, plan } = require_docReview_pipeline.buildAlignmentPlan({
|
|
22
|
+
baseText,
|
|
23
|
+
targetText,
|
|
24
|
+
changedLines
|
|
25
|
+
});
|
|
26
|
+
const summary = {
|
|
27
|
+
reuse: 0,
|
|
28
|
+
review: 0,
|
|
29
|
+
insertNew: 0,
|
|
30
|
+
delete: 0
|
|
31
|
+
};
|
|
32
|
+
const blocks = [];
|
|
33
|
+
for (const [actionIndex, action] of plan.actions.entries()) {
|
|
34
|
+
if (action.kind === "reuse") {
|
|
35
|
+
summary.reuse += 1;
|
|
36
|
+
continue;
|
|
37
|
+
}
|
|
38
|
+
if (action.kind === "review") {
|
|
39
|
+
summary.review += 1;
|
|
40
|
+
const baseBlock = baseBlocks[action.baseIndex];
|
|
41
|
+
if (!baseBlock) continue;
|
|
42
|
+
const targetBlock = action.targetIndex !== null ? targetBlocks[action.targetIndex] : null;
|
|
43
|
+
blocks.push({
|
|
44
|
+
action: "review",
|
|
45
|
+
baseLineRange: {
|
|
46
|
+
start: baseBlock.lineStart,
|
|
47
|
+
end: baseBlock.lineEnd
|
|
48
|
+
},
|
|
49
|
+
targetLineRange: targetBlock ? {
|
|
50
|
+
start: targetBlock.lineStart,
|
|
51
|
+
end: targetBlock.lineEnd
|
|
52
|
+
} : void 0,
|
|
53
|
+
baseContent: baseBlock.content,
|
|
54
|
+
targetContent: targetBlock?.content
|
|
55
|
+
});
|
|
56
|
+
continue;
|
|
57
|
+
}
|
|
58
|
+
if (action.kind === "insert_new") {
|
|
59
|
+
summary.insertNew += 1;
|
|
60
|
+
const baseBlock = baseBlocks[action.baseIndex];
|
|
61
|
+
if (!baseBlock) continue;
|
|
62
|
+
let insertAfterLine;
|
|
63
|
+
for (let prevIndex = actionIndex - 1; prevIndex >= 0; prevIndex--) {
|
|
64
|
+
const prevAction = plan.actions[prevIndex];
|
|
65
|
+
if (!prevAction) continue;
|
|
66
|
+
let targetIdx = null;
|
|
67
|
+
if (prevAction.kind === "reuse") targetIdx = prevAction.targetIndex;
|
|
68
|
+
else if (prevAction.kind === "review" && prevAction.targetIndex !== null) targetIdx = prevAction.targetIndex;
|
|
69
|
+
else if (prevAction.kind === "delete") targetIdx = prevAction.targetIndex;
|
|
70
|
+
if (targetIdx !== null) {
|
|
71
|
+
const prevTargetBlock = targetBlocks[targetIdx];
|
|
72
|
+
if (prevTargetBlock) {
|
|
73
|
+
insertAfterLine = prevTargetBlock.lineEnd + 1;
|
|
74
|
+
break;
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
blocks.push({
|
|
79
|
+
action: "insert_new",
|
|
80
|
+
baseLineRange: {
|
|
81
|
+
start: baseBlock.lineStart,
|
|
82
|
+
end: baseBlock.lineEnd
|
|
83
|
+
},
|
|
84
|
+
targetLineRange: insertAfterLine !== void 0 ? {
|
|
85
|
+
start: insertAfterLine,
|
|
86
|
+
end: insertAfterLine
|
|
87
|
+
} : void 0,
|
|
88
|
+
baseContent: baseBlock.content
|
|
89
|
+
});
|
|
90
|
+
continue;
|
|
91
|
+
}
|
|
92
|
+
if (action.kind === "delete") {
|
|
93
|
+
summary.delete += 1;
|
|
94
|
+
const targetBlock = targetBlocks[action.targetIndex];
|
|
95
|
+
if (!targetBlock) continue;
|
|
96
|
+
blocks.push({
|
|
97
|
+
action: "delete",
|
|
98
|
+
targetLineRange: {
|
|
99
|
+
start: targetBlock.lineStart,
|
|
100
|
+
end: targetBlock.lineEnd
|
|
101
|
+
},
|
|
102
|
+
targetContent: targetBlock.content
|
|
103
|
+
});
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
return {
|
|
107
|
+
blocks,
|
|
108
|
+
summary
|
|
109
|
+
};
|
|
110
|
+
};
|
|
111
|
+
/** Render a line range as a blue colored string, or an orange dash when absent. */
|
|
112
|
+
const colorizeLineRange = (range) => {
|
|
113
|
+
if (!range) return (0, _intlayer_config_logger.colorize)("—", _intlayer_config_colors.ORANGE);
|
|
114
|
+
return (0, _intlayer_config_logger.colorize)(range.start === range.end ? `L${range.start}` : `L${range.start}-${range.end}`, _intlayer_config_colors.BLUE);
|
|
115
|
+
};
|
|
116
|
+
/**
|
|
117
|
+
* Colorize a count with green when zero (nothing to do) and a caller-supplied
|
|
118
|
+
* non-zero color (orange for warnings, red for destructive actions).
|
|
119
|
+
*/
|
|
120
|
+
const colorizeCount = (count, nonZeroColor) => (0, _intlayer_config_logger.colorizeNumber)(count, {
|
|
121
|
+
zero: _intlayer_config_colors.GREEN,
|
|
122
|
+
one: nonZeroColor,
|
|
123
|
+
two: nonZeroColor,
|
|
124
|
+
few: nonZeroColor,
|
|
125
|
+
many: nonZeroColor,
|
|
126
|
+
other: nonZeroColor
|
|
127
|
+
});
|
|
128
|
+
/**
|
|
129
|
+
* Render a {@link ReviewReport} as a human and agent readable log.
|
|
130
|
+
*
|
|
131
|
+
* Each divergent block is printed with its action, the base/target line ranges,
|
|
132
|
+
* the base content to translate, and the existing translation to update.
|
|
133
|
+
*
|
|
134
|
+
* @param report - The report to format.
|
|
135
|
+
* @param options - Optional labels for the base and target locales.
|
|
136
|
+
* @returns A multi-line string describing every block that needs attention.
|
|
137
|
+
*/
|
|
138
|
+
const formatReviewReport = (report, options) => {
|
|
139
|
+
const baseLabel = options?.baseLabel ?? "base";
|
|
140
|
+
const targetLabel = options?.targetLabel ?? "target";
|
|
141
|
+
const { summary, blocks } = report;
|
|
142
|
+
const header = [
|
|
143
|
+
(0, _intlayer_config_logger.colorize)("Review report: ", _intlayer_config_colors.ORANGE),
|
|
144
|
+
colorizeCount(blocks.length, _intlayer_config_colors.ORANGE),
|
|
145
|
+
(0, _intlayer_config_logger.colorize)(" block(s) need attention (review=", _intlayer_config_colors.ORANGE),
|
|
146
|
+
colorizeCount(summary.review, _intlayer_config_colors.ORANGE),
|
|
147
|
+
(0, _intlayer_config_logger.colorize)(", new=", _intlayer_config_colors.ORANGE),
|
|
148
|
+
colorizeCount(summary.insertNew, _intlayer_config_colors.ORANGE),
|
|
149
|
+
(0, _intlayer_config_logger.colorize)(", delete=", _intlayer_config_colors.ORANGE),
|
|
150
|
+
colorizeCount(summary.delete, _intlayer_config_colors.RED),
|
|
151
|
+
(0, _intlayer_config_logger.colorize)(", reuse=", _intlayer_config_colors.ORANGE),
|
|
152
|
+
(0, _intlayer_config_logger.colorizeNumber)(summary.reuse),
|
|
153
|
+
(0, _intlayer_config_logger.colorize)(").", _intlayer_config_colors.ORANGE)
|
|
154
|
+
].join("");
|
|
155
|
+
if (blocks.length === 0) return `${header}\n${(0, _intlayer_config_logger.colorize)("No changes needed.", _intlayer_config_colors.GREEN)}`;
|
|
156
|
+
const sections = blocks.map((block, index) => {
|
|
157
|
+
const lines = [];
|
|
158
|
+
const blockHeader = [
|
|
159
|
+
(0, _intlayer_config_logger.colorize)("--- Block ", _intlayer_config_colors.ORANGE),
|
|
160
|
+
(0, _intlayer_config_logger.colorizeNumber)(index + 1),
|
|
161
|
+
(0, _intlayer_config_logger.colorize)("/", _intlayer_config_colors.ORANGE),
|
|
162
|
+
(0, _intlayer_config_logger.colorizeNumber)(blocks.length),
|
|
163
|
+
(0, _intlayer_config_logger.colorize)(` [${block.action}] `, _intlayer_config_colors.ORANGE),
|
|
164
|
+
baseLabel,
|
|
165
|
+
(0, _intlayer_config_logger.colorize)(" ", _intlayer_config_colors.ORANGE),
|
|
166
|
+
colorizeLineRange(block.baseLineRange),
|
|
167
|
+
(0, _intlayer_config_logger.colorize)(" → ", _intlayer_config_colors.ORANGE),
|
|
168
|
+
targetLabel,
|
|
169
|
+
(0, _intlayer_config_logger.colorize)(" ", _intlayer_config_colors.ORANGE),
|
|
170
|
+
colorizeLineRange(block.targetLineRange),
|
|
171
|
+
(0, _intlayer_config_logger.colorize)(" ---", _intlayer_config_colors.ORANGE)
|
|
172
|
+
].join("");
|
|
173
|
+
lines.push(blockHeader);
|
|
174
|
+
if (block.baseContent !== void 0) {
|
|
175
|
+
lines.push((0, _intlayer_config_logger.colorize)(`[${baseLabel}]`, _intlayer_config_colors.BEIGE));
|
|
176
|
+
lines.push((0, _intlayer_config_logger.colorize)(block.baseContent.trimEnd(), _intlayer_config_colors.GREY));
|
|
177
|
+
}
|
|
178
|
+
if (block.targetContent !== void 0) {
|
|
179
|
+
lines.push((0, _intlayer_config_logger.colorize)(`[${targetLabel}]`, _intlayer_config_colors.BEIGE));
|
|
180
|
+
lines.push((0, _intlayer_config_logger.colorize)(block.targetContent.trimEnd(), _intlayer_config_colors.GREY));
|
|
181
|
+
} else if (block.action === "insert_new") {
|
|
182
|
+
lines.push((0, _intlayer_config_logger.colorize)(`[${targetLabel}]`, _intlayer_config_colors.BEIGE));
|
|
183
|
+
lines.push((0, _intlayer_config_logger.colorize)("(missing — to be translated)", _intlayer_config_colors.ORANGE));
|
|
184
|
+
}
|
|
185
|
+
return lines.join("\n");
|
|
186
|
+
});
|
|
187
|
+
const editingNote = (0, _intlayer_config_logger.colorize)("Tip: start editing from the last block — working bottom-up keeps earlier line numbers accurate.", _intlayer_config_colors.GREY);
|
|
188
|
+
return [
|
|
189
|
+
header,
|
|
190
|
+
"",
|
|
191
|
+
...sections,
|
|
192
|
+
"",
|
|
193
|
+
editingNote
|
|
194
|
+
].join("\n");
|
|
195
|
+
};
|
|
196
|
+
|
|
197
|
+
//#endregion
|
|
198
|
+
exports.buildReviewReport = buildReviewReport;
|
|
199
|
+
exports.formatReviewReport = formatReviewReport;
|
|
200
|
+
//# sourceMappingURL=reviewReport.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"reviewReport.cjs","names":["buildAlignmentPlan","ANSIColors"],"sources":["../../../src/docReview/reviewReport.ts"],"sourcesContent":["import * as ANSIColors from '@intlayer/config/colors';\nimport { colorize, colorizeNumber } from '@intlayer/config/logger';\nimport { buildAlignmentPlan } from './pipeline';\n\n/**\n * The kind of change detected for a block when reviewing a translation against\n * its base document.\n *\n * - `review`: the base block changed and its translation must be updated.\n * - `insert_new`: the base block has no translation yet and must be added.\n * - `delete`: the target block no longer exists in the base and should be removed.\n */\nexport type ReviewBlockAction = 'review' | 'insert_new' | 'delete';\n\n/** A 1-based, inclusive line range within a document. */\nexport type LineRange = {\n start: number;\n end: number;\n};\n\n/**\n * A single block that diverges between the base document and its translation.\n *\n * This is the unit an external translator (AI client, human, or agent) needs to\n * act on: it carries the base content to translate, the existing translation to\n * update, and where each lives so the change can be located in the file.\n */\nexport type ReviewReportBlock = {\n /** What should happen to this block. */\n action: ReviewBlockAction;\n /** Line range of the block in the base document (omitted for pure deletions). */\n baseLineRange?: LineRange;\n /** Line range of the block in the target document (omitted for new insertions). */\n targetLineRange?: LineRange;\n /** Raw markdown of the base block (omitted for pure deletions). */\n baseContent?: string;\n /** Existing translation of the block (omitted for new insertions). */\n targetContent?: string;\n};\n\nexport type ReviewReportSummary = {\n /** Number of blocks reused as-is (unchanged translation). */\n reuse: number;\n /** Number of blocks whose translation must be updated. */\n review: number;\n /** Number of blocks missing a translation. */\n insertNew: number;\n /** Number of stale target blocks to delete. */\n delete: number;\n};\n\nexport type ReviewReport = {\n /** Only the blocks that diverge (review, insert_new, delete). */\n blocks: ReviewReportBlock[];\n /** Counts per action over the whole document, including reused blocks. */\n summary: ReviewReportSummary;\n};\n\nexport type BuildReviewReportInput = {\n /** The base (source) document, used as the translation reference. */\n baseText: string;\n /** The existing target (translated) document, possibly empty. */\n targetText: string;\n /**\n * 1-based line numbers that changed in the base document. When omitted, only\n * inserted and deleted blocks are reported (no aligned block is flagged for\n * review since there is no way to know which ones changed).\n */\n changedLines?: number[];\n};\n\n/**\n * Compare a base markdown document with its translation and report only the\n * blocks that need attention, with their line ranges and content.\n *\n * Reusable across the CLI (`doc review --log`), the backend (comparing two\n * translation contents stored in database), and agents that generate the\n * missing translations.\n *\n * @param input - The base/target texts and optional changed lines.\n * @returns The divergent blocks and a per-action summary.\n */\nexport const buildReviewReport = ({\n baseText,\n targetText,\n changedLines,\n}: BuildReviewReportInput): ReviewReport => {\n const { baseBlocks, targetBlocks, plan } = buildAlignmentPlan({\n baseText,\n targetText,\n changedLines,\n });\n\n const summary: ReviewReportSummary = {\n reuse: 0,\n review: 0,\n insertNew: 0,\n delete: 0,\n };\n\n const blocks: ReviewReportBlock[] = [];\n\n for (const [actionIndex, action] of plan.actions.entries()) {\n if (action.kind === 'reuse') {\n summary.reuse += 1;\n continue;\n }\n\n if (action.kind === 'review') {\n summary.review += 1;\n const baseBlock = baseBlocks[action.baseIndex];\n\n if (!baseBlock) continue;\n\n const targetBlock =\n action.targetIndex !== null ? targetBlocks[action.targetIndex] : null;\n\n blocks.push({\n action: 'review',\n baseLineRange: { start: baseBlock.lineStart, end: baseBlock.lineEnd },\n targetLineRange: targetBlock\n ? { start: targetBlock.lineStart, end: targetBlock.lineEnd }\n : undefined,\n baseContent: baseBlock.content,\n targetContent: targetBlock?.content,\n });\n continue;\n }\n\n if (action.kind === 'insert_new') {\n summary.insertNew += 1;\n const baseBlock = baseBlocks[action.baseIndex];\n\n if (!baseBlock) continue;\n\n // Find the target line after which the new block should be inserted:\n // scan backwards for the last action that produced a target block.\n let insertAfterLine: number | undefined;\n for (let prevIndex = actionIndex - 1; prevIndex >= 0; prevIndex--) {\n const prevAction = plan.actions[prevIndex];\n if (!prevAction) continue;\n\n let targetIdx: number | null = null;\n if (prevAction.kind === 'reuse') targetIdx = prevAction.targetIndex;\n else if (\n prevAction.kind === 'review' &&\n prevAction.targetIndex !== null\n )\n targetIdx = prevAction.targetIndex;\n else if (prevAction.kind === 'delete')\n targetIdx = prevAction.targetIndex;\n\n if (targetIdx !== null) {\n const prevTargetBlock = targetBlocks[targetIdx];\n if (prevTargetBlock) {\n insertAfterLine = prevTargetBlock.lineEnd + 1;\n break;\n }\n }\n }\n\n blocks.push({\n action: 'insert_new',\n baseLineRange: { start: baseBlock.lineStart, end: baseBlock.lineEnd },\n targetLineRange:\n insertAfterLine !== undefined\n ? { start: insertAfterLine, end: insertAfterLine }\n : undefined,\n baseContent: baseBlock.content,\n });\n continue;\n }\n\n if (action.kind === 'delete') {\n summary.delete += 1;\n const targetBlock = targetBlocks[action.targetIndex];\n\n if (!targetBlock) continue;\n\n blocks.push({\n action: 'delete',\n targetLineRange: {\n start: targetBlock.lineStart,\n end: targetBlock.lineEnd,\n },\n targetContent: targetBlock.content,\n });\n }\n }\n\n return { blocks, summary };\n};\n\n/** Render a line range as a blue colored string, or an orange dash when absent. */\nconst colorizeLineRange = (range?: LineRange): string => {\n if (!range) return colorize('—', ANSIColors.ORANGE);\n const rangeStr =\n range.start === range.end\n ? `L${range.start}`\n : `L${range.start}-${range.end}`;\n return colorize(rangeStr, ANSIColors.BLUE);\n};\n\n/**\n * Colorize a count with green when zero (nothing to do) and a caller-supplied\n * non-zero color (orange for warnings, red for destructive actions).\n */\nconst colorizeCount = (\n count: number,\n nonZeroColor: (typeof ANSIColors)[keyof typeof ANSIColors]\n): string =>\n colorizeNumber(count, {\n zero: ANSIColors.GREEN,\n one: nonZeroColor,\n two: nonZeroColor,\n few: nonZeroColor,\n many: nonZeroColor,\n other: nonZeroColor,\n });\n\n/**\n * Render a {@link ReviewReport} as a human and agent readable log.\n *\n * Each divergent block is printed with its action, the base/target line ranges,\n * the base content to translate, and the existing translation to update.\n *\n * @param report - The report to format.\n * @param options - Optional labels for the base and target locales.\n * @returns A multi-line string describing every block that needs attention.\n */\nexport const formatReviewReport = (\n report: ReviewReport,\n options?: { baseLabel?: string; targetLabel?: string }\n): string => {\n const baseLabel = options?.baseLabel ?? 'base';\n const targetLabel = options?.targetLabel ?? 'target';\n\n const { summary, blocks } = report;\n\n // Build the summary header piece-by-piece so each count uses its own color.\n const header = [\n colorize('Review report: ', ANSIColors.ORANGE),\n colorizeCount(blocks.length, ANSIColors.ORANGE),\n colorize(' block(s) need attention (review=', ANSIColors.ORANGE),\n colorizeCount(summary.review, ANSIColors.ORANGE),\n colorize(', new=', ANSIColors.ORANGE),\n colorizeCount(summary.insertNew, ANSIColors.ORANGE),\n colorize(', delete=', ANSIColors.ORANGE),\n colorizeCount(summary.delete, ANSIColors.RED),\n colorize(', reuse=', ANSIColors.ORANGE),\n colorizeNumber(summary.reuse),\n colorize(').', ANSIColors.ORANGE),\n ].join('');\n\n if (blocks.length === 0) {\n return `${header}\\n${colorize('No changes needed.', ANSIColors.GREEN)}`;\n }\n\n const sections = blocks.map((block, index) => {\n const lines: string[] = [];\n\n // Block header: each token colored individually.\n const blockHeader = [\n colorize('--- Block ', ANSIColors.ORANGE),\n colorizeNumber(index + 1),\n colorize('/', ANSIColors.ORANGE),\n colorizeNumber(blocks.length),\n colorize(` [${block.action}] `, ANSIColors.ORANGE),\n baseLabel,\n colorize(' ', ANSIColors.ORANGE),\n colorizeLineRange(block.baseLineRange),\n colorize(' → ', ANSIColors.ORANGE),\n targetLabel,\n colorize(' ', ANSIColors.ORANGE),\n colorizeLineRange(block.targetLineRange),\n colorize(' ---', ANSIColors.ORANGE),\n ].join('');\n\n lines.push(blockHeader);\n\n if (block.baseContent !== undefined) {\n lines.push(colorize(`[${baseLabel}]`, ANSIColors.BEIGE));\n lines.push(colorize(block.baseContent.trimEnd(), ANSIColors.GREY));\n }\n\n if (block.targetContent !== undefined) {\n lines.push(colorize(`[${targetLabel}]`, ANSIColors.BEIGE));\n lines.push(colorize(block.targetContent.trimEnd(), ANSIColors.GREY));\n } else if (block.action === 'insert_new') {\n lines.push(colorize(`[${targetLabel}]`, ANSIColors.BEIGE));\n lines.push(colorize('(missing — to be translated)', ANSIColors.ORANGE));\n }\n\n return lines.join('\\n');\n });\n\n const editingNote = colorize(\n 'Tip: start editing from the last block — working bottom-up keeps earlier line numbers accurate.',\n ANSIColors.GREY\n );\n\n return [header, '', ...sections, '', editingNote].join('\\n');\n};\n"],"mappings":"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"}
|
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
|
|
2
|
+
|
|
3
|
+
//#region src/docReview/segmentDocument.ts
|
|
4
|
+
const isBlankLine = (line) => line.trim().length === 0;
|
|
5
|
+
const isFencedCodeDelimiter = (line) => /^\s*```/.test(line);
|
|
6
|
+
const isHeading = (line) => /^\s*#{1,6}\s+/.test(line);
|
|
7
|
+
const isFrontmatterDelimiter = (line) => /^\s*---\s*$/.test(line);
|
|
8
|
+
/**
|
|
9
|
+
* Split a markdown document into fine-grained blocks.
|
|
10
|
+
*
|
|
11
|
+
* Boundaries are drawn at headings, blank lines (paragraph breaks) and fenced
|
|
12
|
+
* code blocks, while frontmatter and the inside of code fences are kept intact.
|
|
13
|
+
* Each blank-line run is appended to the block that precedes it, so the blocks
|
|
14
|
+
* form an exact partition of the document: concatenating every `content` (in
|
|
15
|
+
* order) yields the original text unchanged. This is what lets the block-aware
|
|
16
|
+
* review re-translate only the paragraphs/snippets that actually changed instead
|
|
17
|
+
* of the whole heading section.
|
|
18
|
+
*
|
|
19
|
+
* @param text - The full markdown document.
|
|
20
|
+
* @returns The ordered list of blocks with their 1-based line ranges.
|
|
21
|
+
*/
|
|
22
|
+
const segmentDocument = (text) => {
|
|
23
|
+
const lines = text.split("\n");
|
|
24
|
+
const lineCount = lines.length;
|
|
25
|
+
const units = [];
|
|
26
|
+
let index = 0;
|
|
27
|
+
while (index < lineCount) {
|
|
28
|
+
const currentLine = lines[index];
|
|
29
|
+
if (isBlankLine(currentLine)) {
|
|
30
|
+
index += 1;
|
|
31
|
+
continue;
|
|
32
|
+
}
|
|
33
|
+
if (units.length === 0 && isFrontmatterDelimiter(currentLine)) {
|
|
34
|
+
const startIndex = index;
|
|
35
|
+
index += 1;
|
|
36
|
+
while (index < lineCount && !isFrontmatterDelimiter(lines[index])) index += 1;
|
|
37
|
+
if (index < lineCount) index += 1;
|
|
38
|
+
units.push({
|
|
39
|
+
type: "unknown",
|
|
40
|
+
startIndex,
|
|
41
|
+
endIndex: index - 1
|
|
42
|
+
});
|
|
43
|
+
continue;
|
|
44
|
+
}
|
|
45
|
+
if (isFencedCodeDelimiter(currentLine)) {
|
|
46
|
+
const startIndex = index;
|
|
47
|
+
index += 1;
|
|
48
|
+
while (index < lineCount && !isFencedCodeDelimiter(lines[index])) index += 1;
|
|
49
|
+
if (index < lineCount) index += 1;
|
|
50
|
+
units.push({
|
|
51
|
+
type: "code_block",
|
|
52
|
+
startIndex,
|
|
53
|
+
endIndex: index - 1
|
|
54
|
+
});
|
|
55
|
+
continue;
|
|
56
|
+
}
|
|
57
|
+
if (isHeading(currentLine)) {
|
|
58
|
+
units.push({
|
|
59
|
+
type: "heading",
|
|
60
|
+
startIndex: index,
|
|
61
|
+
endIndex: index
|
|
62
|
+
});
|
|
63
|
+
index += 1;
|
|
64
|
+
continue;
|
|
65
|
+
}
|
|
66
|
+
const startIndex = index;
|
|
67
|
+
while (index < lineCount && !isBlankLine(lines[index]) && !isHeading(lines[index]) && !isFencedCodeDelimiter(lines[index])) index += 1;
|
|
68
|
+
units.push({
|
|
69
|
+
type: "paragraph",
|
|
70
|
+
startIndex,
|
|
71
|
+
endIndex: index - 1
|
|
72
|
+
});
|
|
73
|
+
}
|
|
74
|
+
if (units.length === 0) return [];
|
|
75
|
+
return units.map((unit, unitIndex) => {
|
|
76
|
+
const blockStartIndex = unitIndex === 0 ? 0 : unit.startIndex;
|
|
77
|
+
const blockEndIndex = unitIndex === units.length - 1 ? lineCount - 1 : units[unitIndex + 1].startIndex - 1;
|
|
78
|
+
const blockLines = lines.slice(blockStartIndex, blockEndIndex + 1);
|
|
79
|
+
const content = blockEndIndex < lineCount - 1 ? `${blockLines.join("\n")}\n` : blockLines.join("\n");
|
|
80
|
+
return {
|
|
81
|
+
type: unit.type,
|
|
82
|
+
content,
|
|
83
|
+
lineStart: blockStartIndex + 1,
|
|
84
|
+
lineEnd: blockEndIndex + 1
|
|
85
|
+
};
|
|
86
|
+
});
|
|
87
|
+
};
|
|
88
|
+
/**
|
|
89
|
+
* Split a markdown document into coarse, heading-anchored sections.
|
|
90
|
+
*
|
|
91
|
+
* Built by grouping the fine blocks of {@link segmentDocument}: frontmatter and
|
|
92
|
+
* each heading open a new section, and the following non-heading blocks are
|
|
93
|
+
* folded into it. Because it only concatenates adjacent fine blocks, the result
|
|
94
|
+
* is still an exact partition of the document (sections concatenate back to the
|
|
95
|
+
* source unchanged).
|
|
96
|
+
*
|
|
97
|
+
* Sections are the robust alignment unit between a base document and its
|
|
98
|
+
* translation — both share the same heading structure, so they align almost
|
|
99
|
+
* perfectly and a translation that splits its prose into a different number of
|
|
100
|
+
* paragraphs never causes a section to be dropped. Fine-grained review happens
|
|
101
|
+
* within a section once it is known to have changed.
|
|
102
|
+
*
|
|
103
|
+
* @param text - The full markdown document.
|
|
104
|
+
* @returns The ordered list of sections with their 1-based line ranges.
|
|
105
|
+
*/
|
|
106
|
+
const segmentSections = (text) => {
|
|
107
|
+
const fineBlocks = segmentDocument(text);
|
|
108
|
+
const sections = [];
|
|
109
|
+
let currentBlocks = [];
|
|
110
|
+
const flushSection = () => {
|
|
111
|
+
if (currentBlocks.length === 0) return;
|
|
112
|
+
const [firstBlock] = currentBlocks;
|
|
113
|
+
const lastBlock = currentBlocks[currentBlocks.length - 1];
|
|
114
|
+
sections.push({
|
|
115
|
+
type: firstBlock.type,
|
|
116
|
+
content: currentBlocks.map((block) => block.content).join(""),
|
|
117
|
+
lineStart: firstBlock.lineStart,
|
|
118
|
+
lineEnd: lastBlock.lineEnd
|
|
119
|
+
});
|
|
120
|
+
currentBlocks = [];
|
|
121
|
+
};
|
|
122
|
+
for (const block of fineBlocks) {
|
|
123
|
+
if (block.type === "heading" || block.type === "unknown" && sections.length === 0) flushSection();
|
|
124
|
+
currentBlocks.push(block);
|
|
125
|
+
if (block.type === "unknown" && sections.length === 0) flushSection();
|
|
126
|
+
}
|
|
127
|
+
flushSection();
|
|
128
|
+
return sections;
|
|
129
|
+
};
|
|
130
|
+
|
|
131
|
+
//#endregion
|
|
132
|
+
exports.segmentDocument = segmentDocument;
|
|
133
|
+
exports.segmentSections = segmentSections;
|
|
134
|
+
//# sourceMappingURL=segmentDocument.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"segmentDocument.cjs","names":[],"sources":["../../../src/docReview/segmentDocument.ts"],"sourcesContent":["import type { Block, BlockType } from './types';\n\nconst isBlankLine = (line: string): boolean => line.trim().length === 0;\nconst isFencedCodeDelimiter = (line: string): boolean => /^\\s*```/.test(line);\nconst isHeading = (line: string): boolean => /^\\s*#{1,6}\\s+/.test(line);\nconst isFrontmatterDelimiter = (line: string): boolean =>\n /^\\s*---\\s*$/.test(line);\n\n/**\n * A content unit (heading, paragraph, code block or frontmatter) spanning a\n * 0-based, inclusive line range. Blank-line runs are not units of their own;\n * they are folded into the preceding unit as trailing separators (see\n * {@link segmentDocument}) so that the concatenation of every block's content\n * reproduces the document byte-for-byte.\n */\ntype ContentUnit = {\n type: BlockType;\n startIndex: number;\n endIndex: number;\n};\n\n/**\n * Split a markdown document into fine-grained blocks.\n *\n * Boundaries are drawn at headings, blank lines (paragraph breaks) and fenced\n * code blocks, while frontmatter and the inside of code fences are kept intact.\n * Each blank-line run is appended to the block that precedes it, so the blocks\n * form an exact partition of the document: concatenating every `content` (in\n * order) yields the original text unchanged. This is what lets the block-aware\n * review re-translate only the paragraphs/snippets that actually changed instead\n * of the whole heading section.\n *\n * @param text - The full markdown document.\n * @returns The ordered list of blocks with their 1-based line ranges.\n */\nexport const segmentDocument = (text: string): Block[] => {\n const lines = text.split('\\n');\n const lineCount = lines.length;\n\n // 1. Tokenize into content units, skipping blank-line runs (folded in below).\n const units: ContentUnit[] = [];\n let index = 0;\n\n while (index < lineCount) {\n const currentLine = lines[index];\n\n if (isBlankLine(currentLine)) {\n index += 1;\n continue;\n }\n\n // Frontmatter: only when it opens the document.\n if (units.length === 0 && isFrontmatterDelimiter(currentLine)) {\n const startIndex = index;\n index += 1;\n while (index < lineCount && !isFrontmatterDelimiter(lines[index])) {\n index += 1;\n }\n // Include the closing delimiter when present.\n if (index < lineCount) index += 1;\n units.push({ type: 'unknown', startIndex, endIndex: index - 1 });\n continue;\n }\n\n // Fenced code block: consumed whole so inner blank lines and `#` lines are\n // never treated as boundaries.\n if (isFencedCodeDelimiter(currentLine)) {\n const startIndex = index;\n index += 1;\n while (index < lineCount && !isFencedCodeDelimiter(lines[index])) {\n index += 1;\n }\n // Include the closing fence when present.\n if (index < lineCount) index += 1;\n units.push({ type: 'code_block', startIndex, endIndex: index - 1 });\n continue;\n }\n\n // Heading: a single self-contained line.\n if (isHeading(currentLine)) {\n units.push({ type: 'heading', startIndex: index, endIndex: index });\n index += 1;\n continue;\n }\n\n // Paragraph: a run of consecutive lines until a blank line, a heading or a\n // code fence. Tables and tight lists stay together (no blank line between\n // their rows/items).\n const startIndex = index;\n while (\n index < lineCount &&\n !isBlankLine(lines[index]) &&\n !isHeading(lines[index]) &&\n !isFencedCodeDelimiter(lines[index])\n ) {\n index += 1;\n }\n units.push({ type: 'paragraph', startIndex, endIndex: index - 1 });\n }\n\n if (units.length === 0) return [];\n\n // 2. Turn each unit into a block whose line range extends to just before the\n // next unit, so the trailing blank-line run is owned by it. The first block\n // also absorbs any leading blank lines, and the last block runs to EOF.\n return units.map((unit, unitIndex): Block => {\n const blockStartIndex = unitIndex === 0 ? 0 : unit.startIndex;\n const blockEndIndex =\n unitIndex === units.length - 1\n ? lineCount - 1\n : units[unitIndex + 1].startIndex - 1;\n\n const blockLines = lines.slice(blockStartIndex, blockEndIndex + 1);\n // Re-append the boundary newline dropped by `split` for every block but the\n // one ending at EOF, so concatenating all blocks rebuilds the document.\n const content =\n blockEndIndex < lineCount - 1\n ? `${blockLines.join('\\n')}\\n`\n : blockLines.join('\\n');\n\n return {\n type: unit.type,\n content,\n lineStart: blockStartIndex + 1,\n lineEnd: blockEndIndex + 1,\n };\n });\n};\n\n/**\n * Split a markdown document into coarse, heading-anchored sections.\n *\n * Built by grouping the fine blocks of {@link segmentDocument}: frontmatter and\n * each heading open a new section, and the following non-heading blocks are\n * folded into it. Because it only concatenates adjacent fine blocks, the result\n * is still an exact partition of the document (sections concatenate back to the\n * source unchanged).\n *\n * Sections are the robust alignment unit between a base document and its\n * translation — both share the same heading structure, so they align almost\n * perfectly and a translation that splits its prose into a different number of\n * paragraphs never causes a section to be dropped. Fine-grained review happens\n * within a section once it is known to have changed.\n *\n * @param text - The full markdown document.\n * @returns The ordered list of sections with their 1-based line ranges.\n */\nexport const segmentSections = (text: string): Block[] => {\n const fineBlocks = segmentDocument(text);\n const sections: Block[] = [];\n let currentBlocks: Block[] = [];\n\n const flushSection = (): void => {\n if (currentBlocks.length === 0) return;\n\n const [firstBlock] = currentBlocks;\n const lastBlock = currentBlocks[currentBlocks.length - 1];\n\n sections.push({\n type: firstBlock.type,\n content: currentBlocks.map((block) => block.content).join(''),\n lineStart: firstBlock.lineStart,\n lineEnd: lastBlock.lineEnd,\n });\n currentBlocks = [];\n };\n\n for (const block of fineBlocks) {\n // Frontmatter (a leading `unknown` block) and every heading open a section.\n const opensSection =\n block.type === 'heading' ||\n (block.type === 'unknown' && sections.length === 0);\n\n if (opensSection) flushSection();\n currentBlocks.push(block);\n if (block.type === 'unknown' && sections.length === 0) flushSection();\n }\n\n flushSection();\n\n return sections;\n};\n"],"mappings":";;;AAEA,MAAM,eAAe,SAA0B,KAAK,MAAM,CAAC,WAAW;AACtE,MAAM,yBAAyB,SAA0B,UAAU,KAAK,KAAK;AAC7E,MAAM,aAAa,SAA0B,gBAAgB,KAAK,KAAK;AACvE,MAAM,0BAA0B,SAC9B,cAAc,KAAK,KAAK;;;;;;;;;;;;;;;AA6B1B,MAAa,mBAAmB,SAA0B;CACxD,MAAM,QAAQ,KAAK,MAAM,KAAK;CAC9B,MAAM,YAAY,MAAM;CAGxB,MAAM,QAAuB,EAAE;CAC/B,IAAI,QAAQ;AAEZ,QAAO,QAAQ,WAAW;EACxB,MAAM,cAAc,MAAM;AAE1B,MAAI,YAAY,YAAY,EAAE;AAC5B,YAAS;AACT;;AAIF,MAAI,MAAM,WAAW,KAAK,uBAAuB,YAAY,EAAE;GAC7D,MAAM,aAAa;AACnB,YAAS;AACT,UAAO,QAAQ,aAAa,CAAC,uBAAuB,MAAM,OAAO,CAC/D,UAAS;AAGX,OAAI,QAAQ,UAAW,UAAS;AAChC,SAAM,KAAK;IAAE,MAAM;IAAW;IAAY,UAAU,QAAQ;IAAG,CAAC;AAChE;;AAKF,MAAI,sBAAsB,YAAY,EAAE;GACtC,MAAM,aAAa;AACnB,YAAS;AACT,UAAO,QAAQ,aAAa,CAAC,sBAAsB,MAAM,OAAO,CAC9D,UAAS;AAGX,OAAI,QAAQ,UAAW,UAAS;AAChC,SAAM,KAAK;IAAE,MAAM;IAAc;IAAY,UAAU,QAAQ;IAAG,CAAC;AACnE;;AAIF,MAAI,UAAU,YAAY,EAAE;AAC1B,SAAM,KAAK;IAAE,MAAM;IAAW,YAAY;IAAO,UAAU;IAAO,CAAC;AACnE,YAAS;AACT;;EAMF,MAAM,aAAa;AACnB,SACE,QAAQ,aACR,CAAC,YAAY,MAAM,OAAO,IAC1B,CAAC,UAAU,MAAM,OAAO,IACxB,CAAC,sBAAsB,MAAM,OAAO,CAEpC,UAAS;AAEX,QAAM,KAAK;GAAE,MAAM;GAAa;GAAY,UAAU,QAAQ;GAAG,CAAC;;AAGpE,KAAI,MAAM,WAAW,EAAG,QAAO,EAAE;AAKjC,QAAO,MAAM,KAAK,MAAM,cAAqB;EAC3C,MAAM,kBAAkB,cAAc,IAAI,IAAI,KAAK;EACnD,MAAM,gBACJ,cAAc,MAAM,SAAS,IACzB,YAAY,IACZ,MAAM,YAAY,GAAG,aAAa;EAExC,MAAM,aAAa,MAAM,MAAM,iBAAiB,gBAAgB,EAAE;EAGlE,MAAM,UACJ,gBAAgB,YAAY,IACxB,GAAG,WAAW,KAAK,KAAK,CAAC,MACzB,WAAW,KAAK,KAAK;AAE3B,SAAO;GACL,MAAM,KAAK;GACX;GACA,WAAW,kBAAkB;GAC7B,SAAS,gBAAgB;GAC1B;GACD;;;;;;;;;;;;;;;;;;;;AAqBJ,MAAa,mBAAmB,SAA0B;CACxD,MAAM,aAAa,gBAAgB,KAAK;CACxC,MAAM,WAAoB,EAAE;CAC5B,IAAI,gBAAyB,EAAE;CAE/B,MAAM,qBAA2B;AAC/B,MAAI,cAAc,WAAW,EAAG;EAEhC,MAAM,CAAC,cAAc;EACrB,MAAM,YAAY,cAAc,cAAc,SAAS;AAEvD,WAAS,KAAK;GACZ,MAAM,WAAW;GACjB,SAAS,cAAc,KAAK,UAAU,MAAM,QAAQ,CAAC,KAAK,GAAG;GAC7D,WAAW,WAAW;GACtB,SAAS,UAAU;GACpB,CAAC;AACF,kBAAgB,EAAE;;AAGpB,MAAK,MAAM,SAAS,YAAY;AAM9B,MAHE,MAAM,SAAS,aACd,MAAM,SAAS,aAAa,SAAS,WAAW,EAEjC,eAAc;AAChC,gBAAc,KAAK,MAAM;AACzB,MAAI,MAAM,SAAS,aAAa,SAAS,WAAW,EAAG,eAAc;;AAGvE,eAAc;AAEd,QAAO"}
|
|
File without changes
|
package/dist/cjs/init/index.cjs
CHANGED
|
@@ -3,6 +3,7 @@ const require_runtime = require('../_virtual/_rolldown/runtime.cjs');
|
|
|
3
3
|
const require_initConfig_index = require('../initConfig/index.cjs');
|
|
4
4
|
const require_init_utils_configManipulation = require('./utils/configManipulation.cjs');
|
|
5
5
|
const require_init_utils_fileSystem = require('./utils/fileSystem.cjs');
|
|
6
|
+
const require_init_utils_githubActions = require('./utils/githubActions.cjs');
|
|
6
7
|
const require_init_utils_jsonParser = require('./utils/jsonParser.cjs');
|
|
7
8
|
const require_init_utils_packageManager = require('./utils/packageManager.cjs');
|
|
8
9
|
const require_init_utils_tsConfig = require('./utils/tsConfig.cjs');
|
|
@@ -123,7 +124,7 @@ const initIntlayer = async (rootDir, options) => {
|
|
|
123
124
|
...packageJson.devDependencies ?? {}
|
|
124
125
|
};
|
|
125
126
|
const packageManager = require_init_utils_packageManager.detectPackageManager(rootDir);
|
|
126
|
-
const { packagesToInstall, compatSyncConfig, compatVitePluginConfig } = require_init_utils_packageManager.detectMissingIntlayerPackages(allDeps);
|
|
127
|
+
const { packagesToInstall, devPackagesToInstall, compatSyncConfig, compatVitePluginConfig } = require_init_utils_packageManager.detectMissingIntlayerPackages(allDeps);
|
|
127
128
|
if (packagesToInstall.length > 0) {
|
|
128
129
|
(0, _intlayer_config_logger.logger)((0, _intlayer_config_logger.colorize)("Installing missing Intlayer dependencies...", _intlayer_config_colors.CYAN));
|
|
129
130
|
try {
|
|
@@ -133,6 +134,15 @@ const initIntlayer = async (rootDir, options) => {
|
|
|
133
134
|
(0, _intlayer_config_logger.logger)(`${_intlayer_config_logger.x} Failed to install packages. Please install manually: ${packagesToInstall.join(" ")}`, { level: "warn" });
|
|
134
135
|
}
|
|
135
136
|
}
|
|
137
|
+
if (devPackagesToInstall.length > 0) {
|
|
138
|
+
(0, _intlayer_config_logger.logger)((0, _intlayer_config_logger.colorize)("Installing missing Intlayer dev dependencies...", _intlayer_config_colors.CYAN));
|
|
139
|
+
try {
|
|
140
|
+
require_init_utils_packageManager.installPackages(rootDir, devPackagesToInstall, packageManager, true);
|
|
141
|
+
(0, _intlayer_config_logger.logger)(`${_intlayer_config_logger.v} Installed: ${devPackagesToInstall.map((pkg) => (0, _intlayer_config_logger.colorize)(pkg, _intlayer_config_colors.MAGENTA)).join(", ")}`);
|
|
142
|
+
} catch {
|
|
143
|
+
(0, _intlayer_config_logger.logger)(`${_intlayer_config_logger.x} Failed to install dev packages. Please install manually: ${devPackagesToInstall.join(" ")}`, { level: "warn" });
|
|
144
|
+
}
|
|
145
|
+
}
|
|
136
146
|
const gitignorePath = ".gitignore";
|
|
137
147
|
if (!options?.noGitignore && await require_init_utils_fileSystem.exists(rootDir, gitignorePath)) {
|
|
138
148
|
const gitignoreContent = await require_init_utils_fileSystem.readFileFromRoot(rootDir, gitignorePath);
|
|
@@ -141,6 +151,22 @@ const initIntlayer = async (rootDir, options) => {
|
|
|
141
151
|
(0, _intlayer_config_logger.logger)(`${_intlayer_config_logger.v} Added ${(0, _intlayer_config_logger.colorizePath)(".intlayer")} to ${(0, _intlayer_config_logger.colorizePath)(gitignorePath)}`);
|
|
142
152
|
} else (0, _intlayer_config_logger.logger)(`${_intlayer_config_logger.v} ${(0, _intlayer_config_logger.colorizePath)(gitignorePath)} already includes .intlayer`);
|
|
143
153
|
}
|
|
154
|
+
if (!options?.noGithubActions) {
|
|
155
|
+
const workflows = require_init_utils_githubActions.getGithubWorkflows(packageManager);
|
|
156
|
+
for (const workflow of workflows) {
|
|
157
|
+
if (await require_init_utils_fileSystem.exists(rootDir, workflow.filePath)) {
|
|
158
|
+
(0, _intlayer_config_logger.logger)(`${_intlayer_config_logger.v} ${(0, _intlayer_config_logger.colorizePath)(workflow.filePath)} already exists`);
|
|
159
|
+
continue;
|
|
160
|
+
}
|
|
161
|
+
try {
|
|
162
|
+
await require_init_utils_fileSystem.ensureDirectory(rootDir, (0, node_path.join)(".github", "workflows"));
|
|
163
|
+
await require_init_utils_fileSystem.writeFileToRoot(rootDir, workflow.filePath, workflow.content);
|
|
164
|
+
(0, _intlayer_config_logger.logger)(`${_intlayer_config_logger.v} Added GitHub Actions workflow ${(0, _intlayer_config_logger.colorizePath)(workflow.filePath)}`);
|
|
165
|
+
} catch {
|
|
166
|
+
(0, _intlayer_config_logger.logger)(`${_intlayer_config_logger.x} Could not create ${(0, _intlayer_config_logger.colorizePath)(workflow.filePath)}. You may need to add it manually.`, { level: "warn" });
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
}
|
|
144
170
|
const vscodeDir = ".vscode";
|
|
145
171
|
const extensionsJsonPath = (0, node_path.join)(vscodeDir, "extensions.json");
|
|
146
172
|
const extensionId = "intlayer.intlayer-vs-code-extension";
|
|
@@ -198,9 +224,10 @@ const initIntlayer = async (rootDir, options) => {
|
|
|
198
224
|
(0, _intlayer_config_logger.logger)(`${_intlayer_config_logger.x} Could not parse or update ${(0, _intlayer_config_logger.colorizePath)(fileName)}. You may need to add ${(0, _intlayer_config_logger.colorizePath)(".intlayer/types/**/*.ts")} manually.`, { level: "warn" });
|
|
199
225
|
}
|
|
200
226
|
}
|
|
201
|
-
|
|
227
|
+
const format = hasTsConfig ? "intlayer.config.ts" : "intlayer.config.mjs";
|
|
228
|
+
const detectedPattern = await require_init_utils_fileSystem.detectJsonLocalePattern(rootDir);
|
|
229
|
+
await require_initConfig_index.initConfig(format, rootDir, detectedPattern?.locales);
|
|
202
230
|
if (compatSyncConfig) {
|
|
203
|
-
const detectedPattern = await require_init_utils_fileSystem.detectJsonLocalePattern(rootDir);
|
|
204
231
|
const resolvedSyncConfig = detectedPattern ? {
|
|
205
232
|
...compatSyncConfig,
|
|
206
233
|
sourceTemplate: detectedPattern.template
|
|
@@ -299,7 +326,7 @@ const initIntlayer = async (rootDir, options) => {
|
|
|
299
326
|
const isVersionGreaterOrEqual = (versionString, major) => {
|
|
300
327
|
if (!versionString || typeof versionString !== "string") return false;
|
|
301
328
|
const match = versionString.match(/^[^\d]*(\d+)/);
|
|
302
|
-
if (!match) return false;
|
|
329
|
+
if (!match?.[1]) return false;
|
|
303
330
|
return parseInt(match[1], 10) >= major;
|
|
304
331
|
};
|
|
305
332
|
const backendIntlayerPackages = [
|
|
@@ -310,7 +337,7 @@ const initIntlayer = async (rootDir, options) => {
|
|
|
310
337
|
];
|
|
311
338
|
const devScript = packageJson.scripts?.dev;
|
|
312
339
|
let newDevScript;
|
|
313
|
-
if ((isNextJsProject && isVersionGreaterOrEqual(allDeps.next, 16) || backendIntlayerPackages.some((pkg) => allDeps[pkg])) && !devScript.includes("intlayer watch")) newDevScript = `intlayer watch --with '${devScript}'`;
|
|
340
|
+
if ((isNextJsProject && allDeps.next && isVersionGreaterOrEqual(allDeps.next, 16) || backendIntlayerPackages.some((pkg) => allDeps[pkg])) && !devScript.includes("intlayer watch")) newDevScript = `intlayer watch --with '${devScript}'`;
|
|
314
341
|
if (newDevScript) {
|
|
315
342
|
packageJson.scripts.dev = newDevScript;
|
|
316
343
|
await require_init_utils_fileSystem.writeFileToRoot(rootDir, packageJsonPath, JSON.stringify(packageJson, null, 2));
|
|
@@ -337,19 +364,21 @@ const initIntlayer = async (rootDir, options) => {
|
|
|
337
364
|
const aliases = (0, _intlayer_config_utils.getAlias)({ configuration: (0, _intlayer_config_node.getConfiguration)({ baseDir: rootDir }) });
|
|
338
365
|
if (hasTsConfig && tsConfigFiles.length > 0) {
|
|
339
366
|
const tsConfigPath = tsConfigFiles.find((file) => file === "tsconfig.json") || tsConfigFiles[0];
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
config.compilerOptions.paths[alias]
|
|
347
|
-
|
|
367
|
+
if (tsConfigPath) {
|
|
368
|
+
const config = require_init_utils_jsonParser.parseJSONWithComments(await require_init_utils_fileSystem.readFileFromRoot(rootDir, tsConfigPath));
|
|
369
|
+
config.compilerOptions ??= {};
|
|
370
|
+
config.compilerOptions.paths ??= {};
|
|
371
|
+
let updated = false;
|
|
372
|
+
Object.entries(aliases).forEach(([alias, path]) => {
|
|
373
|
+
if (!config.compilerOptions.paths[alias]) {
|
|
374
|
+
config.compilerOptions.paths[alias] = [path];
|
|
375
|
+
updated = true;
|
|
376
|
+
}
|
|
377
|
+
});
|
|
378
|
+
if (updated) {
|
|
379
|
+
await require_init_utils_fileSystem.writeFileToRoot(rootDir, tsConfigPath, JSON.stringify(config, null, 2));
|
|
380
|
+
(0, _intlayer_config_logger.logger)(`${_intlayer_config_logger.v} Updated ${(0, _intlayer_config_logger.colorizePath)(tsConfigPath)} to include Intlayer aliases`);
|
|
348
381
|
}
|
|
349
|
-
});
|
|
350
|
-
if (updated) {
|
|
351
|
-
await require_init_utils_fileSystem.writeFileToRoot(rootDir, tsConfigPath, JSON.stringify(config, null, 2));
|
|
352
|
-
(0, _intlayer_config_logger.logger)(`${_intlayer_config_logger.v} Updated ${(0, _intlayer_config_logger.colorizePath)(tsConfigPath)} to include Intlayer aliases`);
|
|
353
382
|
}
|
|
354
383
|
} else {
|
|
355
384
|
const jsConfigPath = "jsconfig.json";
|