project-logbook 0.4.1 → 1.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +38 -2
- package/dist/commands/build.js +75 -85
- package/dist/commands/build.js.map +1 -0
- package/dist/commands/init.js +1 -0
- package/dist/commands/init.js.map +1 -0
- package/dist/commands/lint.js +9 -3
- package/dist/commands/lint.js.map +1 -0
- package/dist/commands/list.js +14 -26
- package/dist/commands/list.js.map +1 -0
- package/dist/commands/log.d.ts +1 -3
- package/dist/commands/log.js +28 -4
- package/dist/commands/log.js.map +1 -0
- package/dist/commands/new.d.ts +4 -1
- package/dist/commands/new.js +73 -52
- package/dist/commands/new.js.map +1 -0
- package/dist/commands/preview.js +1 -0
- package/dist/commands/preview.js.map +1 -0
- package/dist/commands/release.js +2 -1
- package/dist/commands/release.js.map +1 -0
- package/dist/commands/start.d.ts +1 -1
- package/dist/commands/start.js +76 -16
- package/dist/commands/start.js.map +1 -0
- package/dist/commands/status.js +10 -18
- package/dist/commands/status.js.map +1 -0
- package/dist/commands/steer.js +1 -0
- package/dist/commands/steer.js.map +1 -0
- package/dist/commands/upgrade.js +1 -0
- package/dist/commands/upgrade.js.map +1 -0
- package/dist/index.js +7 -5
- package/dist/index.js.map +1 -0
- package/dist/lib/about-content.js +1 -0
- package/dist/lib/about-content.js.map +1 -0
- package/dist/lib/adr-renderer.d.ts +12 -0
- package/dist/lib/adr-renderer.js +53 -0
- package/dist/lib/adr-renderer.js.map +1 -0
- package/dist/lib/autolink.d.ts +15 -0
- package/dist/lib/autolink.js +39 -0
- package/dist/lib/autolink.js.map +1 -0
- package/dist/lib/build-helpers.d.ts +1 -1
- package/dist/lib/build-helpers.js +24 -7
- package/dist/lib/build-helpers.js.map +1 -0
- package/dist/lib/build-steps.d.ts +16 -2
- package/dist/lib/build-steps.js +124 -20
- package/dist/lib/build-steps.js.map +1 -0
- package/dist/lib/config.d.ts +22 -0
- package/dist/lib/config.js +29 -1
- package/dist/lib/config.js.map +1 -0
- package/dist/lib/custom-card-renderer.d.ts +2 -0
- package/dist/lib/custom-card-renderer.js +58 -0
- package/dist/lib/custom-card-renderer.js.map +1 -0
- package/dist/lib/custom-types-builder.d.ts +4 -0
- package/dist/lib/custom-types-builder.js +37 -0
- package/dist/lib/custom-types-builder.js.map +1 -0
- package/dist/lib/entry-id.js +1 -0
- package/dist/lib/entry-id.js.map +1 -0
- package/dist/lib/entry-paths.js +1 -0
- package/dist/lib/entry-paths.js.map +1 -0
- package/dist/lib/git-helpers.d.ts +5 -16
- package/dist/lib/git-helpers.js +61 -78
- package/dist/lib/git-helpers.js.map +1 -0
- package/dist/lib/git-url-helpers.d.ts +16 -0
- package/dist/lib/git-url-helpers.js +76 -0
- package/dist/lib/git-url-helpers.js.map +1 -0
- package/dist/lib/hast-helpers.js +1 -0
- package/dist/lib/hast-helpers.js.map +1 -0
- package/dist/lib/html-attributes.js +1 -0
- package/dist/lib/html-attributes.js.map +1 -0
- package/dist/lib/html-escape.js +1 -0
- package/dist/lib/html-escape.js.map +1 -0
- package/dist/lib/image-dimension-parser.d.ts +11 -0
- package/dist/lib/image-dimension-parser.js +127 -0
- package/dist/lib/image-dimension-parser.js.map +1 -0
- package/dist/lib/image-helpers.d.ts +2 -0
- package/dist/lib/image-helpers.js +22 -30
- package/dist/lib/image-helpers.js.map +1 -0
- package/dist/lib/jira-helpers.js +1 -0
- package/dist/lib/jira-helpers.js.map +1 -0
- package/dist/lib/lint-runner.js +1 -0
- package/dist/lib/lint-runner.js.map +1 -0
- package/dist/lib/lint-types.js +1 -0
- package/dist/lib/lint-types.js.map +1 -0
- package/dist/lib/lockfile.js +1 -0
- package/dist/lib/lockfile.js.map +1 -0
- package/dist/lib/logbook-client.js +1 -0
- package/dist/lib/logbook-client.js.map +1 -0
- package/dist/lib/markdown-processors.js +1 -0
- package/dist/lib/markdown-processors.js.map +1 -0
- package/dist/lib/migrations.js +1 -0
- package/dist/lib/migrations.js.map +1 -0
- package/dist/lib/package-version.js +1 -0
- package/dist/lib/package-version.js.map +1 -0
- package/dist/lib/post-template.d.ts +5 -0
- package/dist/lib/post-template.js +48 -0
- package/dist/lib/post-template.js.map +1 -0
- package/dist/lib/rss.js +1 -0
- package/dist/lib/rss.js.map +1 -0
- package/dist/lib/session.d.ts +2 -2
- package/dist/lib/session.js +75 -35
- package/dist/lib/session.js.map +1 -0
- package/dist/lib/styles.js +1 -0
- package/dist/lib/styles.js.map +1 -0
- package/dist/lib/template-helpers.d.ts +6 -1
- package/dist/lib/template-helpers.js +81 -1
- package/dist/lib/template-helpers.js.map +1 -0
- package/dist/lib/template-types.d.ts +37 -5
- package/dist/lib/template-types.js +1 -0
- package/dist/lib/template-types.js.map +1 -0
- package/dist/lib/templates.d.ts +11 -8
- package/dist/lib/templates.js +59 -60
- package/dist/lib/templates.js.map +1 -0
- package/dist/lib/theme.js +1 -0
- package/dist/lib/theme.js.map +1 -0
- package/dist/lib/url-helpers.js +1 -0
- package/dist/lib/url-helpers.js.map +1 -0
- package/dist/linters/diff-to-narrative.d.ts +2 -1
- package/dist/linters/diff-to-narrative.js +3 -10
- package/dist/linters/diff-to-narrative.js.map +1 -0
- package/dist/linters/frontmatter.js +1 -0
- package/dist/linters/frontmatter.js.map +1 -0
- package/dist/linters/index.js +1 -0
- package/dist/linters/index.js.map +1 -0
- package/dist/linters/jira-prefix.js +1 -0
- package/dist/linters/jira-prefix.js.map +1 -0
- package/dist/linters/links.js +26 -4
- package/dist/linters/links.js.map +1 -0
- package/dist/linters/lockfile.js +1 -0
- package/dist/linters/lockfile.js.map +1 -0
- package/dist/linters/placeholders.js +6 -4
- package/dist/linters/placeholders.js.map +1 -0
- package/dist/linters/project-integrity.js +1 -0
- package/dist/linters/project-integrity.js.map +1 -0
- package/dist/linters/readability.js +2 -3
- package/dist/linters/readability.js.map +1 -0
- package/dist/linters/technical-log.js +1 -0
- package/dist/linters/technical-log.js.map +1 -0
- package/dist/linters/workspaces.js +1 -0
- package/dist/linters/workspaces.js.map +1 -0
- package/dist/templates/CONTRIBUTING.md +10 -1
- package/dist/templates/index.md +2 -1
- package/dist/templates/log.md +1 -1
- package/dist/templates/styles.css +171 -32
- package/dist/utils/date.js +1 -0
- package/dist/utils/date.js.map +1 -0
- package/dist/utils/frontmatter.d.ts +9 -0
- package/dist/utils/frontmatter.js +16 -0
- package/dist/utils/frontmatter.js.map +1 -0
- package/dist/utils/fs.d.ts +10 -0
- package/dist/utils/fs.js +112 -0
- package/dist/utils/fs.js.map +1 -0
- package/dist/utils/id.js +1 -0
- package/dist/utils/id.js.map +1 -0
- package/dist/utils/log-timeline.d.ts +2 -1
- package/dist/utils/log-timeline.js +1 -0
- package/dist/utils/log-timeline.js.map +1 -0
- package/dist/utils/slug.js +1 -0
- package/dist/utils/slug.js.map +1 -0
- package/dist/utils/string.js +1 -0
- package/dist/utils/string.js.map +1 -0
- package/dist/utils/timeline-helpers.d.ts +2 -2
- package/dist/utils/timeline-helpers.js +5 -2
- package/dist/utils/timeline-helpers.js.map +1 -0
- package/dist/utils/validation.d.ts +5 -0
- package/dist/utils/validation.js +21 -0
- package/dist/utils/validation.js.map +1 -0
- package/package.json +12 -6
- package/src/templates/CONTRIBUTING.md +10 -1
- package/src/templates/index.md +2 -1
- package/src/templates/log.md +1 -1
- package/src/templates/styles.css +171 -32
|
@@ -1,16 +1,5 @@
|
|
|
1
1
|
import type { GitCommit } from './template-types.js';
|
|
2
|
-
|
|
3
|
-
* Clean the repository URL by removing trailing slashes and .git extensions.
|
|
4
|
-
*/
|
|
5
|
-
export declare function cleanRepositoryUrl(url: string): string;
|
|
6
|
-
/**
|
|
7
|
-
* Generate a URL to view a specific commit in a web interface (GitHub, GitLab, Bitbucket, etc.).
|
|
8
|
-
*/
|
|
9
|
-
export declare function getCommitUrl(repositoryUrl: string | undefined, sha: string): string | undefined;
|
|
10
|
-
/**
|
|
11
|
-
* Generate a URL to view a specific tag in a web interface (GitHub, GitLab, Bitbucket, etc.).
|
|
12
|
-
*/
|
|
13
|
-
export declare function getTagUrl(repositoryUrl: string | undefined, tag: string): string | undefined;
|
|
2
|
+
export { cleanRepositoryUrl, getCommitUrl, getTagUrl, parseRemoteUrlToWebUrl } from './git-url-helpers.js';
|
|
14
3
|
/**
|
|
15
4
|
* Parse the raw output of `git log --pretty=format:"%H|%s|%aI"` into GitCommit objects.
|
|
16
5
|
* Pure function (no I/O) — unit-testable without spawning git.
|
|
@@ -39,15 +28,15 @@ export declare function getGitTags(): Promise<{
|
|
|
39
28
|
* Synchronous execution — safe to use during synchronous config parsing.
|
|
40
29
|
*/
|
|
41
30
|
export declare function getGitRemoteUrl(cwd?: string): string | undefined;
|
|
42
|
-
/**
|
|
43
|
-
* Parse a git remote URL (SSH or HTTPS) into a clean web/HTTP(S) repository homepage URL.
|
|
44
|
-
*/
|
|
45
|
-
export declare function parseRemoteUrlToWebUrl(remoteUrl: string | undefined): string | undefined;
|
|
46
31
|
/**
|
|
47
32
|
* Synchronous branch detection — used in session resolution (not the build pipeline).
|
|
48
33
|
* Kept synchronous intentionally; simple-git is used for the heavier async build operations.
|
|
49
34
|
*/
|
|
50
35
|
export declare function getCurrentBranch(cwd?: string): string | undefined;
|
|
36
|
+
/**
|
|
37
|
+
* Dynamically detect the default branch (usually main or master).
|
|
38
|
+
*/
|
|
39
|
+
export declare function getDefaultBranch(cwd?: string): string;
|
|
51
40
|
/**
|
|
52
41
|
* Calculate the changed LOC (insertions + deletions) for the active branch or main working tree.
|
|
53
42
|
*/
|
package/dist/lib/git-helpers.js
CHANGED
|
@@ -1,55 +1,6 @@
|
|
|
1
1
|
import { execSync } from 'node:child_process';
|
|
2
2
|
import { simpleGit } from 'simple-git';
|
|
3
|
-
|
|
4
|
-
* Clean the repository URL by removing trailing slashes and .git extensions.
|
|
5
|
-
*/
|
|
6
|
-
export function cleanRepositoryUrl(url) {
|
|
7
|
-
let cleaned = url.trim();
|
|
8
|
-
if (cleaned.endsWith('/')) {
|
|
9
|
-
cleaned = cleaned.slice(0, -1);
|
|
10
|
-
}
|
|
11
|
-
if (cleaned.endsWith('.git')) {
|
|
12
|
-
cleaned = cleaned.slice(0, -4);
|
|
13
|
-
}
|
|
14
|
-
if (cleaned.endsWith('/')) {
|
|
15
|
-
cleaned = cleaned.slice(0, -1);
|
|
16
|
-
}
|
|
17
|
-
return cleaned;
|
|
18
|
-
}
|
|
19
|
-
/**
|
|
20
|
-
* Generate a URL to view a specific commit in a web interface (GitHub, GitLab, Bitbucket, etc.).
|
|
21
|
-
*/
|
|
22
|
-
export function getCommitUrl(repositoryUrl, sha) {
|
|
23
|
-
if (!repositoryUrl)
|
|
24
|
-
return undefined;
|
|
25
|
-
const baseUrl = cleanRepositoryUrl(repositoryUrl);
|
|
26
|
-
const lowerUrl = baseUrl.toLowerCase();
|
|
27
|
-
if (lowerUrl.includes('gitlab')) {
|
|
28
|
-
return `${baseUrl}/-/commit/${sha}`;
|
|
29
|
-
}
|
|
30
|
-
if (lowerUrl.includes('bitbucket')) {
|
|
31
|
-
return `${baseUrl}/commits/${sha}`;
|
|
32
|
-
}
|
|
33
|
-
// Default to GitHub style
|
|
34
|
-
return `${baseUrl}/commit/${sha}`;
|
|
35
|
-
}
|
|
36
|
-
/**
|
|
37
|
-
* Generate a URL to view a specific tag in a web interface (GitHub, GitLab, Bitbucket, etc.).
|
|
38
|
-
*/
|
|
39
|
-
export function getTagUrl(repositoryUrl, tag) {
|
|
40
|
-
if (!repositoryUrl)
|
|
41
|
-
return undefined;
|
|
42
|
-
const baseUrl = cleanRepositoryUrl(repositoryUrl);
|
|
43
|
-
const lowerUrl = baseUrl.toLowerCase();
|
|
44
|
-
if (lowerUrl.includes('gitlab')) {
|
|
45
|
-
return `${baseUrl}/-/tags/${tag}`;
|
|
46
|
-
}
|
|
47
|
-
if (lowerUrl.includes('bitbucket')) {
|
|
48
|
-
return `${baseUrl}/src/${tag}`;
|
|
49
|
-
}
|
|
50
|
-
// Default to GitHub style
|
|
51
|
-
return `${baseUrl}/releases/tag/${tag}`;
|
|
52
|
-
}
|
|
3
|
+
export { cleanRepositoryUrl, getCommitUrl, getTagUrl, parseRemoteUrlToWebUrl } from './git-url-helpers.js';
|
|
53
4
|
function getGit() {
|
|
54
5
|
return simpleGit(process.cwd());
|
|
55
6
|
}
|
|
@@ -142,31 +93,6 @@ export function getGitRemoteUrl(cwd = process.cwd()) {
|
|
|
142
93
|
return undefined;
|
|
143
94
|
}
|
|
144
95
|
}
|
|
145
|
-
/**
|
|
146
|
-
* Parse a git remote URL (SSH or HTTPS) into a clean web/HTTP(S) repository homepage URL.
|
|
147
|
-
*/
|
|
148
|
-
export function parseRemoteUrlToWebUrl(remoteUrl) {
|
|
149
|
-
if (!remoteUrl)
|
|
150
|
-
return undefined;
|
|
151
|
-
let url = remoteUrl.trim();
|
|
152
|
-
// If it's already an HTTP/HTTPS URL, clean and return it
|
|
153
|
-
if (url.startsWith('https://') || url.startsWith('http://')) {
|
|
154
|
-
return cleanRepositoryUrl(url);
|
|
155
|
-
}
|
|
156
|
-
// Strip ssh:// scheme and git@ user if present
|
|
157
|
-
if (url.startsWith('ssh://')) {
|
|
158
|
-
url = url.slice(6);
|
|
159
|
-
}
|
|
160
|
-
if (url.startsWith('git@')) {
|
|
161
|
-
url = url.slice(4);
|
|
162
|
-
}
|
|
163
|
-
// Replace first colon with slash to map SSH path to web path (e.g. host:owner/repo -> host/owner/repo)
|
|
164
|
-
const firstColon = url.indexOf(':');
|
|
165
|
-
if (firstColon !== -1) {
|
|
166
|
-
url = url.slice(0, firstColon) + '/' + url.slice(firstColon + 1);
|
|
167
|
-
}
|
|
168
|
-
return `https://${cleanRepositoryUrl(url)}`;
|
|
169
|
-
}
|
|
170
96
|
/**
|
|
171
97
|
* Synchronous branch detection — used in session resolution (not the build pipeline).
|
|
172
98
|
* Kept synchronous intentionally; simple-git is used for the heavier async build operations.
|
|
@@ -183,19 +109,75 @@ export function getCurrentBranch(cwd = process.cwd()) {
|
|
|
183
109
|
return undefined;
|
|
184
110
|
}
|
|
185
111
|
}
|
|
112
|
+
/**
|
|
113
|
+
* Dynamically detect the default branch (usually main or master).
|
|
114
|
+
*/
|
|
115
|
+
export function getDefaultBranch(cwd = process.cwd()) {
|
|
116
|
+
try {
|
|
117
|
+
// 1. Try checking the remote HEAD reference
|
|
118
|
+
const remoteHead = execSync('git symbolic-ref refs/remotes/origin/HEAD', {
|
|
119
|
+
encoding: 'utf8',
|
|
120
|
+
cwd,
|
|
121
|
+
stdio: ['ignore', 'pipe', 'ignore'],
|
|
122
|
+
}).trim();
|
|
123
|
+
if (remoteHead) {
|
|
124
|
+
const parts = remoteHead.split('/');
|
|
125
|
+
const branch = parts[parts.length - 1];
|
|
126
|
+
if (branch)
|
|
127
|
+
return branch;
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
catch {
|
|
131
|
+
// Ignore and proceed
|
|
132
|
+
}
|
|
133
|
+
try {
|
|
134
|
+
// 2. Check if local main branch exists
|
|
135
|
+
execSync('git show-ref --verify refs/heads/main', {
|
|
136
|
+
cwd,
|
|
137
|
+
stdio: 'ignore',
|
|
138
|
+
});
|
|
139
|
+
return 'main';
|
|
140
|
+
}
|
|
141
|
+
catch {
|
|
142
|
+
// Ignore and proceed
|
|
143
|
+
}
|
|
144
|
+
try {
|
|
145
|
+
// 3. Check if local master branch exists
|
|
146
|
+
execSync('git show-ref --verify refs/heads/master', {
|
|
147
|
+
cwd,
|
|
148
|
+
stdio: 'ignore',
|
|
149
|
+
});
|
|
150
|
+
return 'master';
|
|
151
|
+
}
|
|
152
|
+
catch {
|
|
153
|
+
// Ignore and proceed
|
|
154
|
+
}
|
|
155
|
+
// 4. Ultimate fallback
|
|
156
|
+
return 'main';
|
|
157
|
+
}
|
|
186
158
|
/**
|
|
187
159
|
* Calculate the changed LOC (insertions + deletions) for the active branch or main working tree.
|
|
188
160
|
*/
|
|
189
161
|
export async function getChangedLOC(logbookDir, cwd = process.cwd()) {
|
|
190
162
|
try {
|
|
191
|
-
const
|
|
163
|
+
const defaultBranch = getDefaultBranch(cwd);
|
|
164
|
+
const branchName = getCurrentBranch(cwd) || defaultBranch;
|
|
192
165
|
const git = simpleGit(cwd);
|
|
193
166
|
let summary;
|
|
194
|
-
if (branchName ===
|
|
167
|
+
if (branchName === defaultBranch) {
|
|
195
168
|
summary = await git.diffSummary(['HEAD', '--', '.', `:!${logbookDir}`]);
|
|
196
169
|
}
|
|
197
170
|
else {
|
|
198
|
-
|
|
171
|
+
let mergeBase = defaultBranch;
|
|
172
|
+
try {
|
|
173
|
+
const base = await git.raw(['merge-base', defaultBranch, 'HEAD']);
|
|
174
|
+
if (base.trim())
|
|
175
|
+
mergeBase = base.trim();
|
|
176
|
+
}
|
|
177
|
+
catch {
|
|
178
|
+
// Fallback to defaultBranch
|
|
179
|
+
}
|
|
180
|
+
summary = await git.diffSummary([mergeBase, '--', '.', `:!${logbookDir}`]);
|
|
199
181
|
}
|
|
200
182
|
return {
|
|
201
183
|
total: summary.insertions + summary.deletions,
|
|
@@ -207,3 +189,4 @@ export async function getChangedLOC(logbookDir, cwd = process.cwd()) {
|
|
|
207
189
|
return { total: 0, insertions: 0, deletions: 0 };
|
|
208
190
|
}
|
|
209
191
|
}
|
|
192
|
+
//# sourceMappingURL=git-helpers.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"git-helpers.js","sourceRoot":"","sources":["../../src/lib/git-helpers.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Clean the repository URL by removing trailing slashes and .git extensions.
|
|
3
|
+
*/
|
|
4
|
+
export declare function cleanRepositoryUrl(url: string): string;
|
|
5
|
+
/**
|
|
6
|
+
* Generate a URL to view a specific commit in a web interface (GitHub, GitLab, Bitbucket, etc.).
|
|
7
|
+
*/
|
|
8
|
+
export declare function getCommitUrl(repositoryUrl: string | undefined, sha: string): string | undefined;
|
|
9
|
+
/**
|
|
10
|
+
* Generate a URL to view a specific tag in a web interface (GitHub, GitLab, Bitbucket, etc.).
|
|
11
|
+
*/
|
|
12
|
+
export declare function getTagUrl(repositoryUrl: string | undefined, tag: string): string | undefined;
|
|
13
|
+
/**
|
|
14
|
+
* Parse a git remote URL (SSH or HTTPS) into a clean web/HTTP(S) repository homepage URL.
|
|
15
|
+
*/
|
|
16
|
+
export declare function parseRemoteUrlToWebUrl(remoteUrl: string | undefined): string | undefined;
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Clean the repository URL by removing trailing slashes and .git extensions.
|
|
3
|
+
*/
|
|
4
|
+
export function cleanRepositoryUrl(url) {
|
|
5
|
+
let cleaned = url.trim();
|
|
6
|
+
if (cleaned.endsWith('/')) {
|
|
7
|
+
cleaned = cleaned.slice(0, -1);
|
|
8
|
+
}
|
|
9
|
+
if (cleaned.endsWith('.git')) {
|
|
10
|
+
cleaned = cleaned.slice(0, -4);
|
|
11
|
+
}
|
|
12
|
+
if (cleaned.endsWith('/')) {
|
|
13
|
+
cleaned = cleaned.slice(0, -1);
|
|
14
|
+
}
|
|
15
|
+
return cleaned;
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Generate a URL to view a specific commit in a web interface (GitHub, GitLab, Bitbucket, etc.).
|
|
19
|
+
*/
|
|
20
|
+
export function getCommitUrl(repositoryUrl, sha) {
|
|
21
|
+
if (!repositoryUrl)
|
|
22
|
+
return undefined;
|
|
23
|
+
const baseUrl = cleanRepositoryUrl(repositoryUrl);
|
|
24
|
+
const lowerUrl = baseUrl.toLowerCase();
|
|
25
|
+
if (lowerUrl.includes('gitlab')) {
|
|
26
|
+
return `${baseUrl}/-/commit/${sha}`;
|
|
27
|
+
}
|
|
28
|
+
if (lowerUrl.includes('bitbucket')) {
|
|
29
|
+
return `${baseUrl}/commits/${sha}`;
|
|
30
|
+
}
|
|
31
|
+
// Default to GitHub style
|
|
32
|
+
return `${baseUrl}/commit/${sha}`;
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Generate a URL to view a specific tag in a web interface (GitHub, GitLab, Bitbucket, etc.).
|
|
36
|
+
*/
|
|
37
|
+
export function getTagUrl(repositoryUrl, tag) {
|
|
38
|
+
if (!repositoryUrl)
|
|
39
|
+
return undefined;
|
|
40
|
+
const baseUrl = cleanRepositoryUrl(repositoryUrl);
|
|
41
|
+
const lowerUrl = baseUrl.toLowerCase();
|
|
42
|
+
if (lowerUrl.includes('gitlab')) {
|
|
43
|
+
return `${baseUrl}/-/tags/${tag}`;
|
|
44
|
+
}
|
|
45
|
+
if (lowerUrl.includes('bitbucket')) {
|
|
46
|
+
return `${baseUrl}/src/${tag}`;
|
|
47
|
+
}
|
|
48
|
+
// Default to GitHub style
|
|
49
|
+
return `${baseUrl}/releases/tag/${tag}`;
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Parse a git remote URL (SSH or HTTPS) into a clean web/HTTP(S) repository homepage URL.
|
|
53
|
+
*/
|
|
54
|
+
export function parseRemoteUrlToWebUrl(remoteUrl) {
|
|
55
|
+
if (!remoteUrl)
|
|
56
|
+
return undefined;
|
|
57
|
+
let url = remoteUrl.trim();
|
|
58
|
+
// If it's already an HTTP/HTTPS URL, clean and return it
|
|
59
|
+
if (url.startsWith('https://') || url.startsWith('http://')) {
|
|
60
|
+
return cleanRepositoryUrl(url);
|
|
61
|
+
}
|
|
62
|
+
// Strip ssh:// scheme and git@ user if present
|
|
63
|
+
if (url.startsWith('ssh://')) {
|
|
64
|
+
url = url.slice(6);
|
|
65
|
+
}
|
|
66
|
+
if (url.startsWith('git@')) {
|
|
67
|
+
url = url.slice(4);
|
|
68
|
+
}
|
|
69
|
+
// Replace first colon with slash to map SSH path to web path (e.g. host:owner/repo -> host/owner/repo)
|
|
70
|
+
const firstColon = url.indexOf(':');
|
|
71
|
+
if (firstColon !== -1) {
|
|
72
|
+
url = url.slice(0, firstColon) + '/' + url.slice(firstColon + 1);
|
|
73
|
+
}
|
|
74
|
+
return `https://${cleanRepositoryUrl(url)}`;
|
|
75
|
+
}
|
|
76
|
+
//# sourceMappingURL=git-url-helpers.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"git-url-helpers.js","sourceRoot":"","sources":["../../src/lib/git-url-helpers.ts"],"names":[],"mappings":"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"}
|
package/dist/lib/hast-helpers.js
CHANGED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"hast-helpers.js","sourceRoot":"","sources":["../../src/lib/hast-helpers.ts"],"names":[],"mappings":"AAEA;;;;;;;GAOG;AACH,MAAM,UAAU,iBAAiB,CAC/B,IAAoB,EACpB,QAA2B,EAC3B,OAAgC;IAEhC,MAAM,WAAW,GAAG,IAAI,GAAG,CAAC,KAAK,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC;IAE7E,SAAS,QAAQ,CAAC,CAAiB;QACjC,KAAK,MAAM,KAAK,IAAI,CAAC,CAAC,QAAQ,EAAE,CAAC;YAC/B,IAAI,KAAK,CAAC,IAAI,KAAK,SAAS,EAAE,CAAC;gBAC7B,IAAI,WAAW,CAAC,GAAG,CAAC,KAAK,CAAC,OAAO,CAAC,EAAE,CAAC;oBACnC,OAAO,CAAC,KAAK,CAAC,CAAC;gBACjB,CAAC;gBACD,QAAQ,CAAC,KAAK,CAAC,CAAC;YAClB,CAAC;QACH,CAAC;IACH,CAAC;IAED,QAAQ,CAAC,IAAI,CAAC,CAAC;AACjB,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"html-attributes.js","sourceRoot":"","sources":["../../src/lib/html-attributes.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,kFAAkF;AAClF,MAAM,CAAC,MAAM,cAAc,GAAG,gBAAgB,CAAC;AAE/C,0DAA0D;AAC1D,MAAM,CAAC,MAAM,eAAe,GAAG,iBAAiB,CAAC;AAEjD,oEAAoE;AACpE,MAAM,CAAC,MAAM,cAAc,GAAG,WAAW,CAAC;AAE1C,wCAAwC;AACxC,MAAM,CAAC,MAAM,gBAAgB,GAAG,YAAY,CAAC;AAE7C,8CAA8C;AAC9C,MAAM,CAAC,MAAM,iBAAiB,GAAG,aAAa,CAAC;AAE/C,4CAA4C;AAC5C,MAAM,CAAC,MAAM,oBAAoB,GAAG,gBAAgB,CAAC"}
|
package/dist/lib/html-escape.js
CHANGED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"html-escape.js","sourceRoot":"","sources":["../../src/lib/html-escape.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,MAAM,UAAU,UAAU,CAAC,GAAW;IACpC,IAAI,CAAC,GAAG;QAAE,OAAO,EAAE,CAAC;IACpB,OAAO,GAAG;SACP,OAAO,CAAC,IAAI,EAAE,OAAO,CAAC;SACtB,OAAO,CAAC,IAAI,EAAE,MAAM,CAAC;SACrB,OAAO,CAAC,IAAI,EAAE,MAAM,CAAC;SACrB,OAAO,CAAC,IAAI,EAAE,QAAQ,CAAC;SACvB,OAAO,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;AAC5B,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,eAAe,CAAC,KAAa;IAC3C,OAAO,yDAAyD,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;AAC/E,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,iBAAiB,CAAC,GAAW;IAC3C,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,IAAI,GAAG,CAAC,GAAG,CAAC,CAAC;QAC5B,IAAI,MAAM,CAAC,QAAQ,KAAK,QAAQ,IAAI,MAAM,CAAC,QAAQ,KAAK,OAAO,EAAE,CAAC;YAChE,OAAO,GAAG,CAAC;QACb,CAAC;QACD,OAAO,SAAS,CAAC;IACnB,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,SAAS,CAAC;IACnB,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
interface ImageDimensions {
|
|
2
|
+
width: number;
|
|
3
|
+
height: number;
|
|
4
|
+
}
|
|
5
|
+
/**
|
|
6
|
+
* Parses local image headers to find width and height dimensions.
|
|
7
|
+
* Supports PNG, GIF, WebP, JPEG, and SVG.
|
|
8
|
+
* On error/unknown format, returns null.
|
|
9
|
+
*/
|
|
10
|
+
export declare function getImageDimensions(filePath: string): Promise<ImageDimensions | null>;
|
|
11
|
+
export {};
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
import fs from 'fs-extra';
|
|
2
|
+
/**
|
|
3
|
+
* Parses local image headers to find width and height dimensions.
|
|
4
|
+
* Supports PNG, GIF, WebP, JPEG, and SVG.
|
|
5
|
+
* On error/unknown format, returns null.
|
|
6
|
+
*/
|
|
7
|
+
export async function getImageDimensions(filePath) {
|
|
8
|
+
try {
|
|
9
|
+
if (!(await fs.pathExists(filePath))) {
|
|
10
|
+
return null;
|
|
11
|
+
}
|
|
12
|
+
const fd = await fs.open(filePath, 'r');
|
|
13
|
+
const buffer = Buffer.alloc(100);
|
|
14
|
+
await fs.read(fd, buffer, 0, 100, 0);
|
|
15
|
+
await fs.close(fd);
|
|
16
|
+
// 1. PNG
|
|
17
|
+
if (buffer[0] === 0x89 &&
|
|
18
|
+
buffer[1] === 0x50 &&
|
|
19
|
+
buffer[2] === 0x4e &&
|
|
20
|
+
buffer[3] === 0x47 &&
|
|
21
|
+
buffer[4] === 0x0d &&
|
|
22
|
+
buffer[5] === 0x0a &&
|
|
23
|
+
buffer[6] === 0x1a &&
|
|
24
|
+
buffer[7] === 0x0a) {
|
|
25
|
+
const width = buffer.readUInt32BE(16);
|
|
26
|
+
const height = buffer.readUInt32BE(20);
|
|
27
|
+
return { width, height };
|
|
28
|
+
}
|
|
29
|
+
// 2. GIF
|
|
30
|
+
if (buffer[0] === 0x47 &&
|
|
31
|
+
buffer[1] === 0x49 &&
|
|
32
|
+
buffer[2] === 0x46 &&
|
|
33
|
+
buffer[3] === 0x38 &&
|
|
34
|
+
(buffer[4] === 0x37 || buffer[4] === 0x39) &&
|
|
35
|
+
buffer[5] === 0x61) {
|
|
36
|
+
const width = buffer.readUInt16LE(6);
|
|
37
|
+
const height = buffer.readUInt16LE(8);
|
|
38
|
+
return { width, height };
|
|
39
|
+
}
|
|
40
|
+
// 3. WebP
|
|
41
|
+
if (buffer[0] === 0x52 &&
|
|
42
|
+
buffer[1] === 0x49 &&
|
|
43
|
+
buffer[2] === 0x46 &&
|
|
44
|
+
buffer[3] === 0x46 &&
|
|
45
|
+
buffer[8] === 0x57 &&
|
|
46
|
+
buffer[9] === 0x45 &&
|
|
47
|
+
buffer[10] === 0x42 &&
|
|
48
|
+
buffer[11] === 0x50) {
|
|
49
|
+
const type = buffer.toString('utf8', 12, 16);
|
|
50
|
+
if (type === 'VP8 ') {
|
|
51
|
+
const width = buffer.readUInt16LE(26) & 0x3fff;
|
|
52
|
+
const height = buffer.readUInt16LE(28) & 0x3fff;
|
|
53
|
+
return { width, height };
|
|
54
|
+
}
|
|
55
|
+
else if (type === 'VP8L') {
|
|
56
|
+
const val = buffer.readUInt32LE(21);
|
|
57
|
+
const width = (val & 0x3fff) + 1;
|
|
58
|
+
const height = ((val >> 14) & 0x3fff) + 1;
|
|
59
|
+
return { width, height };
|
|
60
|
+
}
|
|
61
|
+
else if (type === 'VP8X') {
|
|
62
|
+
const width = (buffer.readUInt32LE(24) & 0xffffff) + 1;
|
|
63
|
+
const height = (buffer.readUInt32LE(27) & 0xffffff) + 1;
|
|
64
|
+
return { width, height };
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
// 4. JPEG
|
|
68
|
+
if (buffer[0] === 0xff && buffer[1] === 0xd8) {
|
|
69
|
+
const fullFile = await fs.readFile(filePath);
|
|
70
|
+
let offset = 2;
|
|
71
|
+
while (offset < fullFile.length) {
|
|
72
|
+
if (fullFile[offset] !== 0xff) {
|
|
73
|
+
break;
|
|
74
|
+
}
|
|
75
|
+
const marker = fullFile[offset + 1];
|
|
76
|
+
if (marker === 0xd9 || marker === 0xda) {
|
|
77
|
+
break;
|
|
78
|
+
}
|
|
79
|
+
const length = fullFile.readUInt16BE(offset + 2);
|
|
80
|
+
const isSOF = (marker >= 0xc0 && marker <= 0xc3) ||
|
|
81
|
+
(marker >= 0xc5 && marker <= 0xc7) ||
|
|
82
|
+
(marker >= 0xc9 && marker <= 0xcb) ||
|
|
83
|
+
(marker >= 0xcd && marker <= 0xcf);
|
|
84
|
+
if (isSOF) {
|
|
85
|
+
if (offset + 8 < fullFile.length) {
|
|
86
|
+
const height = fullFile.readUInt16BE(offset + 5);
|
|
87
|
+
const width = fullFile.readUInt16BE(offset + 7);
|
|
88
|
+
return { width, height };
|
|
89
|
+
}
|
|
90
|
+
break;
|
|
91
|
+
}
|
|
92
|
+
offset += 2 + length;
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
// 5. SVG
|
|
96
|
+
const isSvg = filePath.toLowerCase().endsWith('.svg') || buffer.toString('utf8', 0, 20).includes('<svg');
|
|
97
|
+
if (isSvg) {
|
|
98
|
+
const text = await fs.readFile(filePath, 'utf8');
|
|
99
|
+
const svgTagMatch = text.match(/<svg[^>]*>/i);
|
|
100
|
+
if (svgTagMatch) {
|
|
101
|
+
const svgTag = svgTagMatch[0];
|
|
102
|
+
const widthMatch = svgTag.match(/width\s*=\s*["']([^"']+)["']/i);
|
|
103
|
+
const heightMatch = svgTag.match(/height\s*=\s*["']([^"']+)["']/i);
|
|
104
|
+
if (widthMatch && heightMatch) {
|
|
105
|
+
const width = parseFloat(widthMatch[1]);
|
|
106
|
+
const height = parseFloat(heightMatch[1]);
|
|
107
|
+
if (!isNaN(width) && !isNaN(height)) {
|
|
108
|
+
return { width, height };
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
const viewBoxMatch = svgTag.match(/viewBox\s*=\s*["']\s*\d+\s+\d+\s+(\d+(?:\.\d+)?)\s+(\d+(?:\.\d+)?)\s*["']/i);
|
|
112
|
+
if (viewBoxMatch) {
|
|
113
|
+
const width = parseFloat(viewBoxMatch[1]);
|
|
114
|
+
const height = parseFloat(viewBoxMatch[2]);
|
|
115
|
+
if (!isNaN(width) && !isNaN(height)) {
|
|
116
|
+
return { width, height };
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
catch {
|
|
123
|
+
// Return null on error or unparseable image
|
|
124
|
+
}
|
|
125
|
+
return null;
|
|
126
|
+
}
|
|
127
|
+
//# sourceMappingURL=image-dimension-parser.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"image-dimension-parser.js","sourceRoot":"","sources":["../../src/lib/image-dimension-parser.ts"],"names":[],"mappings":"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"}
|
|
@@ -4,6 +4,8 @@ import { warning } from './theme.js';
|
|
|
4
4
|
import { visitHastElements } from './hast-helpers.js';
|
|
5
5
|
import { isExternalUrl } from './url-helpers.js';
|
|
6
6
|
import { createImageCollectionProcessor, rehypeRewriteMdLinks } from './markdown-processors.js';
|
|
7
|
+
import { getImageDimensions } from './image-dimension-parser.js';
|
|
8
|
+
export { getImageDimensions };
|
|
7
9
|
/** Regex to match image links in markdown:  */
|
|
8
10
|
const imageLinkRegex = /!\[.*?\]\(([^)]+\.(?:png|jpe?g|gif|svg|webp|bmp|ico))\)/gi;
|
|
9
11
|
/**
|
|
@@ -18,6 +20,11 @@ export function extractImagePathsFromMarkdown(content) {
|
|
|
18
20
|
}
|
|
19
21
|
return paths;
|
|
20
22
|
}
|
|
23
|
+
function isCandidateLocalSrc(src) {
|
|
24
|
+
if (typeof src !== 'string')
|
|
25
|
+
return false;
|
|
26
|
+
return !isExternalUrl(src) && !src.startsWith('data:');
|
|
27
|
+
}
|
|
21
28
|
/** ImageProcessor: tracks images encountered during markdown-to-html conversion */
|
|
22
29
|
class ImageProcessor {
|
|
23
30
|
images = [];
|
|
@@ -32,14 +39,9 @@ class ImageProcessor {
|
|
|
32
39
|
return (tree) => {
|
|
33
40
|
visitHastElements(tree, 'img', (node) => {
|
|
34
41
|
const src = node.properties?.src;
|
|
35
|
-
if (
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
if (isExternalUrl(src))
|
|
39
|
-
return;
|
|
40
|
-
if (src.startsWith('data:'))
|
|
41
|
-
return;
|
|
42
|
-
this.images.push(src);
|
|
42
|
+
if (isCandidateLocalSrc(src)) {
|
|
43
|
+
this.images.push(src);
|
|
44
|
+
}
|
|
43
45
|
});
|
|
44
46
|
};
|
|
45
47
|
};
|
|
@@ -50,12 +52,7 @@ export const rehypeRewriteImagePaths = () => {
|
|
|
50
52
|
return (tree) => {
|
|
51
53
|
visitHastElements(tree, 'img', (node) => {
|
|
52
54
|
const src = node.properties?.src;
|
|
53
|
-
if (
|
|
54
|
-
return;
|
|
55
|
-
// Skip external URLs and data URIs
|
|
56
|
-
if (isExternalUrl(src))
|
|
57
|
-
return;
|
|
58
|
-
if (src.startsWith('data:'))
|
|
55
|
+
if (!isCandidateLocalSrc(src))
|
|
59
56
|
return;
|
|
60
57
|
// Skip already rewritten paths
|
|
61
58
|
if (src.startsWith('./images/') || src.startsWith('../images/'))
|
|
@@ -95,17 +92,11 @@ export async function copyImages(sourceDir, outputDir, imagePaths) {
|
|
|
95
92
|
processedPaths.add(imagePath);
|
|
96
93
|
let sourcePath = '';
|
|
97
94
|
let destRelPath = '';
|
|
98
|
-
//
|
|
95
|
+
// 1. Resolve paths
|
|
99
96
|
if (imagePath.startsWith('/')) {
|
|
100
97
|
// Absolute path like /static/screenshot.jpg -> copy from project root to public/static/
|
|
101
98
|
const relativeToProjectRoot = imagePath.substring(1); // Remove leading /
|
|
102
99
|
sourcePath = join(projectRoot, relativeToProjectRoot);
|
|
103
|
-
// Path traversal protection: ensure resolved path stays within project root
|
|
104
|
-
const resolvedSource = resolve(sourcePath);
|
|
105
|
-
if (!resolvedSource.startsWith(projectRoot + '/') && resolvedSource !== projectRoot) {
|
|
106
|
-
console.warn(warning(` Path traversal blocked: ${imagePath}`));
|
|
107
|
-
continue;
|
|
108
|
-
}
|
|
109
100
|
destRelPath = relativeToProjectRoot;
|
|
110
101
|
}
|
|
111
102
|
else {
|
|
@@ -116,21 +107,21 @@ export async function copyImages(sourceDir, outputDir, imagePaths) {
|
|
|
116
107
|
}
|
|
117
108
|
const fullPath = join(sourceDir, resolvedPath);
|
|
118
109
|
sourcePath = fullPath;
|
|
119
|
-
// Path traversal protection: ensure resolved path stays within source directory
|
|
120
|
-
const resolvedSource = resolve(sourcePath);
|
|
121
|
-
const resolvedSourceDir = resolve(sourceDir);
|
|
122
|
-
if (!resolvedSource.startsWith(resolvedSourceDir + '/') && resolvedSource !== resolvedSourceDir) {
|
|
123
|
-
console.warn(warning(` Path traversal blocked: ${imagePath}`));
|
|
124
|
-
continue;
|
|
125
|
-
}
|
|
126
|
-
// Get the relative path from source dir to maintain folder structure
|
|
127
110
|
destRelPath = relative(sourceDir, fullPath);
|
|
128
111
|
}
|
|
129
|
-
// Check if image exists
|
|
112
|
+
// 2. Check if image exists
|
|
130
113
|
if (!(await fs.pathExists(sourcePath))) {
|
|
131
114
|
console.warn(warning(` Image not found: ${sourcePath}`));
|
|
132
115
|
continue;
|
|
133
116
|
}
|
|
117
|
+
// 3. Path traversal protection: ensure resolved path stays within allowed root boundaries
|
|
118
|
+
const allowedRoot = imagePath.startsWith('/') ? projectRoot : sourceDir;
|
|
119
|
+
const resolvedSource = fs.realpathSync(sourcePath);
|
|
120
|
+
const resolvedRoot = fs.realpathSync(allowedRoot);
|
|
121
|
+
if (!resolvedSource.startsWith(resolvedRoot + '/') && resolvedSource !== resolvedRoot) {
|
|
122
|
+
console.warn(warning(` Path traversal blocked: ${imagePath}`));
|
|
123
|
+
continue;
|
|
124
|
+
}
|
|
134
125
|
const destPath = join(outputDir, destRelPath);
|
|
135
126
|
// Create destination directory if needed
|
|
136
127
|
await fs.mkdirp(dirname(destPath));
|
|
@@ -138,3 +129,4 @@ export async function copyImages(sourceDir, outputDir, imagePaths) {
|
|
|
138
129
|
await fs.copyFile(sourcePath, destPath);
|
|
139
130
|
}
|
|
140
131
|
}
|
|
132
|
+
//# sourceMappingURL=image-helpers.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"image-helpers.js","sourceRoot":"","sources":["../../src/lib/image-helpers.ts"],"names":[],"mappings":"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"}
|
package/dist/lib/jira-helpers.js
CHANGED
|
@@ -3,3 +3,4 @@
|
|
|
3
3
|
* Only applied when both jiraBaseUrl and jiraPrefix are provided.
|
|
4
4
|
*/
|
|
5
5
|
export const linkJiraIds = (msg, base, prefix) => msg.replace(new RegExp(`(${prefix.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')}-\\d+)`, 'g'), (m) => `<a href="${base}${m}" target="_blank" rel="noopener noreferrer" class="commit-jira-link">${m}</a>`);
|
|
6
|
+
//# sourceMappingURL=jira-helpers.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"jira-helpers.js","sourceRoot":"","sources":["../../src/lib/jira-helpers.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,MAAM,CAAC,MAAM,WAAW,GAAG,CAAC,GAAW,EAAE,IAAY,EAAE,MAAc,EAAU,EAAE,CAC/E,GAAG,CAAC,OAAO,CACT,IAAI,MAAM,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,qBAAqB,EAAE,MAAM,CAAC,QAAQ,EAAE,GAAG,CAAC,EAC1E,CAAC,CAAC,EAAE,EAAE,CAAC,YAAY,IAAI,GAAG,CAAC,wEAAwE,CAAC,MAAM,CAC3G,CAAC"}
|
package/dist/lib/lint-runner.js
CHANGED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"lint-runner.js","sourceRoot":"","sources":["../../src/lib/lint-runner.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,YAAY,CAAC;AAElD,OAAO,EAAE,OAAO,EAAE,MAAM,qBAAqB,CAAC;AAE9C,MAAM,CAAC,KAAK,UAAU,UAAU,CAAC,OAAsB;IACrD,MAAM,MAAM,GAAgB,EAAE,CAAC;IAC/B,KAAK,MAAM,MAAM,IAAI,OAAO,EAAE,CAAC;QAC7B,IAAI,CAAC;YACH,MAAM,MAAM,GAAG,MAAM,MAAM,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;YAC3C,MAAM,CAAC,IAAI,CAAC,GAAG,MAAM,CAAC,CAAC;QACzB,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,yBAAyB,MAAM,CAAC,IAAI,IAAI,CAAC,EAAE,GAAG,CAAC,CAAC;QACtE,CAAC;IACH,CAAC;IAED,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACxB,OAAO,IAAI,CAAC;IACd,CAAC;IAED,IAAI,OAAO,CAAC,SAAS,EAAE,CAAC;QACtB,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,YAAY,OAAO,CAAC,SAAS,EAAE,CAAC,CAAC,CAAC;IACrD,CAAC;IAED,IAAI,SAAS,GAAG,KAAK,CAAC;IACtB,KAAK,MAAM,KAAK,IAAI,MAAM,EAAE,CAAC;QAC3B,IAAI,KAAK,CAAC,KAAK,KAAK,OAAO,EAAE,CAAC;YAC5B,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,MAAM,KAAK,CAAC,QAAQ,CAAC,WAAW,EAAE,KAAK,KAAK,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC;YAC7E,SAAS,GAAG,IAAI,CAAC;QACnB,CAAC;aAAM,CAAC;YACN,OAAO,CAAC,IAAI,CAAC,OAAO,CAAC,MAAM,KAAK,CAAC,QAAQ,CAAC,WAAW,EAAE,KAAK,KAAK,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC;QAChF,CAAC;IACH,CAAC;IAED,OAAO,CAAC,SAAS,CAAC;AACpB,CAAC"}
|