@longzai-intelligence-git/gitignore-formatter 0.1.6 → 0.1.8
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 +13 -0
- package/dist/index.d.ts +64 -2
- package/dist/index.js +11 -10
- package/package.json +10 -3
package/README.md
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
# @longzai-intelligence-git/gitignore-formatter
|
|
2
|
+
|
|
3
|
+
Longzai Intelligence Git 的 .gitignore 格式化业务逻辑。
|
|
4
|
+
|
|
5
|
+
## 简介
|
|
6
|
+
|
|
7
|
+
治理 .gitignore 文件的格式化口径:把行分类、语义安全归一化与分组编排沉淀为独立业务逻辑包,使各端与命令行的格式化行为一致、可配置、无运行时副作用。
|
|
8
|
+
|
|
9
|
+
## 能力
|
|
10
|
+
|
|
11
|
+
- 行分类:空行 / 注释 / 模式 / negation 识别与模式分组匹配
|
|
12
|
+
- 语义安全归一化:行结束符、尾空白、去重、空行合并
|
|
13
|
+
- 分组编排:按配置重组分组或保留原分组输出
|
package/dist/index.d.ts
CHANGED
|
@@ -114,6 +114,66 @@ declare function stripTrailingWhitespace(line: string): string;
|
|
|
114
114
|
*/
|
|
115
115
|
declare function normalizeGitignore(content: string, dedupe?: boolean): string;
|
|
116
116
|
//#endregion
|
|
117
|
+
//#region src/forbidden.utils.d.ts
|
|
118
|
+
/**
|
|
119
|
+
* 禁止忽略项检出引擎。
|
|
120
|
+
*
|
|
121
|
+
* 清单内的文件必须被 git 跟踪,任何忽略模式命中即为违例。
|
|
122
|
+
* `format` 在格式化时政策性剔除命中的忽略模式行,`check` 依据本引擎的检出报告违规。
|
|
123
|
+
* 判定口径与 git 语义对齐:忽略模式在 git 语义下会忽略仓根目标文件即命中,
|
|
124
|
+
* negation 取反行本身是解禁表达,视为合规。
|
|
125
|
+
*/
|
|
126
|
+
/**
|
|
127
|
+
* 单条禁止项违规明细。
|
|
128
|
+
*/
|
|
129
|
+
type ForbiddenHit = {
|
|
130
|
+
/**
|
|
131
|
+
* 违规行在原文件中的行号,1 起始。
|
|
132
|
+
*/
|
|
133
|
+
readonly line: number;
|
|
134
|
+
/**
|
|
135
|
+
* 违规模式原文,即去首尾空白后的行内容。
|
|
136
|
+
*/
|
|
137
|
+
readonly pattern: string;
|
|
138
|
+
/**
|
|
139
|
+
* 被该模式命中的禁止项目标文件名。
|
|
140
|
+
*/
|
|
141
|
+
readonly target: string;
|
|
142
|
+
};
|
|
143
|
+
/**
|
|
144
|
+
* 判断一条忽略模式是否命中任一禁止项目标。
|
|
145
|
+
*
|
|
146
|
+
* 判定分两层:先做分类等价的精确判定,尾斜杠误写形态在此按等价命中,
|
|
147
|
+
* 再做 glob 通配判定,覆盖 `CLAUDE*` 与 `*.md` 一类宽模式。
|
|
148
|
+
* 目标恒为仓根文件名,因此含中间斜杠的子路径锚定模式不命中,
|
|
149
|
+
* 根锚定前导斜杠与双星任意层级前缀剥离后按文件名匹配。
|
|
150
|
+
*
|
|
151
|
+
* @param pattern - 忽略模式,应为非 negation 的模式行
|
|
152
|
+
* @param targets - 禁止项目标清单
|
|
153
|
+
* @returns 命中的目标文件名,未命中返回 undefined
|
|
154
|
+
*/
|
|
155
|
+
declare function matchForbiddenTarget(pattern: string, targets: readonly string[]): string | undefined;
|
|
156
|
+
/**
|
|
157
|
+
* 判断单条已归一化的模式是否命中禁止项。
|
|
158
|
+
*
|
|
159
|
+
* format 的政策性剔除与分组注入源过滤均以本函数为准。
|
|
160
|
+
*
|
|
161
|
+
* @param pattern - 已归一化的模式行
|
|
162
|
+
* @param targets - 禁止项目标清单
|
|
163
|
+
* @returns 是否命中
|
|
164
|
+
*/
|
|
165
|
+
declare function isForbiddenPattern(pattern: string, targets: readonly string[]): boolean;
|
|
166
|
+
/**
|
|
167
|
+
* 检出文件内容中命中禁止项的全部违规行。
|
|
168
|
+
*
|
|
169
|
+
* 空行、注释行与 negation 取反行不参与判定。
|
|
170
|
+
*
|
|
171
|
+
* @param content - 原始 .gitignore 内容
|
|
172
|
+
* @param targets - 禁止项目标清单,空清单直接返回空数组
|
|
173
|
+
* @returns 违规明细数组,按行序排列
|
|
174
|
+
*/
|
|
175
|
+
declare function findForbiddenPatterns(content: string, targets: readonly string[]): ForbiddenHit[];
|
|
176
|
+
//#endregion
|
|
117
177
|
//#region src/format.d.ts
|
|
118
178
|
/**
|
|
119
179
|
* .gitignore 格式化引擎(presets + inject + 分组编排)。
|
|
@@ -174,7 +234,9 @@ type GitignoreFileContext = {
|
|
|
174
234
|
* .gitignore 格式化入口。
|
|
175
235
|
*
|
|
176
236
|
* 根据配置决定是按 preset+groups 重组(含 inject)还是保留原分组,统一应用归一化规则。
|
|
177
|
-
* 缺失 config.gitignore 时退化为纯归一化(无分组、无 inject
|
|
237
|
+
* 缺失 config.gitignore 时退化为纯归一化(无分组、无 inject、无禁止项剔除)。
|
|
238
|
+
* 存在 gitignore 配置时,命中禁止项的忽略模式行在两条编排路径下均被政策性剔除,
|
|
239
|
+
* 分组注入源中的命中模式同步过滤,杜绝违规模式经注入回流。
|
|
178
240
|
*
|
|
179
241
|
* @param content - 原始 .gitignore 内容
|
|
180
242
|
* @param config - lzi-git.config.ts 解析得到的配置(可为 undefined,表示无配置文件)
|
|
@@ -183,4 +245,4 @@ type GitignoreFileContext = {
|
|
|
183
245
|
*/
|
|
184
246
|
declare function formatGitignore(content: string, config?: LziGitConfig, fileContext?: GitignoreFileContext): string;
|
|
185
247
|
//#endregion
|
|
186
|
-
export { GitignoreFileContext, classifyEquivalent, classifyPattern, formatGitignore, formatGroupHeader, getNegationBody, isBlankLine, isCommentLine, isNegationPattern, normalizeGitignore, resolveEnabledPresets, resolveOptions, stripTrailingWhitespace };
|
|
248
|
+
export { ForbiddenHit, GitignoreFileContext, classifyEquivalent, classifyPattern, findForbiddenPatterns, formatGitignore, formatGroupHeader, getNegationBody, isBlankLine, isCommentLine, isForbiddenPattern, isNegationPattern, matchForbiddenTarget, normalizeGitignore, resolveEnabledPresets, resolveOptions, stripTrailingWhitespace };
|
package/dist/index.js
CHANGED
|
@@ -1,12 +1,13 @@
|
|
|
1
|
-
import{
|
|
1
|
+
import{DEFAULT_GITIGNORE_FORBIDDEN as e,DEFAULT_GITIGNORE_OPTIONS as t,GITIGNORE_PRESETS as n}from"@longzai-intelligence-git/config";function r(e){return e.trim().length===0}function i(e){let t=e.trimStart();return t.length!==0&&t[0]===`#`}function a(e){let t=e.trimStart();return t.length!==0&&t[0]===`!`}function o(e){return e.trimStart().slice(1)}function s(e,t){return e===t||(e.endsWith(`/`)?e.slice(0,-1):e)===(t.endsWith(`/`)?t.slice(0,-1):t)}function c(e,t){let n=e;for(let e=0;e<t.length;e+=1){let r=t[e];if(r!==void 0&&r.patterns.some(e=>s(n,e)))return e}return null}function l(e){if(i(e))return e;let t=e.length;for(;t>0;){let n=e[t-1];if(n===void 0)break;if(n===` `||n===` `){if(e[t-2]===`\\`)break;--t}else break}return e.slice(0,t)}function u(e){return e.replace(/\r\n/g,`
|
|
2
2
|
`).replace(/\r/g,`
|
|
3
3
|
`).split(`
|
|
4
|
-
`).map(e=>
|
|
5
|
-
`)}\n`}function
|
|
6
|
-
`)
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
`))
|
|
10
|
-
`),
|
|
11
|
-
|
|
12
|
-
|
|
4
|
+
`).map(e=>l(e))}function d(e,t){if(!t)return e;let n=/* @__PURE__ */ new Set,a=[];for(let t of e){if(r(t)||i(t)){a.push(t);continue}n.has(t)||(n.add(t),a.push(t))}return a}function f(e){let t=[];for(let n of e){if(r(n)){t.length>0&&!r(t[t.length-1]??``)&&t.push(``);continue}t.push(n)}for(;t.length>0&&r(t[t.length-1]??``);)t.pop();return t}function p(e,t=!0){let n=f(d(u(e),t));return n.length===0?``:`${n.join(`
|
|
5
|
+
`)}\n`}function m(e,t){let n=`^${[...e].map(e=>e===`*`?`[^/]*`:e===`?`?`[^/]`:e.replace(/[.*+?^${}()|[\]\\]/g,`\\$&`)).join(``)}$`;return new RegExp(n).test(t)}function h(e,t){for(let n of t)if(s(e,n))return n;let n=e;if(n.startsWith(`/`))n=n.slice(1);else if(n.startsWith(`**/`))n=n.slice(3);else if(n.includes(`/`))return;if(!(n.length===0||n.includes(`/`)||n.endsWith(`/`))){for(let e of t)if(m(n,e))return e}}function g(e,t){return h(e,t)!==void 0}function _(e,t){if(t.length===0)return[];let n=e.split(`
|
|
6
|
+
`),o=[];for(let e=0;e<n.length;e+=1){let s=n[e]??``;if(r(s)||i(s))continue;let c=s.trim();if(a(c))continue;let l=h(c,t);l!==void 0&&o.push({line:e+1,pattern:c,target:l})}return o}function v(e){return{...t,...e}}function y(e,t){let n=a(e),r=a(t);if(n!==r)return n?1:-1;let i=n?o(e):e,s=r?o(t):t;return i===s?e<t?-1:+(e>t):i<s?-1:1}function b(e){let t=p(e,!0);return t===``?[]:t.split(`
|
|
7
|
+
`).filter(e=>!r(e)&&!i(e))}function x(e){let t=e.trim();return t.startsWith(`#`)?t:`# ${t}`}function S(e){if(e===void 0)return[];let t=Object.keys(n),r=[];for(let i of t){let t=n[i];t!==void 0&&(e[i]??t.default)&&r.push({comment:t.comment,patterns:[...t.patterns]})}return r}function C(e,t){return t===void 0||t.length===0?e:[...e,...t]}function w(e,t,n,r){let i=`
|
|
8
|
+
`.repeat(Math.max(0,n.blankLinesBetweenGroups)+1),a=[],o=/* @__PURE__ */ new Set;for(let i of t){if(i===void 0)continue;let t=[];for(let n of e)o.has(n)||i.patterns.some(e=>s(n,e))&&(t.push(n),o.add(n));if(r)for(let n of i.patterns)e.some(e=>s(e,n))||t.push(n);if(t.length===0){r&&a.push(x(i.comment));continue}n.sortWithinGroup&&t.sort(y),a.push([x(i.comment),...t].join(`
|
|
9
|
+
`))}let c=e.filter(e=>!o.has(e));return c.length>0&&(n.sortWithinGroup&&c.sort(y),a.push([x(n.miscGroupComment),...c].join(`
|
|
10
|
+
`))),a.length===0?``:`${a.join(i)}\n`}function T(e,t,n){let a=p(e,t.dedupe);if(a===``)return``;let o=a.split(`
|
|
11
|
+
`),s=[],c={header:null,patterns:[]},l=!1;for(let e of o)if(!r(e)){if(i(e))l&&s.push(c),c={header:e,patterns:[]},l=!0;else if(n.length>0&&g(e,n))continue;else c.patterns.push(e),l=!0}if(l&&s.push(c),t.sortWithinGroup)for(let e of s)e.patterns.sort(y);let u=`
|
|
12
|
+
`.repeat(Math.max(0,t.blankLinesBetweenGroups)+1),d=s.map(e=>{let t=[];return e.header!==null&&t.push(e.header),t.push(...e.patterns),t.join(`
|
|
13
|
+
`)}).filter(e=>e.length>0);return d.length===0?``:`${d.join(u)}\n`}function E(t,n,r){let i=n?.gitignore;if(i===void 0)return p(t,!0);let a=v(i.options),o=i.forbidden??e;if(a.groupByConfig){let e=r?.isRoot??!0,n=a.injectMode===`always`||e;return w(b(t).filter(e=>!g(e,o)),C(S(i.presets),i.groups).map(e=>({...e,patterns:e.patterns.filter(e=>!g(e,o))})),a,n)}return T(t,a,o)}export{s as classifyEquivalent,c as classifyPattern,_ as findForbiddenPatterns,E as formatGitignore,x as formatGroupHeader,o as getNegationBody,r as isBlankLine,i as isCommentLine,g as isForbiddenPattern,a as isNegationPattern,h as matchForbiddenTarget,p as normalizeGitignore,S as resolveEnabledPresets,v as resolveOptions,l as stripTrailingWhitespace};
|
package/package.json
CHANGED
|
@@ -1,7 +1,14 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@longzai-intelligence-git/gitignore-formatter",
|
|
3
|
-
"version": "0.1.
|
|
4
|
-
"description": "Longzai Intelligence Git
|
|
3
|
+
"version": "0.1.8",
|
|
4
|
+
"description": "Longzai Intelligence Git Gitignore 格式化器",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"longzai-intelligence",
|
|
7
|
+
"git",
|
|
8
|
+
"gitignore",
|
|
9
|
+
"formatter",
|
|
10
|
+
"format"
|
|
11
|
+
],
|
|
5
12
|
"files": [
|
|
6
13
|
"dist"
|
|
7
14
|
],
|
|
@@ -30,7 +37,7 @@
|
|
|
30
37
|
"clean": "lzi-dev-cli clean"
|
|
31
38
|
},
|
|
32
39
|
"dependencies": {
|
|
33
|
-
"@longzai-intelligence-git/config": "0.1.
|
|
40
|
+
"@longzai-intelligence-git/config": "0.1.8"
|
|
34
41
|
},
|
|
35
42
|
"devDependencies": {},
|
|
36
43
|
"peerDependencies": {}
|