// npm 패키지
@lint-md/core
Core of lint-md which used to lint your markdown file for Chinese.
버전
23
메인테이너
2
라이선스
MIT
최초 publish
2021-03-28
publisher
yzl520
tarball
213,108 B
AUTO-PUBLISHED·1개 버전 인덱싱됨·최근 publish: 2023-07-12
// publisher 캠페인by yzl520
이 계정에서 catch된 패키지 3건고립된 catch가 아닙니다. 동일 publisher가 2개의 다른 패키지를 추가로 발행했고, 모두 파이프라인이 catch했습니다 — 일회성이 아닌 조직적 캠페인의 형태. 아래 링크는 각 형제 catch의 분석으로 이동합니다.
// offending code· @2.0.0· 3 files flagged
llm: benign · 0.85→ 의심 전송지 없음, 원격 실행 형태 없음 — 1 known-vendor host(s).
- @2.0.0··AUTO-PUBLISHED·publisher: yzl520heuristic 75/100static flags 2llm benign (0.85) via ollamamature-packageosv-flagged:MAL-2026-4124install-path-npm-publishchild-process-spawn
→ 의심 전송지 없음, 원격 실행 형태 없음 — 1 known-vendor host(s).
// offending code· 3 files flaggedpatterns: 2
--- package/package.json (excerpt) --- { "name": "@lint-md/core", "version": "2.0.0", "description": "Core of lint-md which used to lint your markdown file for Chinese.", "main": "lib/index.js", "module": "esm/index.js", "contributors": [ "hustcc <i@hust.cc>", "yuzhanglong <loveyzl1123@gmail.com>" ], "scripts": { "test": "jest --no-cache", "lib:cjs": "tsc -p tsconfig.json --target ESNext --module commonjs --outDir lib", "lib:esm": "tsc -p tsconfig.json --target ESNext --module ESNext --outDir esm", "build": "rm -rf lib esm && run-p lib:*", "clean": "rimraf lib esm", "release": "npm publish" }, "files": [ "esm", "lib", "src" ], "keywords": [ "lint", "markdown", "lint-md", "chinese" ], "dependencies": { "@lint-md/parser": "~0.0.14", "lodash": "^4.17.21" }, "devDependencies": { "@attachments/eslint-config": "^0.3.3", "@lint-md/core": "0.2.2", "@types/benchmark": "^2.1.2", "@types/glob": "^8.0.0", "@types/jest": "^29.2.0", "@types/lodash": "^4.14.186", "@types/node": "^18.11.7", "benchmark": "^2.1.4", "eslint": "^8.26.0", "glob": "^8.0.3", "jest": "^29.2.2", "npm-run-all": "^4.1.5", "rimraf": "^3.0.2", "ts-jest": "^29.0.3", "typescript": "^4.8.4" }, "jest": { "preset": "ts-jest", "testEnvironment": "node", "testRegex": "(/__tests__/.*\\.(test|spec))\\.ts$", "collectCoverage": true, "collectCoverageFrom": [ "src/**/*.{js,jsx,ts,tsx} --- package/src/rules/no-full-width-number.ts (excerpt) --- import type { MarkdownNode } from '@lint-md/parser'; import type { LintMdRule } from '../types'; const FULL_WIDTH_NUMBER_REPLACEMENT_MAP = { '1': 1, '2': 2, '3': 3, '4': 4, '5': 5, '6': 6, '7': 7, '8': 8, '9': 9, '0': 0 }; /** * 从字符串中找出所有全角数字 * @param s * @returns {Array} */ const findAllFullWidthNumbers = (s: string) => { const re = /[0-9]+/g; const r: { number: string; index: number }[] = []; // 循环找出所有的数字 while (true) { const matched = re.exec(s); if (matched) { r.push({ number: matched[0], index: matched.index }); } else { break; } } return r; }; const noFullWidthNumber: LintMdRule = { meta: { name: 'no-full-width-number' }, create: (context) => { return { text: (node: MarkdownNode & { value: string }) => { const text = node.value; const fullWidthNumbers = findAllFullWidthNumbers(text); fullWidthNumbers.forEach((res) => { const { index, number } = res; const { line: startLine, column: startColumn, offset: startOffset } = node.position.start; const startPos = startColumn + index; const endPos = startColumn + index + number.length; context.report({ loc: { start: { line: startLine, column: startPos }, end: { line: startLine, column: endPos } --- package/src/rules/use-standard-ellipsis.ts (excerpt) --- import type { MarkdownCodeNode } from '@lint-md/parser'; import type { LintMdRule } from '../types'; /** * 找到所有的 … */ const findAllSingleEllipsis = (s: string) => { const r = []; const re = /…+/g; // 使用正则匹配 while (true) { const matched = re.exec(s); // 只要不是两个,都是不规范的 if (matched && matched[0].length !== 2) { // @ts-expect-error r.push({ index: matched.index, length: matched[0].length }); } else { break; } } return r; }; /** * 找到所有的 . 组成的省略号 */ const findAllDotEllipsis = (s: string) => { const r = []; const re = /\.{4,}/g; // 使用正则匹配 while (true) { const matched = re.exec(s); if (matched) { // @ts-expect-error r.push({ index: matched.index, length: matched[0].length }); } else { break; } } return r; }; const useStandardEllipsis: LintMdRule = { meta: { name: 'use-standard-ellipsis' }, create: (context) => { return { text: (node: MarkdownCodeNode) => { const text = node.value; const { line, column } = node.position.start; const toFixList: { index: number length: number }[] = findAllDotEllipsis(text).concat(findAllSingleEllipsis(text)); toFixList.forEach((item) => { context.report({ loc: { start: { line, column: column + item.index }, end: { --- bundled output (OSV-MAL flagged — LLM scope expansion) --- --- lib/utils/char-helper.js (bundled) --- "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.isEnglishCharacter = exports.isChineseCharacter = exports.isNumberCharacter = void 0; const isNumberCharacter = (value) => { return /^[0-9]$/.test(value); }; exports.isNumberCharacter = isNumberCharacter; const isChineseCharacter = (value) => { return /^[\u4E00-\u9FA5]$/.test(value); }; exports.isChineseCharacter = isChineseCharacter; const isEnglishCharacter = (value) => { return /^[a-zA-Z]$/.test(value); }; exports.isEnglishCharacter = isEnglishCharacter; //# sourceMappingURL=char-helper.js.map --- lib/utils/rule-manager.js (bundled) --- "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.createRuleManager = void 0; const lodash_1 = require("lodash"); const fixer_1 = require("./fixer"); const createRuleManager = (appliedMarkdown) => { const fixer = (0, fixer_1.createFixer)(); const allReportedData = []; const getReportData = () => { return allReportedData; }; const getAllFixes = () => { return allReportedData .filter((item) => { return (0, lodash_1.isFunction)(item.fix); }) .map((item) => { const fix = item.fix(fixer); return { ...fix, targetRule: item.name }; }); }; const createRuleContext = (ruleConfig, data) => { const { rule, options } = ruleConfig; const report = (option) => { const location = option.loc; const markStart = Math.max(0, location.start.offset - 5); const markEnd = Math.min(appliedMarkdown.length, location.end.offset + 5); allReportedData.push({ ...option, content: appliedMarkdown.slice(markStart, markEnd), name: rule.meta.name }); }; return { report, options: options || {}, ...data }; }; return { getReportData, getAllFixes, createRuleContext }; }; exports.createRuleManager = createRuleManager; //# sourceMappingURL=rule-manager.js.map --- lib/rules/correct-title-trailing-punctuation.js (bundled) --- "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); const get_text_nodes_1 = require("../utils/get-text-nodes"); const FORBIDDEN_PUNCTUATIONS = ['.', ',', ';', ':', '。', ',', ';', ':', '~', '*', '`']; const correctTitleTrailingPunctuation = { meta: { name: 'correct-title-trailing-punctuation', }, create: (context) => { return { heading: (node) => { const lastTextNode = (0, get_text_nodes_1.getTextNodes)(node).pop(); if (lastTextNode) { const val = lastTextNode.value.trimEnd(); let endPos; for (endPos = val.length - 1; endPos >= 0; endPos--) { const currentCharacter = val[endPos]; if (!FORBIDDEN_PUNCTUATIONS.includes(currentCharacter)) { break; } } if (endPos < val.length - 1) { context.report({ loc: node.position, message: '标题末尾不允许出现不规范的标点符号', fix: (fixer) => { return fixer.replaceTextRange([ lastTextNode.position.start.offset, lastTextNode.position.end.offset ], val.slice(0, endPos + 1)); } }); } } } }; } }; exports.default = correctTitleTrailingPunctuation; //# sourceMappingURL=correct-title-trailing-punctuation.js.map --- lib/rules/no-empty-blockquote.js (bundled) --- "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); const noEmptyBlockquote = { meta: { name: 'no-empty-blockquote' }, create: (context) => { return { blockquote: (node) => { if (!node.children || node.children.length === 0) { context.report({ fix(fixer) { return fixer.removeRange([ node.position.start.offset, node.position.end.offset ]); }, loc: node.position, message: '引用块内容不能为空' }); } } }; } }; exports.default = noEmptyBlockquote; //# sourceMappingURL=no-empty-blockquote.js.map --- lib/rules/no-full-width-number.js (bundled) --- "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); const FULL_WIDTH_NUMBER_REPLACEMENT_MAP = { '1': 1, '2': 2, '3': 3, '4': 4, '5': 5, '6': 6, '7': 7, '8': 8, '9': 9, '0': 0 }; const findAllFullWidthNumbers = (s) => { const re = /[0-9]+/g; const r = []; while (true) { const matched = re.exec(s); if (matched) { r.push({ number: matched[0], index: matched.index }); } else { break; } } return r; }; const noFullWidthNumber = { meta: { name: 'no-full-width-number' }, create: (context) => { return { text: (node) => { const text = node.value; const fullWidthNumbers = findAllFullWidthNumbers(text); fullWidthNumbers.forEach((res) => { const { index, number } = res; const { line: startLine, column: startColumn, offset: startOffset } = node.position.start; const startPos = startColumn + index; const endPos = startColumn + index + number.length; context.report({ loc: { start: { line: startLine, column: startPos }, end: { line: startLine, column: endPos } }, message: '不能用全角数字,请使用半角数字', fix: (fixer) => { const replacement = number.split('').map(c => `${FULL_WIDTH_NUMBER_REPLACEMENT_MAP[c]}`).join(''); return fixer.replaceTextRange([startOffset + index, startOffset + index + number.length], replacement); --- lib/rules/no-multiple-space-blockquote.js (bundled) --- "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); const noMultipleSpaceBlockquote = { meta: { name: 'no-multiple-space-blockquote' }, create: (context) => { return { blockquote: (node) => { const blockQuoteColumn = node.position.start.column; const firstChild = node.children[0]; if (firstChild) { const blockQuoteFirstChildColumn = firstChild.position.start.column; const deltaColumn = blockQuoteFirstChildColumn - blockQuoteColumn; if (deltaColumn !== 2) { const fixStartRange = node.position.start.offset + 1; const fixEndRange = deltaColumn > 0 ? node.position.start.offset + deltaColumn : fixStartRange + 1; context.report({ loc: node.position, message: '块引用只允许有一个空格',
