hanlint 0.0.17 → 0.0.19
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.md +23 -20
- package/data/calqueFrame.json +60 -0
- package/data/cliches.json +39 -29
- package/data/collocationStops.txt +28 -0
- package/data/confusable.json +20 -20
- package/data/easyWords.json +12 -246
- package/data/exemplars.json +50 -29
- package/data/hiddenDeps.txt +11 -11
- package/data/japaneseLoan.json +27 -27
- package/data/koreanProse.txt +64 -0
- package/data/patterns.json +26 -26
- package/data/phraseRepeat.json +11 -0
- package/data/platformApis.txt +11 -11
- package/data/redundantPair.json +16 -16
- package/data/ruleCategories.json +2 -0
- package/data/ruleDocs.json +56 -54
- package/data/ruleMechanisms.json +2 -0
- package/data/screenNarration.json +10 -10
- package/data/screenSentence.json +60 -12
- package/data/screenTone.json +6 -6
- package/data/screenWord.json +70 -110
- package/data/spacing.json +12 -12
- package/data/spelling.json +29 -29
- package/data/translationese.json +23 -24
- package/data/usageCounts.report.json +1676 -0
- package/data/version.json +1 -1
- package/package.json +1 -1
- package/src/analysis/grammar/ending.js +1 -1
- package/src/analysis/grammar/hangul.js +4 -4
- package/src/analysis/grammar/josa.js +1 -1
- package/src/analysis/grammar/register.js +1 -1
- package/src/analysis/grammar/voice.js +1 -1
- package/src/analysis/index.js +3 -3
- package/src/analysis/josa.js +1 -1
- package/src/analysis/splitSentences.js +1 -1
- package/src/analysis/tokenize.js +41 -26
- package/src/baseline/store.js +8 -8
- package/src/cli/help.js +11 -10
- package/src/cli/main.js +332 -182
- package/src/cli/walk.js +2 -2
- package/src/cli/welcome.js +8 -8
- package/src/config/loadConfig.js +3 -3
- package/src/config/patch.js +6 -6
- package/src/config/readerContract.js +26 -26
- package/src/config/settings.js +44 -25
- package/src/config/toml.js +9 -9
- package/src/data/exemplars.js +21 -21
- package/src/data/load.js +6 -6
- package/src/data/operations.js +14 -14
- package/src/data/patches.js +10 -10
- package/src/data/patterns.js +5 -5
- package/src/data/profiles.js +6 -6
- package/src/data/prose.js +27 -0
- package/src/document/model.js +4 -4
- package/src/document/parseMarkdown.js +7 -7
- package/src/document/plainText.js +3 -3
- package/src/document/sourceText.js +117 -19
- package/src/edit/applyFixes.js +0 -0
- package/src/fingerprint/build.js +18 -9
- package/src/fingerprint/codeBlocks.js +3 -3
- package/src/fingerprint/codeMarkers.js +4 -4
- package/src/fingerprint/dictionaries.js +34 -7
- package/src/fingerprint/markers.js +27 -5
- package/src/fingerprint/readerState.js +9 -9
- package/src/fingerprint/sourceSentence.js +1 -1
- package/src/fingerprint/topics.js +1 -1
- package/src/guard/contract.js +6 -6
- package/src/guard/editLocality.js +1 -1
- package/src/guard/outline.js +1 -1
- package/src/guard/receipt.js +13 -13
- package/src/guard/surface.js +4 -4
- package/src/index.js +9 -7
- package/src/learn/edits.js +2 -2
- package/src/learn/operations.js +1 -1
- package/src/regex.js +2 -2
- package/src/report/compactReport.js +7 -3
- package/src/report/fingerprintJson.js +2 -2
- package/src/report/githubReport.js +1 -1
- package/src/report/jsonReport.js +3 -3
- package/src/report/registerMatch.js +2 -2
- package/src/report/sheet.js +0 -0
- package/src/report/textReport.js +35 -16
- package/src/report/writingSpec.js +17 -17
- package/src/rules/code/inputFileSource.js +1 -1
- package/src/rules/code/installImport.js +2 -2
- package/src/rules/code/platformApi.js +1 -1
- package/src/rules/document/countMismatch.js +2 -1
- package/src/rules/document/enoughOnce.js +2 -1
- package/src/rules/document/fieldEcho.js +10 -6
- package/src/rules/document/keywordHeading.js +1 -1
- package/src/rules/document/keywordMissing.js +1 -1
- package/src/rules/document/noQuestion.js +2 -2
- package/src/rules/document/promiseRecall.js +1 -1
- package/src/rules/document/tableOddCell.js +1 -1
- package/src/rules/finding.js +4 -4
- package/src/rules/paragraph/factListParagraph.js +1 -1
- package/src/rules/paragraph/paraFragment.js +1 -1
- package/src/rules/readerDebt.js +1 -1
- package/src/rules/registry.js +30 -26
- package/src/rules/screen/screenWord.js +2 -1
- package/src/rules/sentence/calqueFrame.js +11 -0
- package/src/rules/sentence/cliche.js +7 -3
- package/src/rules/sentence/connectorRepeat.js +2 -1
- package/src/rules/sentence/danglingDeixis.js +1 -1
- package/src/rules/sentence/dash.js +1 -1
- package/src/rules/sentence/deixis.js +1 -1
- package/src/rules/sentence/doubleNegative.js +2 -1
- package/src/rules/sentence/doublePassive.js +2 -1
- package/src/rules/sentence/draftHistory.js +2 -1
- package/src/rules/sentence/endingRepeat.js +3 -2
- package/src/rules/sentence/euiChain.js +1 -1
- package/src/rules/sentence/fillerOpener.js +1 -1
- package/src/rules/sentence/hardWord.js +6 -3
- package/src/rules/sentence/imperativePeriod.js +1 -1
- package/src/rules/sentence/japaneseLoan.js +7 -3
- package/src/rules/sentence/longSentence.js +1 -1
- package/src/rules/sentence/negationRedefine.js +1 -1
- package/src/rules/sentence/nounPile.js +10 -4
- package/src/rules/sentence/numberOrphan.js +1 -1
- package/src/rules/sentence/outsideProfile.js +8 -3
- package/src/rules/sentence/phraseRepeat.js +54 -0
- package/src/rules/sentence/redundantPair.js +7 -3
- package/src/rules/sentence/translationese.js +7 -3
- package/src/rules/shared/candidates.js +2 -2
- package/src/rules/shared/dictionaryRule.js +46 -8
- package/src/rules/shared/repeat.js +2 -2
- package/src/rules/structure/bridgeRepeat.js +3 -3
- package/src/rules/structure/emojiBullet.js +1 -1
- package/src/rules/structure/headingSkip.js +1 -1
- package/src/rules/structure/headingUniform.js +2 -1
- package/src/rules/structure/loneSubheading.js +1 -1
- package/src/rules/structure/moreLater.js +1 -1
- package/src/text.js +2 -2
- package/src/usage/counts.js +54 -0
- package/src/usage/index.js +8 -0
- package/src/usage/sentences.js +681 -0
package/data/version.json
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version": "0.0.
|
|
1
|
+
{"version": "0.0.19"}
|
package/package.json
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
// @ts-check
|
|
2
|
-
/** 파이썬 `analysis/grammar/ending.py`와 `predicate.py
|
|
2
|
+
/** 파이썬 `analysis/grammar/ending.py`와 `predicate.py`를 옮긴 것. 종결 서술어를 풀고 세 문체로 짠다. */
|
|
3
3
|
import { loadLines } from "../../data/load.js";
|
|
4
4
|
import * as hangul from "./hangul.js";
|
|
5
5
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
// @ts-check
|
|
2
2
|
/**
|
|
3
|
-
* 한글 음절의 자모 산술. 파이썬 `analysis/grammar/hangul.py
|
|
3
|
+
* 한글 음절의 자모 산술. 파이썬 `analysis/grammar/hangul.py`를 옮긴 것이다. 표 대신 산술로 하는 까닭은 그 파일에 적었다.
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
6
|
export const BASE = 0xac00;
|
|
@@ -31,7 +31,7 @@ export const EU = 18;
|
|
|
31
31
|
export const UI = 19;
|
|
32
32
|
export const IH = 20;
|
|
33
33
|
|
|
34
|
-
// 종성 자리 번호 가운데 형태
|
|
34
|
+
// 종성 자리 번호 가운데 형태 부분이 이름으로 부르는 것.
|
|
35
35
|
export const NONE = 0;
|
|
36
36
|
export const GIYEOK = 1;
|
|
37
37
|
export const NIEUN = 4;
|
|
@@ -44,7 +44,7 @@ export const SSANGSIOT = 20;
|
|
|
44
44
|
export const IEUNG = 21;
|
|
45
45
|
export const HIEUT = 27;
|
|
46
46
|
|
|
47
|
-
/** 양성 모음. 이 모음 뒤에는
|
|
47
|
+
/** 양성 모음. 이 모음 뒤에는 `아`가 붙고 나머지에는 `어`가 붙는다. */
|
|
48
48
|
export const BRIGHT = new Set([A, OH, YA, YO, WA]);
|
|
49
49
|
|
|
50
50
|
/** @param {string} ch */
|
|
@@ -88,7 +88,7 @@ export function withVowel(ch, vowel) {
|
|
|
88
88
|
return join(initial, vowel, final);
|
|
89
89
|
}
|
|
90
90
|
|
|
91
|
-
/**
|
|
91
|
+
/** 단어의 마지막 한글 음절. 없으면 null. @param {string} word */
|
|
92
92
|
export function lastSyllable(word) {
|
|
93
93
|
return word && isSyllable(word[word.length - 1]) ? word[word.length - 1] : null;
|
|
94
94
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
// @ts-check
|
|
2
|
-
/** 파이썬 `analysis/grammar/register.py
|
|
2
|
+
/** 파이썬 `analysis/grammar/register.py`를 옮긴 것. 글의 문체를 판별하고 문장 끝 서술어를 맞춘다. */
|
|
3
3
|
import * as hangul from "./hangul.js";
|
|
4
4
|
import { HAEYO, HANDA, HAPNIDA, REGISTERS, parsePredicate, render } from "./ending.js";
|
|
5
5
|
|
package/src/analysis/index.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
// @ts-check
|
|
2
2
|
/**
|
|
3
|
-
* 분석
|
|
4
|
-
*
|
|
3
|
+
* 분석 부분. 문장 분리와 어절 판정을 글자 모양(어절과 꼬리 사전)만으로 한다. 형태소 분석기는 없다. 파이썬 analysis/__init__.py와 같다.
|
|
4
|
+
* 글 분석에 필요한 것은 넷이다. splitSentences, euiCount와 euiAdjacent, longestNounRun, doublePassives.
|
|
5
5
|
*/
|
|
6
6
|
export { splitSentences } from "./splitSentences.js";
|
|
7
|
-
export { doublePassives, doublePassiveSpans, euiAdjacent, euiCount, longestNounRun } from "./tokenize.js";
|
|
7
|
+
export { doublePassives, doublePassiveSpans, euiAdjacent, euiCount, longestNounRun, nounRuns } from "./tokenize.js";
|
package/src/analysis/josa.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
// 이전 deep path 호환.
|
|
1
|
+
// 이전 deep path 호환. 실제 구현은 grammar/josa.js에 있다.
|
|
2
2
|
export * from "./grammar/josa.js";
|
package/src/analysis/tokenize.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
// @ts-check
|
|
2
2
|
/**
|
|
3
|
-
* 어절 단위
|
|
3
|
+
* 어절 단위 어림. 조사와 어미 꼬리 사전으로 명사 어절을 가려낸다. 파이썬 analysis/tokenize.py와 같은 판정이다.
|
|
4
4
|
* 띄어 쓴 조사와 계사는 앞 어절에 붙은 것으로, 영문 어절 연속은 한 덩어리로, 수사와 바로 뒤 단위는 수량으로 본다.
|
|
5
5
|
*/
|
|
6
6
|
import { loadLines } from "../data/load.js";
|
|
@@ -9,16 +9,16 @@ import { splitWords, stripChars } from "../text.js";
|
|
|
9
9
|
const HANGUL = /[가-힣]/;
|
|
10
10
|
const HANGUL_WORD = /^[가-힣]+$/;
|
|
11
11
|
const WORD_CHARS = /^[가-힣A-Za-z0-9]+$/;
|
|
12
|
-
/** 관형격 조사
|
|
12
|
+
/** 관형격 조사 `의`. 영문과 숫자 뒤(`API의`, `600MiB의`)와 닫는 괄호 뒤(`L7(HTTP)의`)도 센다. 파이썬 tokenize.py와 같다. */
|
|
13
13
|
const GENITIVE = /([가-힣A-Za-z0-9]+|\))의(?=[\s,.)\]]|$)/g;
|
|
14
14
|
const SPACED_GENITIVE = /(?<=\s)의(?=\s)/g;
|
|
15
|
-
const COPULA = /^(?:이(?:고|며|다|라|란|면|라서|므로|지만|어서|었다|었고)|인|인데|입니다|였다)$/;
|
|
15
|
+
export const COPULA = /^(?:이(?:고|며|다|라|란|면|라서|므로|지만|어서|었다|었고)|인|인데|입니다|였다)$/;
|
|
16
16
|
const DIGITS = /^\d+$/;
|
|
17
17
|
/** 수에 단위가 붙은 어절 (2012년, 30분쯤, 제16호, 100명). 수량이라 명사 나열에서 세지도 끊지도 않는다. */
|
|
18
18
|
const QUANTITY = /^제?\d[\d,.]*[가-힣]{1,3}$/;
|
|
19
19
|
const OPENERS = "([{\"“‘'";
|
|
20
20
|
const CLOSERS = ",.?!;:)]}\"”’'";
|
|
21
|
-
const EDGE_PUNCTUATION = ".,?!:;\"'“”‘’()[]{}<>";
|
|
21
|
+
export const EDGE_PUNCTUATION = ".,?!:;\"'“”‘’()[]{}<>";
|
|
22
22
|
|
|
23
23
|
/**
|
|
24
24
|
* @typedef {object} Word
|
|
@@ -77,8 +77,8 @@ export function inNouns() {
|
|
|
77
77
|
}
|
|
78
78
|
|
|
79
79
|
/**
|
|
80
|
-
* `도구인`,
|
|
81
|
-
* 외국인 같은 세 음절 명사는 data/inNouns.txt
|
|
80
|
+
* `도구인`, `규모인`처럼 명사에 계사 관형형 `인`이 붙은 어절. 서술어라 명사 나열을 끊는다. 어간이 두 음절 이상일 때만이고
|
|
81
|
+
* 외국인 같은 세 음절 명사는 data/inNouns.txt가 뺀다. 파이썬 tokenize.py와 같다.
|
|
82
82
|
* @param {string} core
|
|
83
83
|
*/
|
|
84
84
|
export function isCopulaAdnominal(core) {
|
|
@@ -126,40 +126,55 @@ export function isBareNoun(core) {
|
|
|
126
126
|
}
|
|
127
127
|
|
|
128
128
|
/**
|
|
129
|
-
* 명사 어절 연속의 최대 길이. 의존명사와 관형사와 부사
|
|
130
|
-
*
|
|
129
|
+
* 명사 어절 연속의 최대 길이. 의존명사와 관형사와 부사(`수`, `몇`, `직접`)는 조사도 어미도 안 붙어
|
|
130
|
+
* 글자 모양으로는 명사로 보이지만 명사 쌓기의 재료가 아니다. data/nonNouns.txt가 그 목록이고 연속을 끊는다.
|
|
131
131
|
* @param {string} text
|
|
132
132
|
*/
|
|
133
|
-
|
|
134
|
-
|
|
133
|
+
/**
|
|
134
|
+
* 명사 어절 연속마다 [어절들, 센 길이]. 뜻은 파이썬 analysis/tokenize.py의 nounRuns가 정한다.
|
|
135
|
+
* 수사와 단위는 세지도 끊지도 않고 어절에도 안 넣는다. 잇달은 영문 어절은 하나로 센다.
|
|
136
|
+
* @param {string} text @returns {[string[], number][]}
|
|
137
|
+
*/
|
|
138
|
+
export function nounRuns(text) {
|
|
139
|
+
/** @type {[string[], number][]} */
|
|
140
|
+
const runs = [];
|
|
141
|
+
/** @type {string[]} */
|
|
142
|
+
let chain = [];
|
|
135
143
|
let run = 0;
|
|
136
144
|
let previousAscii = false;
|
|
137
145
|
let afterNumeral = false;
|
|
146
|
+
const close = () => {
|
|
147
|
+
if (run) runs.push([chain, run]);
|
|
148
|
+
chain = [];
|
|
149
|
+
run = 0;
|
|
150
|
+
previousAscii = false;
|
|
151
|
+
};
|
|
138
152
|
for (const word of words(text)) {
|
|
139
|
-
if (word.opens)
|
|
140
|
-
run = 0;
|
|
141
|
-
previousAscii = false;
|
|
142
|
-
}
|
|
153
|
+
if (word.opens) close();
|
|
143
154
|
const transparent = isNumeral(word.core) || afterNumeral || isQuantity(word.core);
|
|
144
155
|
afterNumeral = isNumeral(word.core);
|
|
145
156
|
if (word.particle || nonNouns().has(word.core) || !isBareNoun(word.core) || isCopulaAdnominal(word.core)) {
|
|
146
|
-
|
|
147
|
-
previousAscii = false;
|
|
157
|
+
close();
|
|
148
158
|
} else if (!transparent) {
|
|
149
159
|
const isAscii = !HANGUL.test(word.core);
|
|
150
160
|
if (!(isAscii && previousAscii)) run += 1;
|
|
161
|
+
chain.push(word.core);
|
|
151
162
|
previousAscii = isAscii;
|
|
152
|
-
longest = Math.max(longest, run);
|
|
153
|
-
}
|
|
154
|
-
if (word.endsClause) {
|
|
155
|
-
run = 0;
|
|
156
|
-
previousAscii = false;
|
|
157
163
|
}
|
|
164
|
+
if (word.endsClause) close();
|
|
158
165
|
}
|
|
166
|
+
close();
|
|
167
|
+
return runs;
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
/** 명사 어절 연속의 최대 길이. nounRuns의 센 길이 가운데 가장 큰 것. @param {string} text */
|
|
171
|
+
export function longestNounRun(text) {
|
|
172
|
+
let longest = 0;
|
|
173
|
+
for (const [, length] of nounRuns(text)) longest = Math.max(longest, length);
|
|
159
174
|
return longest;
|
|
160
175
|
}
|
|
161
176
|
|
|
162
|
-
/** 관형격 조사
|
|
177
|
+
/** 관형격 조사 `의`가 붙은 곳 [시작, 끝]. `정의`, `회의`처럼 `의`로 끝나는 단어는 빼고 띄어 쓴 `의`는 넣는다. @param {string} text @returns {[number, number][]} */
|
|
163
178
|
export function genitiveSpans(text) {
|
|
164
179
|
/** @type {[number, number][]} */
|
|
165
180
|
const spans = [];
|
|
@@ -170,13 +185,13 @@ export function genitiveSpans(text) {
|
|
|
170
185
|
return spans.sort((a, b) => a[0] - b[0] || a[1] - b[1]);
|
|
171
186
|
}
|
|
172
187
|
|
|
173
|
-
/**
|
|
188
|
+
/** `의`로 끝나는 어절 둘이 붙어 있는가(`회사의 팀의`). 사이가 공백뿐이어야 한다. @param {string} text */
|
|
174
189
|
export function euiAdjacent(text) {
|
|
175
190
|
const spans = genitiveSpans(text);
|
|
176
191
|
return spans.some((span, index) => index > 0 && /^\s+$/.test(text.slice(spans[index - 1][1], span[0])));
|
|
177
192
|
}
|
|
178
193
|
|
|
179
|
-
/** 관형격 조사
|
|
194
|
+
/** 관형격 조사 `의`의 수. @param {string} text */
|
|
180
195
|
export function euiCount(text) {
|
|
181
196
|
return genitiveSpans(text).length;
|
|
182
197
|
}
|
|
@@ -205,7 +220,7 @@ export function doublePassivePattern() {
|
|
|
205
220
|
return passivePattern;
|
|
206
221
|
}
|
|
207
222
|
|
|
208
|
-
/** 이중 피동의 [시작, 끝, `되어지`
|
|
223
|
+
/** 이중 피동의 [시작, 끝, `되어지` 꼴로 쓴 글자]. @param {string} text @returns {[number, number, string][]} */
|
|
209
224
|
export function doublePassiveSpans(text) {
|
|
210
225
|
return [...text.matchAll(doublePassivePattern())].map((match) => {
|
|
211
226
|
const start = /** @type {number} */ (match.index);
|
|
@@ -213,7 +228,7 @@ export function doublePassiveSpans(text) {
|
|
|
213
228
|
});
|
|
214
229
|
}
|
|
215
230
|
|
|
216
|
-
/** 이중 피동의
|
|
231
|
+
/** 이중 피동의 글자를 `되어지` 꼴로. @param {string} text */
|
|
217
232
|
export function doublePassives(text) {
|
|
218
233
|
return doublePassiveSpans(text).map(([, , surface]) => surface);
|
|
219
234
|
}
|
package/src/baseline/store.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
// @ts-check
|
|
2
2
|
/**
|
|
3
|
-
* 이미 있는 지적을
|
|
4
|
-
* 왜 줄 번호가 아니라 글자인지, 왜 사람이 읽는
|
|
3
|
+
* 이미 있는 지적을 baseline 파일에 적어 두고 새로 생긴 지적만 막는다. 파이썬 `hanlint/baseline/store.py`를 옮긴 것이다.
|
|
4
|
+
* 왜 줄 번호가 아니라 글자인지, 왜 사람이 읽는 형식인지는 그 파일의 docstring에 있다.
|
|
5
5
|
*/
|
|
6
6
|
import { existsSync, readFileSync } from "node:fs";
|
|
7
7
|
import { dirname, posix, relative, resolve, sep } from "node:path";
|
|
@@ -20,7 +20,7 @@ export function keyOf(finding) {
|
|
|
20
20
|
return `${finding.rule}\u0000${normalizeQuote(finding.quote)}`;
|
|
21
21
|
}
|
|
22
22
|
|
|
23
|
-
/**
|
|
23
|
+
/** baseline 파일이 있는 폴더에서 본 상대 경로. @param {string} path @param {string | null} target */
|
|
24
24
|
export function pathKey(path, target) {
|
|
25
25
|
if (!target || !path || path.startsWith("<")) return path;
|
|
26
26
|
return relative(dirname(resolve(target)), resolve(path)).split(sep).join(posix.sep);
|
|
@@ -44,7 +44,7 @@ export class Baseline {
|
|
|
44
44
|
return (this.locked.get(pathKey(path, this.source)) ?? new Set()).has(keyOf(finding));
|
|
45
45
|
}
|
|
46
46
|
|
|
47
|
-
/**
|
|
47
|
+
/** baseline 파일에 없는 지적만 남긴다. @param {string} path @param {import("../rules/finding.js").Finding[]} findings */
|
|
48
48
|
keep(path, findings) {
|
|
49
49
|
return findings.filter((finding) => !this.isLocked(path, finding));
|
|
50
50
|
}
|
|
@@ -60,7 +60,7 @@ export function build(results, target = null) {
|
|
|
60
60
|
return new Baseline(locked, target ? resolve(target) : null);
|
|
61
61
|
}
|
|
62
62
|
|
|
63
|
-
/** 사람이 읽고 리뷰하는
|
|
63
|
+
/** 사람이 읽고 리뷰하는 형식. 정렬해 담아 같은 입력에 같은 파일이 나온다. @param {Baseline} baseline */
|
|
64
64
|
export function render(baseline) {
|
|
65
65
|
/** @type {Record<string, {rule: string, quote: string}[]>} */
|
|
66
66
|
const files = {};
|
|
@@ -80,7 +80,7 @@ export function render(baseline) {
|
|
|
80
80
|
/** @param {string} text @param {string | null} [source] */
|
|
81
81
|
export function parse(text, source = null) {
|
|
82
82
|
const data = JSON.parse(text);
|
|
83
|
-
if (data.version !== VERSION) throw new Error(
|
|
83
|
+
if (data.version !== VERSION) throw new Error(`지원하지 않는 baseline 버전: ${data.version}. hanlint baseline으로 다시 만든다`);
|
|
84
84
|
/** @type {Map<string, Set<string>>} */
|
|
85
85
|
const locked = new Map();
|
|
86
86
|
for (const [path, entries] of Object.entries(data.files ?? {})) {
|
|
@@ -92,7 +92,7 @@ export function parse(text, source = null) {
|
|
|
92
92
|
/** @param {string} path */
|
|
93
93
|
export function load(path) {
|
|
94
94
|
if (!existsSync(path)) {
|
|
95
|
-
const error = /** @type {NodeJS.ErrnoException} */ (new Error(
|
|
95
|
+
const error = /** @type {NodeJS.ErrnoException} */ (new Error(`파일을 찾지 못했다: ${path}`));
|
|
96
96
|
error.code = "ENOENT";
|
|
97
97
|
error.path = path;
|
|
98
98
|
throw error;
|
|
@@ -100,7 +100,7 @@ export function load(path) {
|
|
|
100
100
|
return parse(readFileSync(path, "utf-8"), resolve(path));
|
|
101
101
|
}
|
|
102
102
|
|
|
103
|
-
/** 지금 글에
|
|
103
|
+
/** 지금 글에 더는 없는 지적을 baseline 파일에서 지운다. @param {Baseline} baseline @param {Map<string, import("../rules/finding.js").Finding[]>} results */
|
|
104
104
|
export function prune(baseline, results) {
|
|
105
105
|
const kept = new Map(baseline.locked);
|
|
106
106
|
for (const [path, findings] of results) {
|
package/src/cli/help.js
CHANGED
|
@@ -2,14 +2,14 @@
|
|
|
2
2
|
/** 첫 화면 다음에 보이는 작업 흐름 중심 도움말. */
|
|
3
3
|
|
|
4
4
|
export function rootHelp() {
|
|
5
|
-
return `hanlint: 한국어
|
|
5
|
+
return `hanlint: 한국어 글에서 규칙으로 잡을 수 있는 잘못을 찾는다
|
|
6
6
|
|
|
7
7
|
일상 검사
|
|
8
8
|
hanlint 글.md 글을 검사한다
|
|
9
9
|
hanlint fix 글.md 안전한 고침만 적용한다
|
|
10
|
-
hanlint hook AI가 저장한 마크다운을 같은 턴에 검사한다
|
|
10
|
+
hanlint hook AI가 쓰기 전에 글쓰기 지침을 넣어 주고, 저장한 마크다운을 같은 턴에 검사한다
|
|
11
11
|
|
|
12
|
-
요구사항
|
|
12
|
+
요구사항 고정
|
|
13
13
|
hanlint contract init 글.md --reader "독자" --goal "목표" --outline h2
|
|
14
14
|
hanlint check contract.json 글.md --format text
|
|
15
15
|
hanlint verify-patch contract.json 글.md patch.json
|
|
@@ -17,19 +17,20 @@ export function rootHelp() {
|
|
|
17
17
|
설정과 이해
|
|
18
18
|
hanlint init 설정 파일을 만든다
|
|
19
19
|
hanlint doctor 적용 설정과 꺼진 규칙을 본다
|
|
20
|
-
hanlint rules 규칙을
|
|
21
|
-
hanlint explain <규칙> 규칙의 이유와
|
|
20
|
+
hanlint rules 규칙을 카테고리별로 본다
|
|
21
|
+
hanlint explain <규칙> 규칙의 이유와 예시를 본다
|
|
22
22
|
hanlint patterns --rule <규칙> 다시 쓸 문장 틀을 본다
|
|
23
23
|
hanlint spec --preset <종류> --chars 800
|
|
24
|
-
쓰기
|
|
25
|
-
hanlint primer --preset <종류> 쓰기 전에 규칙의 고치는 법과
|
|
26
|
-
hanlint sheet src/ --preset screen 소스의 화면 글을 표 하나로
|
|
24
|
+
쓰기 전에 볼 스펙을 만든다
|
|
25
|
+
hanlint primer --preset <종류> 쓰기 전에 규칙의 고치는 법과 예시를 한 장으로 본다
|
|
26
|
+
hanlint sheet src/ --preset screen 소스의 화면 글을 표 하나로 내보낸다. 고친 표는 sheet apply로 원본에 반영한다
|
|
27
|
+
hanlint usage "단어 단어" 그 종류의 실제 글에서 단어가 쓰인 문장을 본다. 색인은 usage build가 만든다
|
|
27
28
|
|
|
28
29
|
추가 명령
|
|
29
30
|
baseline, print
|
|
30
31
|
Python 전용: audit, map, watch, profile, coverage, diff, learn, packet,
|
|
31
32
|
guard, arena, blueprint, evidence, entailment, terms
|
|
32
33
|
|
|
33
|
-
|
|
34
|
-
종료 코드: 0
|
|
34
|
+
명령마다의 옵션은 README의 명령 표에 있다. 폴더를 주면 그 아래 마크다운을 검사한다.
|
|
35
|
+
종료 코드: 0은 오류 없음, 1은 오류 있음, 2는 입력이나 설정 문제. 좋은 글인지는 판정하지 않는다.`;
|
|
35
36
|
}
|