@poetora/cli 0.1.4 → 0.1.6
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/.turbo/turbo-build.log +1 -1
- package/bin/cli-builder.js +7 -2
- package/bin/cli.js +4 -0
- package/bin/commands/base.command.js +2 -2
- package/bin/mdxAccessibility.js +2 -2
- package/bin/middlewares.d.ts +2 -0
- package/bin/middlewares.js +47 -0
- package/bin/services/accessibility-check.service.js +1 -1
- package/bin/services/link.service.js +2 -2
- package/bin/services/openapi-check.service.js +1 -1
- package/bin/services/template.service.js +2 -2
- package/bin/services/version.service.js +4 -4
- package/bin/utils/console-logger.js +24 -28
- package/package.json +11 -10
- package/src/cli-builder.ts +10 -3
- package/src/cli.ts +7 -0
- package/src/commands/__tests__/base.command.test.ts +2 -8
- package/src/commands/base.command.ts +2 -2
- package/src/mdxAccessibility.ts +2 -2
- package/src/middlewares.ts +73 -0
- package/src/services/__tests__/template.service.test.ts +1 -1
- package/src/services/accessibility-check.service.ts +1 -1
- package/src/services/link.service.ts +2 -2
- package/src/services/openapi-check.service.ts +1 -1
- package/src/services/template.service.ts +2 -2
- package/src/services/version.service.ts +6 -6
- package/src/utils/console-logger.ts +41 -32
package/.turbo/turbo-build.log
CHANGED
package/bin/cli-builder.js
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
|
+
import chalk from 'chalk';
|
|
1
2
|
import yargs from 'yargs';
|
|
2
3
|
import { hideBin } from 'yargs/helpers';
|
|
3
4
|
import { CheckCommand, DevCommand, InitCommand, LinkCommand, UpdateCommand, } from './commands/index.js';
|
|
5
|
+
import { checkNodeVersion, suppressConsoleWarnings } from './middlewares.js';
|
|
4
6
|
import { AccessibilityCheckService, LinkService, OpenApiCheckService, PortService, TemplateService, UpdateService, VersionService, } from './services/index.js';
|
|
5
7
|
import { ConsoleLogger } from './utils/index.js';
|
|
6
8
|
export class CliBuilder {
|
|
@@ -25,6 +27,9 @@ export class CliBuilder {
|
|
|
25
27
|
const updateCommand = new UpdateCommand(this.logger, updateService, this.packageName);
|
|
26
28
|
return (yargs(hideBin(process.argv))
|
|
27
29
|
.scriptName(this.packageName)
|
|
30
|
+
.version()
|
|
31
|
+
.middleware(checkNodeVersion)
|
|
32
|
+
.middleware(suppressConsoleWarnings)
|
|
28
33
|
.command('dev', 'initialize a local preview environment', (yargs) => yargs
|
|
29
34
|
.option('port', {
|
|
30
35
|
type: 'number',
|
|
@@ -163,8 +168,8 @@ export class CliBuilder {
|
|
|
163
168
|
})
|
|
164
169
|
.command(['version', 'v'], 'display the current version of the CLI and client', () => undefined, async () => {
|
|
165
170
|
const versions = versionService.getVersions();
|
|
166
|
-
|
|
167
|
-
|
|
171
|
+
console.log(`${chalk.bold.green('cli version')} ${versions.cli}`);
|
|
172
|
+
console.log(`${chalk.bold.green('client version')} ${versions.client}`);
|
|
168
173
|
process.exit(0);
|
|
169
174
|
})
|
|
170
175
|
.strictCommands()
|
package/bin/cli.js
CHANGED
|
@@ -1,6 +1,10 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
+
import { Logs } from '@poetora/previewing';
|
|
3
|
+
import { render } from 'ink';
|
|
4
|
+
import React from 'react';
|
|
2
5
|
import { CliBuilder } from './cli-builder.js';
|
|
3
6
|
export const cli = (options) => {
|
|
7
|
+
render(React.createElement(Logs));
|
|
4
8
|
const builder = new CliBuilder(options.packageName);
|
|
5
9
|
builder.run().catch((error) => {
|
|
6
10
|
console.error('Fatal error:', error);
|
|
@@ -26,12 +26,12 @@ export class BaseCommand {
|
|
|
26
26
|
else if (error instanceof Error) {
|
|
27
27
|
this.logger.error(error.message);
|
|
28
28
|
if (process.env.DEBUG === 'true') {
|
|
29
|
-
|
|
29
|
+
this.logger.logColor(error.stack ?? '', 'gray');
|
|
30
30
|
}
|
|
31
31
|
}
|
|
32
32
|
else {
|
|
33
33
|
this.logger.error('An unexpected error occurred');
|
|
34
|
-
|
|
34
|
+
this.logger.logColor(String(error), 'gray');
|
|
35
35
|
}
|
|
36
36
|
}
|
|
37
37
|
exit(code) {
|
package/bin/mdxAccessibility.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import fs from 'fs';
|
|
2
|
-
import path from 'path';
|
|
3
1
|
import { categorizeFilePaths, getPoetIgnore } from '@poetora/prebuild';
|
|
4
2
|
import { coreRemark } from '@poetora/shared';
|
|
3
|
+
import fs from 'fs';
|
|
4
|
+
import path from 'path';
|
|
5
5
|
import { visit } from 'unist-util-visit';
|
|
6
6
|
const checkAltAttributes = (filePath, content) => {
|
|
7
7
|
const issues = [];
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { addLog, ErrorLog } from '@poetora/previewing';
|
|
2
|
+
import React from 'react';
|
|
3
|
+
export const checkNodeVersion = async () => {
|
|
4
|
+
let nodeVersionString = process.version;
|
|
5
|
+
if (nodeVersionString.charAt(0) === 'v') {
|
|
6
|
+
nodeVersionString = nodeVersionString.slice(1);
|
|
7
|
+
}
|
|
8
|
+
const versionArr = nodeVersionString.split('.');
|
|
9
|
+
const versionStr = versionArr[0];
|
|
10
|
+
if (!versionStr) {
|
|
11
|
+
addLog(React.createElement(ErrorLog, {
|
|
12
|
+
message: `Unable to determine Node.js version (got "${process.version}"). Please ensure you are running Node.js >= 18.0.0.`,
|
|
13
|
+
}));
|
|
14
|
+
process.exit(1);
|
|
15
|
+
}
|
|
16
|
+
const majorVersion = parseInt(versionStr, 10);
|
|
17
|
+
if (majorVersion < 18) {
|
|
18
|
+
addLog(React.createElement(ErrorLog, {
|
|
19
|
+
message: `poetora requires Node.js >= 18.0.0 (current version ${nodeVersionString}). Please upgrade Node.js and try again.`,
|
|
20
|
+
}));
|
|
21
|
+
process.exit(1);
|
|
22
|
+
}
|
|
23
|
+
};
|
|
24
|
+
export const suppressConsoleWarnings = () => {
|
|
25
|
+
const ignoredMessages = [
|
|
26
|
+
'No utility classes were detected',
|
|
27
|
+
'https://tailwindcss.com/docs/content-configuration',
|
|
28
|
+
'DeprecationWarning',
|
|
29
|
+
'punycode',
|
|
30
|
+
];
|
|
31
|
+
const originalConsoleError = console.error;
|
|
32
|
+
console.error = (...args) => {
|
|
33
|
+
const message = args.join(' ');
|
|
34
|
+
if (ignoredMessages.some((ignoredMessage) => message.includes(ignoredMessage))) {
|
|
35
|
+
return;
|
|
36
|
+
}
|
|
37
|
+
originalConsoleError.apply(console, args);
|
|
38
|
+
};
|
|
39
|
+
const originalConsoleWarn = console.warn;
|
|
40
|
+
console.warn = (...args) => {
|
|
41
|
+
const message = args.join(' ');
|
|
42
|
+
if (ignoredMessages.some((ignoredMessage) => message.includes(ignoredMessage))) {
|
|
43
|
+
return;
|
|
44
|
+
}
|
|
45
|
+
originalConsoleWarn.apply(console, args);
|
|
46
|
+
};
|
|
47
|
+
};
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import path from 'path';
|
|
2
1
|
import { getConfigObj, getConfigPath } from '@poetora/prebuild';
|
|
3
2
|
import { getBackgroundColors } from '@poetora/shared';
|
|
3
|
+
import path from 'path';
|
|
4
4
|
import { checkDocsColors, } from '../accessibility.js';
|
|
5
5
|
import { CMD_EXEC_PATH } from '../constants.js';
|
|
6
6
|
import { checkMdxAccessibility } from '../mdxAccessibility.js';
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import * as path from 'path';
|
|
2
1
|
import { getBrokenInternalLinks, renameFilesAndUpdateLinksInContent, } from '@poetora/link-rot';
|
|
2
|
+
import * as path from 'path';
|
|
3
3
|
export class LinkService {
|
|
4
4
|
logger;
|
|
5
5
|
constructor(logger) {
|
|
@@ -26,7 +26,7 @@ export class LinkService {
|
|
|
26
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
27
|
this.logger.logNewLine();
|
|
28
28
|
for (const [filename, links] of Object.entries(brokenLinksByFile)) {
|
|
29
|
-
|
|
29
|
+
this.logger.logColor(filename, 'cyan');
|
|
30
30
|
links.forEach((link) => {
|
|
31
31
|
this.logger.logColor(` ⎿ ${link}`, 'gray');
|
|
32
32
|
});
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import * as fs from 'fs';
|
|
2
1
|
import { getOpenApiDocumentFromUrl, isAllowedLocalSchemaUrl, validate } from '@poetora/shared';
|
|
2
|
+
import * as fs from 'fs';
|
|
3
3
|
import * as yaml from 'js-yaml';
|
|
4
4
|
import { FileSystemError, ValidationError } from '../errors/index.js';
|
|
5
5
|
export class OpenApiCheckService {
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import * as fs from 'fs';
|
|
2
|
-
import * as path from 'path';
|
|
3
1
|
import { docsConfigSchema } from '@poetora/validation';
|
|
4
2
|
import AdmZip from 'adm-zip';
|
|
3
|
+
import * as fs from 'fs';
|
|
5
4
|
import * as fse from 'fs-extra';
|
|
5
|
+
import * as path from 'path';
|
|
6
6
|
import { ExternalServiceError, FileSystemError } from '../errors/index.js';
|
|
7
7
|
export class TemplateService {
|
|
8
8
|
TEMPLATE_URL = 'https://github.com/poetora/starter/archive/refs/heads/main.zip';
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { execSync } from 'child_process';
|
|
2
1
|
import { getClientVersion, LOCAL_LINKED_CLI_VERSION } from '@poetora/previewing';
|
|
2
|
+
import { execSync } from 'child_process';
|
|
3
3
|
import yargs from 'yargs';
|
|
4
4
|
import { InvalidEnvironmentError } from '../errors/index.js';
|
|
5
5
|
import { CLI_CONSTANTS } from '../types/index.js';
|
|
@@ -55,15 +55,15 @@ export class VersionService {
|
|
|
55
55
|
};
|
|
56
56
|
}
|
|
57
57
|
getCliVersion() {
|
|
58
|
-
if (process.env.CLI_TEST_MODE === 'true') {
|
|
59
|
-
return 'test-cli';
|
|
60
|
-
}
|
|
61
58
|
const y = yargs();
|
|
62
59
|
let version;
|
|
63
60
|
y.showVersion((v) => {
|
|
64
61
|
version = v;
|
|
65
62
|
return false;
|
|
66
63
|
});
|
|
64
|
+
if (process.env.CLI_TEST_MODE === 'true') {
|
|
65
|
+
return 'test-cli';
|
|
66
|
+
}
|
|
67
67
|
if (version === 'unknown') {
|
|
68
68
|
version = LOCAL_LINKED_CLI_VERSION;
|
|
69
69
|
}
|
|
@@ -1,65 +1,61 @@
|
|
|
1
|
+
import { addLog, EmptyLineLog, ErrorLog, InfoLog, SpinnerLog, SuccessLog, WarningLog, } from '@poetora/previewing';
|
|
1
2
|
import chalk from 'chalk';
|
|
2
|
-
import
|
|
3
|
+
import { Text } from 'ink';
|
|
4
|
+
import React from 'react';
|
|
3
5
|
export class ConsoleLogger {
|
|
4
6
|
info(message) {
|
|
5
|
-
|
|
7
|
+
addLog(React.createElement(InfoLog, { message }));
|
|
6
8
|
}
|
|
7
9
|
success(message) {
|
|
8
|
-
|
|
10
|
+
addLog(React.createElement(SuccessLog, { message }));
|
|
9
11
|
}
|
|
10
12
|
error(message) {
|
|
11
|
-
|
|
13
|
+
addLog(React.createElement(ErrorLog, { message }));
|
|
12
14
|
}
|
|
13
15
|
warn(message) {
|
|
14
|
-
|
|
16
|
+
addLog(React.createElement(WarningLog, { message }));
|
|
15
17
|
}
|
|
16
18
|
spinner(message) {
|
|
17
|
-
|
|
19
|
+
addLog(React.createElement(SpinnerLog, { message }));
|
|
20
|
+
return new InkSpinner();
|
|
18
21
|
}
|
|
19
22
|
log(message) {
|
|
20
|
-
|
|
23
|
+
addLog(React.createElement(Text, {}, message));
|
|
21
24
|
}
|
|
22
25
|
logColor(message, color) {
|
|
23
|
-
|
|
26
|
+
addLog(React.createElement(Text, { color }, message));
|
|
24
27
|
}
|
|
25
28
|
logBold(message, color) {
|
|
26
|
-
|
|
27
|
-
console.log(chalk[color].bold(message));
|
|
28
|
-
}
|
|
29
|
-
else {
|
|
30
|
-
console.log(chalk.bold(message));
|
|
31
|
-
}
|
|
29
|
+
addLog(React.createElement(Text, { bold: true, color }, message));
|
|
32
30
|
}
|
|
33
31
|
logSeparator() {
|
|
34
|
-
|
|
32
|
+
addLog(React.createElement(Text, { color: 'gray' }, '─'.repeat(50)));
|
|
35
33
|
}
|
|
36
34
|
logNewLine() {
|
|
37
|
-
|
|
35
|
+
addLog(React.createElement(EmptyLineLog));
|
|
38
36
|
}
|
|
39
37
|
logHeader(message) {
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
38
|
+
this.logNewLine();
|
|
39
|
+
addLog(React.createElement(Text, { bold: true, color: 'cyan' }, message));
|
|
40
|
+
this.logNewLine();
|
|
43
41
|
}
|
|
44
42
|
highlight(text) {
|
|
45
43
|
return chalk.yellow(text);
|
|
46
44
|
}
|
|
47
45
|
}
|
|
48
|
-
class
|
|
49
|
-
spinner;
|
|
50
|
-
constructor(message) {
|
|
51
|
-
this.spinner = ora(message);
|
|
52
|
-
}
|
|
46
|
+
class InkSpinner {
|
|
53
47
|
start() {
|
|
54
|
-
this.spinner.start();
|
|
55
48
|
}
|
|
56
49
|
stop() {
|
|
57
|
-
this.spinner.stop();
|
|
58
50
|
}
|
|
59
51
|
succeed(message) {
|
|
60
|
-
|
|
52
|
+
if (message) {
|
|
53
|
+
addLog(React.createElement(SuccessLog, { message }));
|
|
54
|
+
}
|
|
61
55
|
}
|
|
62
56
|
fail(message) {
|
|
63
|
-
|
|
57
|
+
if (message) {
|
|
58
|
+
addLog(React.createElement(ErrorLog, { message }));
|
|
59
|
+
}
|
|
64
60
|
}
|
|
65
61
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@poetora/cli",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.6",
|
|
4
4
|
"description": "The CLI for Poetora documentation Engine",
|
|
5
5
|
"engines": {
|
|
6
6
|
"node": ">=18.0.0"
|
|
@@ -32,20 +32,20 @@
|
|
|
32
32
|
"color": "4.2.3",
|
|
33
33
|
"detect-port": "1.5.1",
|
|
34
34
|
"front-matter": "4.0.2",
|
|
35
|
-
"fs-extra": "11.
|
|
35
|
+
"fs-extra": "11.1.0",
|
|
36
|
+
"ink": "6.3.0",
|
|
36
37
|
"inquirer": "12.3.0",
|
|
37
38
|
"js-yaml": "4.1.0",
|
|
38
39
|
"mdast-util-mdx-jsx": "3.2.0",
|
|
39
|
-
"
|
|
40
|
-
"react": "^19.0.1",
|
|
40
|
+
"react": "19.2.3",
|
|
41
41
|
"semver": "7.7.2",
|
|
42
42
|
"unist-util-visit": "5.0.0",
|
|
43
43
|
"yargs": "17.7.1",
|
|
44
|
-
"@poetora/link-rot": "0.0.
|
|
45
|
-
"@poetora/prebuild": "0.1.
|
|
46
|
-
"@poetora/previewing": "0.1.
|
|
47
|
-
"@poetora/shared": "0.1.
|
|
48
|
-
"@poetora/validation": "0.1.
|
|
44
|
+
"@poetora/link-rot": "0.0.7",
|
|
45
|
+
"@poetora/prebuild": "0.1.6",
|
|
46
|
+
"@poetora/previewing": "0.1.7",
|
|
47
|
+
"@poetora/shared": "0.1.6",
|
|
48
|
+
"@poetora/validation": "0.1.6"
|
|
49
49
|
},
|
|
50
50
|
"devDependencies": {
|
|
51
51
|
"@tsconfig/recommended": "1.0.2",
|
|
@@ -53,9 +53,10 @@
|
|
|
53
53
|
"@types/color": "^3.0.3",
|
|
54
54
|
"@types/detect-port": "1.3.2",
|
|
55
55
|
"@types/fs-extra": "^9.0.13",
|
|
56
|
-
"@types/js-yaml": "
|
|
56
|
+
"@types/js-yaml": "4.0.9",
|
|
57
57
|
"@types/mdast": "4.0.4",
|
|
58
58
|
"@types/node": "22.19.2",
|
|
59
|
+
"@types/react": "19.2.7",
|
|
59
60
|
"@types/yargs": "17.0.22",
|
|
60
61
|
"@typescript-eslint/eslint-plugin": "8.49.0",
|
|
61
62
|
"@typescript-eslint/parser": "8.49.0",
|
package/src/cli-builder.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
+
import chalk from 'chalk';
|
|
1
2
|
import type { Argv } from 'yargs';
|
|
2
3
|
import yargs from 'yargs';
|
|
3
4
|
import { hideBin } from 'yargs/helpers';
|
|
4
|
-
|
|
5
5
|
import {
|
|
6
6
|
CheckCommand,
|
|
7
7
|
DevCommand,
|
|
@@ -9,6 +9,7 @@ import {
|
|
|
9
9
|
LinkCommand,
|
|
10
10
|
UpdateCommand,
|
|
11
11
|
} from './commands/index.js';
|
|
12
|
+
import { checkNodeVersion, suppressConsoleWarnings } from './middlewares.js';
|
|
12
13
|
import {
|
|
13
14
|
AccessibilityCheckService,
|
|
14
15
|
LinkService,
|
|
@@ -60,6 +61,9 @@ export class CliBuilder {
|
|
|
60
61
|
return (
|
|
61
62
|
yargs(hideBin(process.argv))
|
|
62
63
|
.scriptName(this.packageName)
|
|
64
|
+
.version()
|
|
65
|
+
.middleware(checkNodeVersion) // Check Node.js version before any command
|
|
66
|
+
.middleware(suppressConsoleWarnings) // Suppress known console warnings
|
|
63
67
|
// Dev command
|
|
64
68
|
.command(
|
|
65
69
|
'dev',
|
|
@@ -245,14 +249,17 @@ export class CliBuilder {
|
|
|
245
249
|
() => undefined,
|
|
246
250
|
async () => {
|
|
247
251
|
const versions = versionService.getVersions();
|
|
248
|
-
|
|
249
|
-
|
|
252
|
+
// Use chalk for consistent formatting
|
|
253
|
+
console.log(`${chalk.bold.green('cli version')} ${versions.cli}`);
|
|
254
|
+
console.log(`${chalk.bold.green('client version')} ${versions.client}`);
|
|
250
255
|
process.exit(0);
|
|
251
256
|
}
|
|
252
257
|
)
|
|
253
258
|
// Error handling
|
|
254
259
|
.strictCommands()
|
|
255
260
|
.demandCommand(1, 'unknown command. see above for the list of supported commands.')
|
|
261
|
+
|
|
262
|
+
// Alias option flags --help = -h, default --version = -v
|
|
256
263
|
.alias('h', 'help')
|
|
257
264
|
.alias('v', 'version')
|
|
258
265
|
);
|
package/src/cli.ts
CHANGED
|
@@ -1,4 +1,8 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
+
import { Logs } from '@poetora/previewing';
|
|
3
|
+
import { render } from 'ink';
|
|
4
|
+
import React from 'react';
|
|
5
|
+
|
|
2
6
|
import { CliBuilder } from './cli-builder.js';
|
|
3
7
|
|
|
4
8
|
export interface CliOptions {
|
|
@@ -6,6 +10,9 @@ export interface CliOptions {
|
|
|
6
10
|
}
|
|
7
11
|
|
|
8
12
|
export const cli = (options: CliOptions): void => {
|
|
13
|
+
// Initialize ink rendering for logs
|
|
14
|
+
render(React.createElement(Logs));
|
|
15
|
+
|
|
9
16
|
const builder = new CliBuilder(options.packageName);
|
|
10
17
|
|
|
11
18
|
builder.run().catch((error) => {
|
|
@@ -104,14 +104,11 @@ describe('BaseCommand', () => {
|
|
|
104
104
|
(command as unknown as { execute: typeof command.execute }).execute = vi
|
|
105
105
|
.fn()
|
|
106
106
|
.mockRejectedValue('string error');
|
|
107
|
-
const consoleErrorSpy = vi.spyOn(console, 'error').mockImplementation(() => {});
|
|
108
107
|
|
|
109
108
|
await expect(command.run({ value: 'test' })).rejects.toBe('string error');
|
|
110
109
|
|
|
111
110
|
expect(mockLogger.error).toHaveBeenCalledWith('An unexpected error occurred');
|
|
112
|
-
expect(
|
|
113
|
-
|
|
114
|
-
consoleErrorSpy.mockRestore();
|
|
111
|
+
expect(mockLogger.logColor).toHaveBeenCalledWith('string error', 'gray');
|
|
115
112
|
});
|
|
116
113
|
|
|
117
114
|
it('should show stack trace in debug mode', async () => {
|
|
@@ -122,13 +119,10 @@ describe('BaseCommand', () => {
|
|
|
122
119
|
(command as unknown as { execute: typeof command.execute }).execute = vi
|
|
123
120
|
.fn()
|
|
124
121
|
.mockRejectedValue(error);
|
|
125
|
-
const consoleErrorSpy = vi.spyOn(console, 'error').mockImplementation(() => {});
|
|
126
122
|
|
|
127
123
|
await expect(command.run({ value: 'test' })).rejects.toThrow(error);
|
|
128
124
|
|
|
129
|
-
expect(
|
|
130
|
-
|
|
131
|
-
consoleErrorSpy.mockRestore();
|
|
125
|
+
expect(mockLogger.logColor).toHaveBeenCalledWith(error.stack ?? '', 'gray');
|
|
132
126
|
process.env.DEBUG = originalDebug;
|
|
133
127
|
});
|
|
134
128
|
});
|
|
@@ -78,12 +78,12 @@ export abstract class BaseCommand<TOptions = unknown, TResult = void> {
|
|
|
78
78
|
|
|
79
79
|
// In debug mode, show stack trace
|
|
80
80
|
if (process.env.DEBUG === 'true') {
|
|
81
|
-
|
|
81
|
+
this.logger.logColor(error.stack ?? '', 'gray');
|
|
82
82
|
}
|
|
83
83
|
} else {
|
|
84
84
|
// Unknown error types
|
|
85
85
|
this.logger.error('An unexpected error occurred');
|
|
86
|
-
|
|
86
|
+
this.logger.logColor(String(error), 'gray');
|
|
87
87
|
}
|
|
88
88
|
}
|
|
89
89
|
|
package/src/mdxAccessibility.ts
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import fs from 'fs';
|
|
2
|
-
import path from 'path';
|
|
3
1
|
import { categorizeFilePaths, getPoetIgnore } from '@poetora/prebuild';
|
|
4
2
|
import { coreRemark } from '@poetora/shared';
|
|
3
|
+
import fs from 'fs';
|
|
5
4
|
import type { Node, Root, Text } from 'mdast';
|
|
6
5
|
import type { MdxJsxFlowElement } from 'mdast-util-mdx-jsx';
|
|
6
|
+
import path from 'path';
|
|
7
7
|
import { visit } from 'unist-util-visit';
|
|
8
8
|
|
|
9
9
|
export interface AccessibilityFixAttribute {
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import { addLog, ErrorLog } from '@poetora/previewing';
|
|
2
|
+
import React from 'react';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Yargs middleware functions
|
|
6
|
+
* These run before command execution
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Check if Node.js version is supported
|
|
11
|
+
* Middleware that validates Node version before any command runs
|
|
12
|
+
*
|
|
13
|
+
* Minimum requirement: Node.js >= 18.0.0
|
|
14
|
+
* Note: Individual commands may have stricter requirements (e.g., dev command)
|
|
15
|
+
*/
|
|
16
|
+
export const checkNodeVersion = async (): Promise<void> => {
|
|
17
|
+
let nodeVersionString = process.version;
|
|
18
|
+
if (nodeVersionString.charAt(0) === 'v') {
|
|
19
|
+
nodeVersionString = nodeVersionString.slice(1);
|
|
20
|
+
}
|
|
21
|
+
const versionArr = nodeVersionString.split('.');
|
|
22
|
+
const versionStr = versionArr[0];
|
|
23
|
+
if (!versionStr) {
|
|
24
|
+
addLog(
|
|
25
|
+
React.createElement(ErrorLog, {
|
|
26
|
+
message: `Unable to determine Node.js version (got "${process.version}"). Please ensure you are running Node.js >= 18.0.0.`,
|
|
27
|
+
})
|
|
28
|
+
);
|
|
29
|
+
process.exit(1);
|
|
30
|
+
}
|
|
31
|
+
const majorVersion = parseInt(versionStr, 10);
|
|
32
|
+
|
|
33
|
+
if (majorVersion < 18) {
|
|
34
|
+
addLog(
|
|
35
|
+
React.createElement(ErrorLog, {
|
|
36
|
+
message: `poetora requires Node.js >= 18.0.0 (current version ${nodeVersionString}). Please upgrade Node.js and try again.`,
|
|
37
|
+
})
|
|
38
|
+
);
|
|
39
|
+
process.exit(1);
|
|
40
|
+
}
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* Suppress common console warnings that don't affect functionality
|
|
45
|
+
* Filters out known noise from dependencies
|
|
46
|
+
*/
|
|
47
|
+
export const suppressConsoleWarnings = (): void => {
|
|
48
|
+
// Ignore tailwind warnings and punycode deprecation warning
|
|
49
|
+
const ignoredMessages = [
|
|
50
|
+
'No utility classes were detected',
|
|
51
|
+
'https://tailwindcss.com/docs/content-configuration',
|
|
52
|
+
'DeprecationWarning',
|
|
53
|
+
'punycode',
|
|
54
|
+
];
|
|
55
|
+
|
|
56
|
+
const originalConsoleError = console.error;
|
|
57
|
+
console.error = (...args) => {
|
|
58
|
+
const message = args.join(' ');
|
|
59
|
+
if (ignoredMessages.some((ignoredMessage) => message.includes(ignoredMessage))) {
|
|
60
|
+
return;
|
|
61
|
+
}
|
|
62
|
+
originalConsoleError.apply(console, args);
|
|
63
|
+
};
|
|
64
|
+
|
|
65
|
+
const originalConsoleWarn = console.warn;
|
|
66
|
+
console.warn = (...args) => {
|
|
67
|
+
const message = args.join(' ');
|
|
68
|
+
if (ignoredMessages.some((ignoredMessage) => message.includes(ignoredMessage))) {
|
|
69
|
+
return;
|
|
70
|
+
}
|
|
71
|
+
originalConsoleWarn.apply(console, args);
|
|
72
|
+
};
|
|
73
|
+
};
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import * as fs from 'fs';
|
|
2
1
|
import AdmZip from 'adm-zip';
|
|
2
|
+
import * as fs from 'fs';
|
|
3
3
|
import * as fse from 'fs-extra';
|
|
4
4
|
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
|
|
5
5
|
import { ExternalServiceError, FileSystemError } from '../../errors/index.js';
|
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import * as path from 'path';
|
|
2
1
|
import {
|
|
3
2
|
getBrokenInternalLinks,
|
|
4
3
|
type MdxPath,
|
|
5
4
|
renameFilesAndUpdateLinksInContent,
|
|
6
5
|
} from '@poetora/link-rot';
|
|
6
|
+
import * as path from 'path';
|
|
7
7
|
|
|
8
8
|
import type { ILogger } from '../utils/index.js';
|
|
9
9
|
|
|
@@ -46,7 +46,7 @@ export class LinkService {
|
|
|
46
46
|
|
|
47
47
|
for (const [filename, links] of Object.entries(brokenLinksByFile)) {
|
|
48
48
|
// Underline filename for better visibility
|
|
49
|
-
|
|
49
|
+
this.logger.logColor(filename, 'cyan');
|
|
50
50
|
links.forEach((link) => {
|
|
51
51
|
this.logger.logColor(` ⎿ ${link}`, 'gray');
|
|
52
52
|
});
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import * as fs from 'fs';
|
|
2
|
-
import * as path from 'path';
|
|
3
1
|
import { docsConfigSchema } from '@poetora/validation';
|
|
4
2
|
import AdmZip from 'adm-zip';
|
|
3
|
+
import * as fs from 'fs';
|
|
5
4
|
import * as fse from 'fs-extra';
|
|
5
|
+
import * as path from 'path';
|
|
6
6
|
|
|
7
7
|
import { ExternalServiceError, FileSystemError } from '../errors/index.js';
|
|
8
8
|
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { execSync } from 'child_process';
|
|
2
1
|
import { getClientVersion, LOCAL_LINKED_CLI_VERSION } from '@poetora/previewing';
|
|
2
|
+
import { execSync } from 'child_process';
|
|
3
3
|
import yargs from 'yargs';
|
|
4
4
|
|
|
5
5
|
import { InvalidEnvironmentError } from '../errors/index.js';
|
|
@@ -83,10 +83,6 @@ export class VersionService {
|
|
|
83
83
|
* Get CLI version from package.json
|
|
84
84
|
*/
|
|
85
85
|
getCliVersion(): string | undefined {
|
|
86
|
-
if (process.env.CLI_TEST_MODE === 'true') {
|
|
87
|
-
return 'test-cli';
|
|
88
|
-
}
|
|
89
|
-
|
|
90
86
|
const y = yargs();
|
|
91
87
|
let version: string | undefined;
|
|
92
88
|
|
|
@@ -95,7 +91,11 @@ export class VersionService {
|
|
|
95
91
|
return false;
|
|
96
92
|
});
|
|
97
93
|
|
|
98
|
-
|
|
94
|
+
if (process.env.CLI_TEST_MODE === 'true') {
|
|
95
|
+
return 'test-cli';
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
// When running npm link or pnpm link, the version is 'unknown'
|
|
99
99
|
if (version === 'unknown') {
|
|
100
100
|
version = LOCAL_LINKED_CLI_VERSION;
|
|
101
101
|
}
|
|
@@ -1,37 +1,49 @@
|
|
|
1
|
+
import {
|
|
2
|
+
addLog,
|
|
3
|
+
EmptyLineLog,
|
|
4
|
+
ErrorLog,
|
|
5
|
+
InfoLog,
|
|
6
|
+
SpinnerLog,
|
|
7
|
+
SuccessLog,
|
|
8
|
+
WarningLog,
|
|
9
|
+
} from '@poetora/previewing';
|
|
1
10
|
import chalk from 'chalk';
|
|
2
|
-
import
|
|
11
|
+
import { Text } from 'ink';
|
|
12
|
+
import React from 'react';
|
|
3
13
|
|
|
4
14
|
import type { LoggerSpinner } from '../types/index.js';
|
|
5
15
|
|
|
6
16
|
import type { ILogger } from './logger.interface.js';
|
|
7
17
|
|
|
8
18
|
/**
|
|
9
|
-
*
|
|
10
|
-
* Provides
|
|
19
|
+
* Logger implementation using ink and addLog from @poetora/previewing
|
|
20
|
+
* Provides consistent output with the preview server's logging system
|
|
11
21
|
*/
|
|
12
22
|
export class ConsoleLogger implements ILogger {
|
|
13
23
|
info(message: string): void {
|
|
14
|
-
|
|
24
|
+
addLog(React.createElement(InfoLog, { message }));
|
|
15
25
|
}
|
|
16
26
|
|
|
17
27
|
success(message: string): void {
|
|
18
|
-
|
|
28
|
+
addLog(React.createElement(SuccessLog, { message }));
|
|
19
29
|
}
|
|
20
30
|
|
|
21
31
|
error(message: string): void {
|
|
22
|
-
|
|
32
|
+
addLog(React.createElement(ErrorLog, { message }));
|
|
23
33
|
}
|
|
24
34
|
|
|
25
35
|
warn(message: string): void {
|
|
26
|
-
|
|
36
|
+
addLog(React.createElement(WarningLog, { message }));
|
|
27
37
|
}
|
|
28
38
|
|
|
29
39
|
spinner(message: string): LoggerSpinner {
|
|
30
|
-
|
|
40
|
+
// Immediately add spinner log
|
|
41
|
+
addLog(React.createElement(SpinnerLog, { message }));
|
|
42
|
+
return new InkSpinner();
|
|
31
43
|
}
|
|
32
44
|
|
|
33
45
|
log(message: string): void {
|
|
34
|
-
|
|
46
|
+
addLog(React.createElement(Text, {}, message));
|
|
35
47
|
}
|
|
36
48
|
|
|
37
49
|
/**
|
|
@@ -41,45 +53,42 @@ export class ConsoleLogger implements ILogger {
|
|
|
41
53
|
message: string,
|
|
42
54
|
color: 'green' | 'red' | 'yellow' | 'blue' | 'cyan' | 'magenta' | 'gray'
|
|
43
55
|
): void {
|
|
44
|
-
|
|
56
|
+
addLog(React.createElement(Text, { color }, message));
|
|
45
57
|
}
|
|
46
58
|
|
|
47
59
|
/**
|
|
48
60
|
* Log bold text
|
|
49
61
|
*/
|
|
50
62
|
logBold(message: string, color?: 'green' | 'red' | 'yellow' | 'blue' | 'cyan' | 'magenta'): void {
|
|
51
|
-
|
|
52
|
-
console.log(chalk[color].bold(message));
|
|
53
|
-
} else {
|
|
54
|
-
console.log(chalk.bold(message));
|
|
55
|
-
}
|
|
63
|
+
addLog(React.createElement(Text, { bold: true, color }, message));
|
|
56
64
|
}
|
|
57
65
|
|
|
58
66
|
/**
|
|
59
67
|
* Log a separator line
|
|
60
68
|
*/
|
|
61
69
|
logSeparator(): void {
|
|
62
|
-
|
|
70
|
+
addLog(React.createElement(Text, { color: 'gray' }, '─'.repeat(50)));
|
|
63
71
|
}
|
|
64
72
|
|
|
65
73
|
/**
|
|
66
74
|
* Log an empty line
|
|
67
75
|
*/
|
|
68
76
|
logNewLine(): void {
|
|
69
|
-
|
|
77
|
+
addLog(React.createElement(EmptyLineLog));
|
|
70
78
|
}
|
|
71
79
|
|
|
72
80
|
/**
|
|
73
81
|
* Log a section header
|
|
74
82
|
*/
|
|
75
83
|
logHeader(message: string): void {
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
84
|
+
this.logNewLine();
|
|
85
|
+
addLog(React.createElement(Text, { bold: true, color: 'cyan' }, message));
|
|
86
|
+
this.logNewLine();
|
|
79
87
|
}
|
|
80
88
|
|
|
81
89
|
/**
|
|
82
90
|
* Highlight text (typically numbers) with yellow color
|
|
91
|
+
* Note: Returns styled text string for embedding in messages
|
|
83
92
|
*/
|
|
84
93
|
highlight(text: string): string {
|
|
85
94
|
return chalk.yellow(text);
|
|
@@ -87,28 +96,28 @@ export class ConsoleLogger implements ILogger {
|
|
|
87
96
|
}
|
|
88
97
|
|
|
89
98
|
/**
|
|
90
|
-
*
|
|
99
|
+
* Spinner implementation for ink-based logging
|
|
100
|
+
* Note: In ink/React rendering model, spinners are added as logs
|
|
101
|
+
* and don't need explicit start/stop/succeed/fail methods
|
|
91
102
|
*/
|
|
92
|
-
class
|
|
93
|
-
private spinner: Ora;
|
|
94
|
-
|
|
95
|
-
constructor(message: string) {
|
|
96
|
-
this.spinner = ora(message);
|
|
97
|
-
}
|
|
98
|
-
|
|
103
|
+
class InkSpinner implements LoggerSpinner {
|
|
99
104
|
start(): void {
|
|
100
|
-
|
|
105
|
+
// No-op: spinner already added to log stream
|
|
101
106
|
}
|
|
102
107
|
|
|
103
108
|
stop(): void {
|
|
104
|
-
|
|
109
|
+
// No-op: will be replaced by next log
|
|
105
110
|
}
|
|
106
111
|
|
|
107
112
|
succeed(message?: string): void {
|
|
108
|
-
|
|
113
|
+
if (message) {
|
|
114
|
+
addLog(React.createElement(SuccessLog, { message }));
|
|
115
|
+
}
|
|
109
116
|
}
|
|
110
117
|
|
|
111
118
|
fail(message?: string): void {
|
|
112
|
-
|
|
119
|
+
if (message) {
|
|
120
|
+
addLog(React.createElement(ErrorLog, { message }));
|
|
121
|
+
}
|
|
113
122
|
}
|
|
114
123
|
}
|