@poetora/cli 0.1.9 → 0.1.11
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/bin/cli-builder.js +32 -18
- package/bin/services/link.service.js +0 -11
- package/bin/services/version.service.d.ts +1 -1
- package/bin/services/version.service.js +12 -10
- package/bin/utils/index.d.ts +1 -0
- package/bin/utils/index.js +1 -0
- package/bin/utils/terminate.d.ts +1 -0
- package/bin/utils/terminate.js +4 -0
- package/package.json +5 -1
- package/.turbo/turbo-build.log +0 -4
- package/src/accessibility.ts +0 -180
- package/src/cli-builder.ts +0 -274
- package/src/cli.ts +0 -22
- package/src/commands/__tests__/base.command.test.ts +0 -139
- package/src/commands/__tests__/dev.command.test.ts +0 -241
- package/src/commands/__tests__/init.command.test.ts +0 -281
- package/src/commands/__tests__/utils.ts +0 -20
- package/src/commands/base.command.ts +0 -97
- package/src/commands/check.command.ts +0 -40
- package/src/commands/dev.command.ts +0 -63
- package/src/commands/index.ts +0 -6
- package/src/commands/init.command.ts +0 -125
- package/src/commands/link.command.ts +0 -39
- package/src/commands/update.command.ts +0 -23
- package/src/constants.ts +0 -4
- package/src/errors/cli-error.ts +0 -83
- package/src/errors/index.ts +0 -1
- package/src/index.ts +0 -110
- package/src/mdxAccessibility.ts +0 -132
- package/src/middlewares.ts +0 -73
- package/src/services/__tests__/port.service.test.ts +0 -83
- package/src/services/__tests__/template.service.test.ts +0 -234
- package/src/services/__tests__/version.service.test.ts +0 -165
- package/src/services/accessibility-check.service.ts +0 -226
- package/src/services/index.ts +0 -7
- package/src/services/link.service.ts +0 -65
- package/src/services/openapi-check.service.ts +0 -68
- package/src/services/port.service.ts +0 -47
- package/src/services/template.service.ts +0 -203
- package/src/services/update.service.ts +0 -76
- package/src/services/version.service.ts +0 -161
- package/src/start.ts +0 -6
- package/src/types/common.ts +0 -53
- package/src/types/index.ts +0 -2
- package/src/types/options.ts +0 -42
- package/src/utils/console-logger.ts +0 -123
- package/src/utils/index.ts +0 -2
- package/src/utils/logger.interface.ts +0 -70
- package/tsconfig.build.json +0 -17
- package/tsconfig.json +0 -21
- package/vitest.config.ts +0 -8
package/bin/cli-builder.js
CHANGED
|
@@ -1,10 +1,9 @@
|
|
|
1
|
-
import chalk from 'chalk';
|
|
2
1
|
import yargs from 'yargs';
|
|
3
2
|
import { hideBin } from 'yargs/helpers';
|
|
4
3
|
import { CheckCommand, DevCommand, InitCommand, LinkCommand, UpdateCommand, } from './commands/index.js';
|
|
5
4
|
import { checkNodeVersion, suppressConsoleWarnings } from './middlewares.js';
|
|
6
5
|
import { AccessibilityCheckService, LinkService, OpenApiCheckService, PortService, TemplateService, UpdateService, VersionService, } from './services/index.js';
|
|
7
|
-
import { ConsoleLogger } from './utils/index.js';
|
|
6
|
+
import { ConsoleLogger, terminate } from './utils/index.js';
|
|
8
7
|
export class CliBuilder {
|
|
9
8
|
packageName;
|
|
10
9
|
logger;
|
|
@@ -27,7 +26,7 @@ export class CliBuilder {
|
|
|
27
26
|
const updateCommand = new UpdateCommand(this.logger, updateService, this.packageName);
|
|
28
27
|
return (yargs(hideBin(process.argv))
|
|
29
28
|
.scriptName(this.packageName)
|
|
30
|
-
.version()
|
|
29
|
+
.version(versionService.getCliVersion())
|
|
31
30
|
.middleware(checkNodeVersion)
|
|
32
31
|
.middleware(suppressConsoleWarnings)
|
|
33
32
|
.command('dev', 'initialize a local preview environment', (yargs) => yargs
|
|
@@ -67,7 +66,7 @@ export class CliBuilder {
|
|
|
67
66
|
}
|
|
68
67
|
catch (error) {
|
|
69
68
|
this.logger.error(error instanceof Error ? error.message : 'Unknown error');
|
|
70
|
-
|
|
69
|
+
await terminate(1);
|
|
71
70
|
}
|
|
72
71
|
})
|
|
73
72
|
.command(['new [directory]', 'init [directory]'], 'Create a new Poetora documentation site', (yargs) => yargs.positional('directory', {
|
|
@@ -80,7 +79,7 @@ export class CliBuilder {
|
|
|
80
79
|
}
|
|
81
80
|
catch (error) {
|
|
82
81
|
this.logger.error(error instanceof Error ? error.message : 'Unknown error');
|
|
83
|
-
|
|
82
|
+
await terminate(1);
|
|
84
83
|
}
|
|
85
84
|
})
|
|
86
85
|
.command('openapi-check <filename>', 'check if an OpenAPI spec is valid', (yargs) => yargs
|
|
@@ -99,32 +98,47 @@ export class CliBuilder {
|
|
|
99
98
|
filename: argv.filename,
|
|
100
99
|
localSchema: argv.localSchema,
|
|
101
100
|
});
|
|
102
|
-
|
|
101
|
+
await terminate(0);
|
|
103
102
|
}
|
|
104
103
|
catch (error) {
|
|
105
104
|
this.logger.error(error instanceof Error ? error.message : 'Unknown error');
|
|
106
|
-
|
|
105
|
+
await terminate(1);
|
|
107
106
|
}
|
|
108
107
|
})
|
|
109
108
|
.command(['a11y', 'accessibility-check', 'a11y-check', 'accessibility'], 'check for accessibility issues in documentation', () => undefined, async () => {
|
|
110
109
|
try {
|
|
111
110
|
const exitCode = await checkCommand.checkAccessibility();
|
|
112
|
-
|
|
111
|
+
await terminate(exitCode);
|
|
113
112
|
}
|
|
114
113
|
catch (error) {
|
|
115
114
|
this.logger.error(error instanceof Error ? error.message : 'Unknown error');
|
|
116
|
-
|
|
115
|
+
await terminate(1);
|
|
117
116
|
}
|
|
118
117
|
})
|
|
119
118
|
.command('broken-links', 'check for invalid internal links', () => undefined, async () => {
|
|
120
119
|
try {
|
|
121
120
|
const brokenLinks = await linkCommand.checkBrokenLinks();
|
|
122
121
|
const hasBrokenLinks = Object.keys(brokenLinks).length > 0;
|
|
123
|
-
|
|
122
|
+
if (!hasBrokenLinks) {
|
|
123
|
+
this.logger.success('no broken links found');
|
|
124
|
+
await terminate(0);
|
|
125
|
+
}
|
|
126
|
+
const linkCount = Object.values(brokenLinks).flat().length;
|
|
127
|
+
const fileCount = Object.keys(brokenLinks).length;
|
|
128
|
+
this.logger.log(`found ${this.logger.highlight?.(linkCount.toString()) ?? linkCount} broken link${linkCount === 1 ? '' : 's'} in ${this.logger.highlight?.(fileCount.toString()) ?? fileCount} file${fileCount === 1 ? '' : 's'}`);
|
|
129
|
+
this.logger.logNewLine();
|
|
130
|
+
for (const [filename, links] of Object.entries(brokenLinks)) {
|
|
131
|
+
this.logger.logColor(filename, 'cyan');
|
|
132
|
+
links.forEach((link) => {
|
|
133
|
+
this.logger.logColor(` ⎿ ${link}`, 'gray');
|
|
134
|
+
});
|
|
135
|
+
this.logger.logNewLine();
|
|
136
|
+
}
|
|
137
|
+
await terminate(1);
|
|
124
138
|
}
|
|
125
139
|
catch (error) {
|
|
126
140
|
this.logger.error(error instanceof Error ? error.message : 'Unknown error');
|
|
127
|
-
|
|
141
|
+
await terminate(1);
|
|
128
142
|
}
|
|
129
143
|
})
|
|
130
144
|
.command('rename <from> <to>', 'rename a file and update all internal link references', (yargs) => yargs
|
|
@@ -149,28 +163,28 @@ export class CliBuilder {
|
|
|
149
163
|
to: argv.to,
|
|
150
164
|
force: argv.force,
|
|
151
165
|
});
|
|
152
|
-
|
|
166
|
+
await terminate(0);
|
|
153
167
|
}
|
|
154
168
|
catch (error) {
|
|
155
169
|
this.logger.error(error instanceof Error ? error.message : 'Unknown error');
|
|
156
|
-
|
|
170
|
+
await terminate(1);
|
|
157
171
|
}
|
|
158
172
|
})
|
|
159
173
|
.command('update', 'update the CLI to the latest version', () => undefined, async () => {
|
|
160
174
|
try {
|
|
161
175
|
await updateCommand.run({});
|
|
162
|
-
|
|
176
|
+
await terminate(0);
|
|
163
177
|
}
|
|
164
178
|
catch (error) {
|
|
165
179
|
this.logger.error(error instanceof Error ? error.message : 'Unknown error');
|
|
166
|
-
|
|
180
|
+
await terminate(1);
|
|
167
181
|
}
|
|
168
182
|
})
|
|
169
183
|
.command(['version', 'v'], 'display the current version of the CLI and client', () => undefined, async () => {
|
|
170
184
|
const versions = versionService.getVersions();
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
185
|
+
this.logger.logBold(`cli version ${versions.cli}`, 'green');
|
|
186
|
+
this.logger.logBold(`client version ${versions.client}`, 'green');
|
|
187
|
+
await terminate(0);
|
|
174
188
|
})
|
|
175
189
|
.strictCommands()
|
|
176
190
|
.demandCommand(1, 'unknown command. see above for the list of supported commands.')
|
|
@@ -8,7 +8,6 @@ export class LinkService {
|
|
|
8
8
|
async checkBrokenLinks() {
|
|
9
9
|
const brokenLinks = await getBrokenInternalLinks();
|
|
10
10
|
if (brokenLinks.length === 0) {
|
|
11
|
-
this.logger.success('no broken links found');
|
|
12
11
|
return {};
|
|
13
12
|
}
|
|
14
13
|
const brokenLinksByFile = {};
|
|
@@ -22,16 +21,6 @@ export class LinkService {
|
|
|
22
21
|
brokenLinksByFile[filename] = [mdxPath.originalPath];
|
|
23
22
|
}
|
|
24
23
|
});
|
|
25
|
-
const fileCount = Object.keys(brokenLinksByFile).length;
|
|
26
|
-
this.logger.log(`found ${this.logger.highlight?.(brokenLinks.length.toString()) ?? brokenLinks.length} broken link${brokenLinks.length === 1 ? '' : 's'} in ${this.logger.highlight?.(fileCount.toString()) ?? fileCount} file${fileCount === 1 ? '' : 's'}`);
|
|
27
|
-
this.logger.logNewLine();
|
|
28
|
-
for (const [filename, links] of Object.entries(brokenLinksByFile)) {
|
|
29
|
-
this.logger.logColor(filename, 'cyan');
|
|
30
|
-
links.forEach((link) => {
|
|
31
|
-
this.logger.logColor(` ⎿ ${link}`, 'gray');
|
|
32
|
-
});
|
|
33
|
-
this.logger.logNewLine();
|
|
34
|
-
}
|
|
35
24
|
return brokenLinksByFile;
|
|
36
25
|
}
|
|
37
26
|
async renameFile(from, to, force = false) {
|
|
@@ -4,7 +4,7 @@ export declare class VersionService {
|
|
|
4
4
|
constructor(packageName?: string);
|
|
5
5
|
parseNodeVersion(): NodeVersion;
|
|
6
6
|
checkNodeVersion(): ValidationResult;
|
|
7
|
-
getCliVersion(): string
|
|
7
|
+
getCliVersion(): string;
|
|
8
8
|
getClientVersion(): string;
|
|
9
9
|
getVersions(): {
|
|
10
10
|
cli: string | undefined;
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import { getClientVersion, LOCAL_LINKED_CLI_VERSION } from '@poetora/previewing';
|
|
2
2
|
import { execSync } from 'child_process';
|
|
3
|
-
import
|
|
3
|
+
import { readFileSync } from 'fs';
|
|
4
|
+
import path from 'path';
|
|
5
|
+
import { fileURLToPath } from 'url';
|
|
4
6
|
import { InvalidEnvironmentError } from '../errors/index.js';
|
|
5
7
|
import { CLI_CONSTANTS } from '../types/index.js';
|
|
6
8
|
export class VersionService {
|
|
@@ -55,19 +57,19 @@ export class VersionService {
|
|
|
55
57
|
};
|
|
56
58
|
}
|
|
57
59
|
getCliVersion() {
|
|
58
|
-
const y = yargs();
|
|
59
|
-
let version;
|
|
60
|
-
y.showVersion((v) => {
|
|
61
|
-
version = v;
|
|
62
|
-
return false;
|
|
63
|
-
});
|
|
64
60
|
if (process.env.CLI_TEST_MODE === 'true') {
|
|
65
61
|
return 'test-cli';
|
|
66
62
|
}
|
|
67
|
-
|
|
68
|
-
|
|
63
|
+
try {
|
|
64
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
65
|
+
const __dirname = path.dirname(__filename);
|
|
66
|
+
const packageJsonPath = path.join(__dirname, '../../package.json');
|
|
67
|
+
const packageJson = JSON.parse(readFileSync(packageJsonPath, 'utf-8'));
|
|
68
|
+
return packageJson.version;
|
|
69
|
+
}
|
|
70
|
+
catch {
|
|
71
|
+
return LOCAL_LINKED_CLI_VERSION;
|
|
69
72
|
}
|
|
70
|
-
return version;
|
|
71
73
|
}
|
|
72
74
|
getClientVersion() {
|
|
73
75
|
return getClientVersion().trim();
|
package/bin/utils/index.d.ts
CHANGED
package/bin/utils/index.js
CHANGED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const terminate: (code: number) => Promise<void>;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@poetora/cli",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.11",
|
|
4
4
|
"description": "The CLI for Poetora documentation Engine",
|
|
5
5
|
"engines": {
|
|
6
6
|
"node": ">=18.0.0"
|
|
@@ -22,6 +22,10 @@
|
|
|
22
22
|
},
|
|
23
23
|
"main": "./bin/index.js",
|
|
24
24
|
"exports": "./bin/index.js",
|
|
25
|
+
"files": [
|
|
26
|
+
"bin",
|
|
27
|
+
"LICENSE"
|
|
28
|
+
],
|
|
25
29
|
"bin": {
|
|
26
30
|
"poet": "bin/index.js",
|
|
27
31
|
"poetora": "bin/index.js"
|
package/.turbo/turbo-build.log
DELETED
package/src/accessibility.ts
DELETED
|
@@ -1,180 +0,0 @@
|
|
|
1
|
-
import Color from 'color';
|
|
2
|
-
|
|
3
|
-
export const WCAG_STANDARDS = {
|
|
4
|
-
AA_NORMAL: 4.5,
|
|
5
|
-
AA_LARGE: 3,
|
|
6
|
-
AAA_NORMAL: 7,
|
|
7
|
-
AAA_LARGE: 4.5,
|
|
8
|
-
} as const;
|
|
9
|
-
|
|
10
|
-
export type ContrastResult = {
|
|
11
|
-
ratio: number;
|
|
12
|
-
meetsAA: boolean;
|
|
13
|
-
meetsAAA: boolean;
|
|
14
|
-
recommendation: 'pass' | 'warning' | 'fail';
|
|
15
|
-
message: string;
|
|
16
|
-
};
|
|
17
|
-
|
|
18
|
-
export function checkColorContrast(
|
|
19
|
-
foreground: string,
|
|
20
|
-
background: string,
|
|
21
|
-
minThreshold: number = WCAG_STANDARDS.AA_NORMAL
|
|
22
|
-
): ContrastResult | null {
|
|
23
|
-
try {
|
|
24
|
-
const fg = Color(foreground);
|
|
25
|
-
const bg = Color(background);
|
|
26
|
-
|
|
27
|
-
const ratio = fg.contrast(bg);
|
|
28
|
-
const level = fg.level(bg);
|
|
29
|
-
|
|
30
|
-
const meetsAA = level === 'AA' || level === 'AAA';
|
|
31
|
-
const meetsAAA = level === 'AAA';
|
|
32
|
-
|
|
33
|
-
let recommendation: 'pass' | 'warning' | 'fail';
|
|
34
|
-
let message: string;
|
|
35
|
-
|
|
36
|
-
if (minThreshold !== WCAG_STANDARDS.AA_NORMAL) {
|
|
37
|
-
if (ratio >= minThreshold) {
|
|
38
|
-
recommendation = 'pass';
|
|
39
|
-
message = `Contrast ratio: ${ratio.toFixed(
|
|
40
|
-
2
|
|
41
|
-
)}:1 (meets minimum threshold of ${minThreshold}:1)`;
|
|
42
|
-
} else {
|
|
43
|
-
recommendation = 'fail';
|
|
44
|
-
message = `Poor contrast ratio: ${ratio.toFixed(
|
|
45
|
-
2
|
|
46
|
-
)}:1 (fails minimum threshold, required: ${minThreshold}:1)`;
|
|
47
|
-
}
|
|
48
|
-
} else {
|
|
49
|
-
if (meetsAAA) {
|
|
50
|
-
recommendation = 'pass';
|
|
51
|
-
message = `Excellent contrast ratio: ${ratio.toFixed(2)}:1 (meets WCAG AAA)`;
|
|
52
|
-
} else if (meetsAA) {
|
|
53
|
-
recommendation = 'warning';
|
|
54
|
-
message = `Good contrast ratio: ${ratio.toFixed(
|
|
55
|
-
2
|
|
56
|
-
)}:1 (meets WCAG AA, consider AAA for better accessibility)`;
|
|
57
|
-
} else {
|
|
58
|
-
recommendation = 'fail';
|
|
59
|
-
message = `Poor contrast ratio: ${ratio.toFixed(2)}:1 (fails WCAG AA, minimum required: ${
|
|
60
|
-
WCAG_STANDARDS.AA_NORMAL
|
|
61
|
-
}:1)`;
|
|
62
|
-
}
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
return {
|
|
66
|
-
ratio,
|
|
67
|
-
meetsAA,
|
|
68
|
-
meetsAAA,
|
|
69
|
-
recommendation,
|
|
70
|
-
message,
|
|
71
|
-
};
|
|
72
|
-
} catch {
|
|
73
|
-
return null;
|
|
74
|
-
}
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
export interface AccessibilityCheckResult {
|
|
78
|
-
primaryContrast: ContrastResult | null;
|
|
79
|
-
lightContrast: ContrastResult | null;
|
|
80
|
-
darkContrast: ContrastResult | null;
|
|
81
|
-
darkOnLightContrast: ContrastResult | null;
|
|
82
|
-
anchorResults: Array<{
|
|
83
|
-
name: string;
|
|
84
|
-
lightContrast: ContrastResult | null;
|
|
85
|
-
darkContrast: ContrastResult | null;
|
|
86
|
-
}>;
|
|
87
|
-
overallScore: 'pass' | 'warning' | 'fail';
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
export function checkDocsColors(
|
|
91
|
-
colors: {
|
|
92
|
-
primary?: string;
|
|
93
|
-
light?: string;
|
|
94
|
-
dark?: string;
|
|
95
|
-
},
|
|
96
|
-
background: {
|
|
97
|
-
lightHex: string;
|
|
98
|
-
darkHex: string;
|
|
99
|
-
},
|
|
100
|
-
navigation?: {
|
|
101
|
-
global?: {
|
|
102
|
-
anchors?: Array<{
|
|
103
|
-
anchor: string;
|
|
104
|
-
color?: {
|
|
105
|
-
light?: string;
|
|
106
|
-
dark?: string;
|
|
107
|
-
};
|
|
108
|
-
}>;
|
|
109
|
-
};
|
|
110
|
-
}
|
|
111
|
-
): AccessibilityCheckResult {
|
|
112
|
-
const lightBackground = background.lightHex;
|
|
113
|
-
const darkBackground = background.darkHex;
|
|
114
|
-
|
|
115
|
-
const primaryContrast = colors.primary
|
|
116
|
-
? checkColorContrast(colors.primary, lightBackground)
|
|
117
|
-
: null;
|
|
118
|
-
|
|
119
|
-
const lightContrast = colors.light ? checkColorContrast(colors.light, darkBackground) : null;
|
|
120
|
-
|
|
121
|
-
const darkContrast = colors.dark ? checkColorContrast(colors.dark, darkBackground, 3) : null;
|
|
122
|
-
|
|
123
|
-
const darkOnLightContrast = colors.dark
|
|
124
|
-
? checkColorContrast(colors.dark, lightBackground, 3)
|
|
125
|
-
: null;
|
|
126
|
-
|
|
127
|
-
const anchorResults: Array<{
|
|
128
|
-
name: string;
|
|
129
|
-
lightContrast: ContrastResult | null;
|
|
130
|
-
darkContrast: ContrastResult | null;
|
|
131
|
-
}> = [];
|
|
132
|
-
|
|
133
|
-
if (navigation?.global?.anchors) {
|
|
134
|
-
for (const anchor of navigation.global.anchors) {
|
|
135
|
-
if (anchor.color) {
|
|
136
|
-
const lightContrast = anchor.color.light
|
|
137
|
-
? checkColorContrast(anchor.color.light, lightBackground)
|
|
138
|
-
: null;
|
|
139
|
-
const darkContrast = anchor.color.dark
|
|
140
|
-
? checkColorContrast(anchor.color.dark, darkBackground)
|
|
141
|
-
: null;
|
|
142
|
-
|
|
143
|
-
anchorResults.push({
|
|
144
|
-
name: anchor.anchor,
|
|
145
|
-
lightContrast,
|
|
146
|
-
darkContrast,
|
|
147
|
-
});
|
|
148
|
-
}
|
|
149
|
-
}
|
|
150
|
-
}
|
|
151
|
-
|
|
152
|
-
const results = [
|
|
153
|
-
primaryContrast,
|
|
154
|
-
lightContrast,
|
|
155
|
-
darkContrast,
|
|
156
|
-
darkOnLightContrast,
|
|
157
|
-
...anchorResults.flatMap((anchor) => [anchor.lightContrast, anchor.darkContrast]),
|
|
158
|
-
].filter(Boolean);
|
|
159
|
-
|
|
160
|
-
const hasFailure = results.some((result) => result?.recommendation === 'fail');
|
|
161
|
-
const hasWarning = results.some((result) => result?.recommendation === 'warning');
|
|
162
|
-
|
|
163
|
-
let overallScore: 'pass' | 'warning' | 'fail';
|
|
164
|
-
if (hasFailure) {
|
|
165
|
-
overallScore = 'fail';
|
|
166
|
-
} else if (hasWarning) {
|
|
167
|
-
overallScore = 'warning';
|
|
168
|
-
} else {
|
|
169
|
-
overallScore = 'pass';
|
|
170
|
-
}
|
|
171
|
-
|
|
172
|
-
return {
|
|
173
|
-
primaryContrast,
|
|
174
|
-
lightContrast,
|
|
175
|
-
darkContrast,
|
|
176
|
-
darkOnLightContrast,
|
|
177
|
-
anchorResults,
|
|
178
|
-
overallScore,
|
|
179
|
-
};
|
|
180
|
-
}
|