@poetora/cli 0.0.1 → 0.1.3
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 +4 -0
- package/LICENSE +93 -0
- package/bin/accessibility.js +2 -2
- package/bin/cli-builder.d.ts +8 -0
- package/bin/cli-builder.js +178 -0
- package/bin/cli.d.ts +5 -11
- package/bin/cli.js +8 -200
- package/bin/commands/base.command.d.ts +13 -0
- package/bin/commands/base.command.js +40 -0
- package/bin/commands/check.command.d.ts +14 -0
- package/bin/commands/check.command.js +21 -0
- package/bin/commands/dev.command.d.ts +13 -0
- package/bin/commands/dev.command.js +40 -0
- package/bin/commands/index.d.ts +6 -0
- package/bin/commands/index.js +6 -0
- package/bin/commands/init.command.d.ts +16 -0
- package/bin/commands/init.command.js +88 -0
- package/bin/commands/link.command.d.ts +13 -0
- package/bin/commands/link.command.js +19 -0
- package/bin/commands/update.command.d.ts +10 -0
- package/bin/commands/update.command.js +13 -0
- package/bin/errors/cli-error.d.ts +26 -0
- package/bin/errors/cli-error.js +53 -0
- package/bin/errors/index.d.ts +1 -0
- package/bin/errors/index.js +1 -0
- package/bin/index.js +3 -3
- package/bin/mdxAccessibility.js +2 -2
- package/bin/services/accessibility-check.service.d.ts +10 -0
- package/bin/services/accessibility-check.service.js +144 -0
- package/bin/services/index.d.ts +7 -0
- package/bin/services/index.js +7 -0
- package/bin/services/link.service.d.ts +7 -0
- package/bin/services/link.service.js +40 -0
- package/bin/services/openapi-check.service.d.ts +7 -0
- package/bin/services/openapi-check.service.js +43 -0
- package/bin/services/port.service.d.ts +7 -0
- package/bin/services/port.service.js +26 -0
- package/bin/services/template.service.d.ts +22 -0
- package/bin/services/template.service.js +127 -0
- package/bin/services/update.service.d.ts +10 -0
- package/bin/services/update.service.js +57 -0
- package/bin/services/version.service.d.ts +16 -0
- package/bin/services/version.service.js +102 -0
- package/bin/types/common.d.ts +38 -0
- package/bin/types/common.js +21 -0
- package/bin/types/index.d.ts +2 -0
- package/bin/types/index.js +2 -0
- package/bin/types/options.d.ts +23 -0
- package/bin/types/options.js +1 -0
- package/bin/utils/console-logger.d.ts +16 -0
- package/bin/utils/console-logger.js +65 -0
- package/bin/utils/index.d.ts +2 -0
- package/bin/utils/index.js +2 -0
- package/bin/utils/logger.interface.d.ts +15 -0
- package/bin/utils/logger.interface.js +1 -0
- package/package.json +30 -31
- package/src/accessibility.ts +2 -2
- package/src/cli-builder.ts +267 -0
- package/src/cli.ts +15 -0
- package/src/commands/__tests__/base.command.test.ts +145 -0
- package/src/commands/__tests__/dev.command.test.ts +241 -0
- package/src/commands/__tests__/init.command.test.ts +281 -0
- package/{__test__ → src/commands/__tests__}/utils.ts +1 -1
- package/src/commands/base.command.ts +97 -0
- package/src/commands/check.command.ts +40 -0
- package/src/commands/dev.command.ts +63 -0
- package/src/commands/index.ts +6 -0
- package/src/commands/init.command.ts +125 -0
- package/src/commands/link.command.ts +39 -0
- package/src/commands/update.command.ts +23 -0
- package/src/errors/cli-error.ts +83 -0
- package/src/errors/index.ts +1 -0
- package/src/index.ts +4 -4
- package/src/mdxAccessibility.ts +3 -4
- package/src/services/__tests__/port.service.test.ts +83 -0
- package/src/services/__tests__/template.service.test.ts +234 -0
- package/src/services/__tests__/version.service.test.ts +165 -0
- package/src/services/accessibility-check.service.ts +226 -0
- package/src/services/index.ts +7 -0
- package/src/services/link.service.ts +65 -0
- package/src/services/openapi-check.service.ts +68 -0
- package/src/services/port.service.ts +47 -0
- package/src/services/template.service.ts +203 -0
- package/src/services/update.service.ts +76 -0
- package/src/services/version.service.ts +161 -0
- package/src/types/common.ts +53 -0
- package/src/types/index.ts +2 -0
- package/src/types/options.ts +42 -0
- package/src/utils/console-logger.ts +114 -0
- package/src/utils/index.ts +2 -0
- package/src/utils/logger.interface.ts +70 -0
- package/tsconfig.build.json +2 -1
- package/tsconfig.json +1 -1
- package/.prettierignore +0 -2
- package/__test__/brokenLinks.test.ts +0 -93
- package/__test__/checkPort.test.ts +0 -92
- package/__test__/openApiCheck.test.ts +0 -127
- package/__test__/update.test.ts +0 -108
- package/bin/accessibilityCheck.d.ts +0 -2
- package/bin/accessibilityCheck.js +0 -70
- package/bin/helpers.d.ts +0 -17
- package/bin/helpers.js +0 -104
- package/bin/init.d.ts +0 -1
- package/bin/init.js +0 -73
- package/bin/mdxLinter.d.ts +0 -2
- package/bin/mdxLinter.js +0 -45
- package/bin/update.d.ts +0 -3
- package/bin/update.js +0 -32
- package/src/accessibilityCheck.tsx +0 -145
- package/src/cli.tsx +0 -302
- package/src/helpers.tsx +0 -131
- package/src/init.tsx +0 -93
- package/src/mdxLinter.tsx +0 -88
- package/src/update.tsx +0 -37
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
import { execSync } from 'child_process';
|
|
2
|
+
import { getClientVersion, LOCAL_LINKED_CLI_VERSION } from '@poetora/previewing';
|
|
3
|
+
import yargs from 'yargs';
|
|
4
|
+
|
|
5
|
+
import { InvalidEnvironmentError } from '../errors/index.js';
|
|
6
|
+
import { CLI_CONSTANTS, type NodeVersion, type ValidationResult } from '../types/index.js';
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Service for handling version checks and management
|
|
10
|
+
*/
|
|
11
|
+
export class VersionService {
|
|
12
|
+
constructor(private readonly packageName: string = 'poet') {}
|
|
13
|
+
/**
|
|
14
|
+
* Parse Node.js version string
|
|
15
|
+
*/
|
|
16
|
+
parseNodeVersion(): NodeVersion {
|
|
17
|
+
let versionString = process.version;
|
|
18
|
+
|
|
19
|
+
// Remove 'v' prefix if present
|
|
20
|
+
if (versionString.charAt(0) === 'v') {
|
|
21
|
+
versionString = versionString.slice(1);
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
const parts = versionString.split('.');
|
|
25
|
+
const major = parseInt(parts[0] ?? '0', 10);
|
|
26
|
+
const minor = parseInt(parts[1] ?? '0', 10);
|
|
27
|
+
const patch = parseInt(parts[2] ?? '0', 10);
|
|
28
|
+
|
|
29
|
+
return {
|
|
30
|
+
major,
|
|
31
|
+
minor,
|
|
32
|
+
patch,
|
|
33
|
+
raw: versionString,
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Check if current Node.js version is supported
|
|
39
|
+
*/
|
|
40
|
+
checkNodeVersion(): ValidationResult {
|
|
41
|
+
const current = this.parseNodeVersion();
|
|
42
|
+
const { MIN_MAJOR, MIN_MINOR, MAX_MAJOR, RECOMMENDED_MAJOR, RECOMMENDED_MINOR } =
|
|
43
|
+
CLI_CONSTANTS.NODE_VERSION;
|
|
44
|
+
|
|
45
|
+
// Check if version is below minimum
|
|
46
|
+
if (current.major < MIN_MAJOR || (current.major === MIN_MAJOR && current.minor < MIN_MINOR)) {
|
|
47
|
+
return {
|
|
48
|
+
isValid: false,
|
|
49
|
+
hasWarning: false,
|
|
50
|
+
message: `${this.packageName} requires Node.js ${MIN_MAJOR}.${MIN_MINOR}.0 or higher (current version ${current.raw}). Please upgrade Node.js and try again.`,
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
// Check if version is above maximum
|
|
55
|
+
if (current.major > MAX_MAJOR) {
|
|
56
|
+
return {
|
|
57
|
+
isValid: false,
|
|
58
|
+
hasWarning: false,
|
|
59
|
+
message: `${this.packageName} is not supported on Node.js ${current.major}.x. Please use an LTS version (${MIN_MAJOR}-${MAX_MAJOR}).`,
|
|
60
|
+
};
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
// Check if version is below recommended
|
|
64
|
+
if (
|
|
65
|
+
current.major < RECOMMENDED_MAJOR ||
|
|
66
|
+
(current.major === RECOMMENDED_MAJOR && current.minor < RECOMMENDED_MINOR)
|
|
67
|
+
) {
|
|
68
|
+
return {
|
|
69
|
+
isValid: true,
|
|
70
|
+
hasWarning: true,
|
|
71
|
+
message: `Node.js ${RECOMMENDED_MAJOR}.${RECOMMENDED_MINOR}.0 or higher is recommended for best compatibility (current: ${current.raw}).`,
|
|
72
|
+
};
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
// Version is good
|
|
76
|
+
return {
|
|
77
|
+
isValid: true,
|
|
78
|
+
hasWarning: false,
|
|
79
|
+
};
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
/**
|
|
83
|
+
* Get CLI version from package.json
|
|
84
|
+
*/
|
|
85
|
+
getCliVersion(): string | undefined {
|
|
86
|
+
if (process.env.CLI_TEST_MODE === 'true') {
|
|
87
|
+
return 'test-cli';
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
const y = yargs();
|
|
91
|
+
let version: string | undefined;
|
|
92
|
+
|
|
93
|
+
y.showVersion((v) => {
|
|
94
|
+
version = v;
|
|
95
|
+
return false;
|
|
96
|
+
});
|
|
97
|
+
|
|
98
|
+
// Handle npm link case where version is 'unknown'
|
|
99
|
+
if (version === 'unknown') {
|
|
100
|
+
version = LOCAL_LINKED_CLI_VERSION;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
return version;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
/**
|
|
107
|
+
* Get client version
|
|
108
|
+
*/
|
|
109
|
+
getClientVersion(): string {
|
|
110
|
+
return getClientVersion().trim();
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
/**
|
|
114
|
+
* Get versions of CLI and client
|
|
115
|
+
*/
|
|
116
|
+
getVersions(): { cli: string | undefined; client: string } {
|
|
117
|
+
return {
|
|
118
|
+
cli: this.getCliVersion(),
|
|
119
|
+
client: this.getClientVersion(),
|
|
120
|
+
};
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
/**
|
|
124
|
+
* Get latest CLI version from npm registry
|
|
125
|
+
*/
|
|
126
|
+
getLatestCliVersion(packageName: string): string {
|
|
127
|
+
try {
|
|
128
|
+
const version = execSync(`npm view ${packageName} version --silent`, {
|
|
129
|
+
encoding: 'utf-8',
|
|
130
|
+
stdio: ['pipe', 'pipe', 'pipe'],
|
|
131
|
+
}).trim();
|
|
132
|
+
|
|
133
|
+
return version;
|
|
134
|
+
} catch (error) {
|
|
135
|
+
throw new Error(
|
|
136
|
+
`Failed to fetch latest version for ${packageName}: ${
|
|
137
|
+
error instanceof Error ? error.message : 'unknown error'
|
|
138
|
+
}`
|
|
139
|
+
);
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
/**
|
|
144
|
+
* Check if current version is up to date
|
|
145
|
+
*/
|
|
146
|
+
isVersionUpToDate(currentVersion: string, latestVersion: string): boolean {
|
|
147
|
+
return currentVersion.trim() === latestVersion.trim();
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
/**
|
|
151
|
+
* Validate and throw if Node version is not supported
|
|
152
|
+
* @throws {InvalidEnvironmentError} if Node version is not supported
|
|
153
|
+
*/
|
|
154
|
+
validateNodeVersion(): void {
|
|
155
|
+
const result = this.checkNodeVersion();
|
|
156
|
+
|
|
157
|
+
if (!result.isValid) {
|
|
158
|
+
throw new InvalidEnvironmentError(result.message ?? 'Unsupported Node.js version');
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* CLI constants
|
|
3
|
+
*/
|
|
4
|
+
export const CLI_CONSTANTS = {
|
|
5
|
+
PORT: {
|
|
6
|
+
DEFAULT: 3000,
|
|
7
|
+
MAX_ATTEMPTS: 10,
|
|
8
|
+
},
|
|
9
|
+
NODE_VERSION: {
|
|
10
|
+
MIN_MAJOR: 18,
|
|
11
|
+
MIN_MINOR: 0,
|
|
12
|
+
MAX_MAJOR: 24,
|
|
13
|
+
MAX_MINOR: Number.MAX_SAFE_INTEGER,
|
|
14
|
+
RECOMMENDED_MAJOR: 20,
|
|
15
|
+
RECOMMENDED_MINOR: 17,
|
|
16
|
+
},
|
|
17
|
+
TIMEOUT: {
|
|
18
|
+
PROCESS_KILL: 5000,
|
|
19
|
+
LOG_RENDER: 50,
|
|
20
|
+
},
|
|
21
|
+
UPDATE: {
|
|
22
|
+
CHECK_INTERVAL: 86400000, // 24 hours
|
|
23
|
+
},
|
|
24
|
+
} as const;
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Node version structure
|
|
28
|
+
*/
|
|
29
|
+
export interface NodeVersion {
|
|
30
|
+
major: number;
|
|
31
|
+
minor: number;
|
|
32
|
+
patch: number;
|
|
33
|
+
raw: string;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Validation result
|
|
38
|
+
*/
|
|
39
|
+
export interface ValidationResult {
|
|
40
|
+
isValid: boolean;
|
|
41
|
+
hasWarning: boolean;
|
|
42
|
+
message?: string;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* Logger spinner interface
|
|
47
|
+
*/
|
|
48
|
+
export interface LoggerSpinner {
|
|
49
|
+
start(): void;
|
|
50
|
+
stop(): void;
|
|
51
|
+
succeed(message?: string): void;
|
|
52
|
+
fail(message?: string): void;
|
|
53
|
+
}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Options for dev command
|
|
3
|
+
*/
|
|
4
|
+
export interface DevOptions {
|
|
5
|
+
port?: number;
|
|
6
|
+
open?: boolean;
|
|
7
|
+
localSchema?: boolean;
|
|
8
|
+
clientVersion?: string;
|
|
9
|
+
groups?: string[];
|
|
10
|
+
disableOpenapi?: boolean;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Options for init command
|
|
15
|
+
*/
|
|
16
|
+
export interface InitOptions {
|
|
17
|
+
directory: string;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Options for openapi-check command
|
|
22
|
+
*/
|
|
23
|
+
export interface OpenApiCheckOptions {
|
|
24
|
+
filename: string;
|
|
25
|
+
localSchema?: boolean;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Options for rename command
|
|
30
|
+
*/
|
|
31
|
+
export interface RenameOptions {
|
|
32
|
+
from: string;
|
|
33
|
+
to: string;
|
|
34
|
+
force?: boolean;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Options for update command
|
|
39
|
+
*/
|
|
40
|
+
export interface UpdateOptions {
|
|
41
|
+
packageName: string;
|
|
42
|
+
}
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
import chalk from 'chalk';
|
|
2
|
+
import ora, { type Ora } from 'ora';
|
|
3
|
+
|
|
4
|
+
import type { LoggerSpinner } from '../types/index.js';
|
|
5
|
+
|
|
6
|
+
import type { ILogger } from './logger.interface.js';
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Console-based logger implementation using chalk for colors
|
|
10
|
+
* Provides rich colored output similar to ink but with simpler console-based approach
|
|
11
|
+
*/
|
|
12
|
+
export class ConsoleLogger implements ILogger {
|
|
13
|
+
info(message: string): void {
|
|
14
|
+
console.log(chalk.blue(`ℹ ${message}`));
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
success(message: string): void {
|
|
18
|
+
console.log(chalk.green(`✓ ${message}`));
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
error(message: string): void {
|
|
22
|
+
console.error(chalk.red(`✗ ${message}`));
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
warn(message: string): void {
|
|
26
|
+
console.warn(chalk.yellow(`⚠ ${message}`));
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
spinner(message: string): LoggerSpinner {
|
|
30
|
+
return new ConsoleSpinner(message);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
log(message: string): void {
|
|
34
|
+
console.log(message);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Log with custom color
|
|
39
|
+
*/
|
|
40
|
+
logColor(
|
|
41
|
+
message: string,
|
|
42
|
+
color: 'green' | 'red' | 'yellow' | 'blue' | 'cyan' | 'magenta' | 'gray'
|
|
43
|
+
): void {
|
|
44
|
+
console.log(chalk[color](message));
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* Log bold text
|
|
49
|
+
*/
|
|
50
|
+
logBold(message: string, color?: 'green' | 'red' | 'yellow' | 'blue' | 'cyan' | 'magenta'): void {
|
|
51
|
+
if (color) {
|
|
52
|
+
console.log(chalk[color].bold(message));
|
|
53
|
+
} else {
|
|
54
|
+
console.log(chalk.bold(message));
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* Log a separator line
|
|
60
|
+
*/
|
|
61
|
+
logSeparator(): void {
|
|
62
|
+
console.log(chalk.gray('─'.repeat(50)));
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* Log an empty line
|
|
67
|
+
*/
|
|
68
|
+
logNewLine(): void {
|
|
69
|
+
console.log();
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* Log a section header
|
|
74
|
+
*/
|
|
75
|
+
logHeader(message: string): void {
|
|
76
|
+
console.log();
|
|
77
|
+
console.log(chalk.bold.cyan(message));
|
|
78
|
+
console.log();
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
/**
|
|
82
|
+
* Highlight text (typically numbers) with yellow color
|
|
83
|
+
*/
|
|
84
|
+
highlight(text: string): string {
|
|
85
|
+
return chalk.yellow(text);
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
/**
|
|
90
|
+
* Console spinner implementation using ora
|
|
91
|
+
*/
|
|
92
|
+
class ConsoleSpinner implements LoggerSpinner {
|
|
93
|
+
private spinner: Ora;
|
|
94
|
+
|
|
95
|
+
constructor(message: string) {
|
|
96
|
+
this.spinner = ora(message);
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
start(): void {
|
|
100
|
+
this.spinner.start();
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
stop(): void {
|
|
104
|
+
this.spinner.stop();
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
succeed(message?: string): void {
|
|
108
|
+
this.spinner.succeed(message);
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
fail(message?: string): void {
|
|
112
|
+
this.spinner.fail(message);
|
|
113
|
+
}
|
|
114
|
+
}
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import type { LoggerSpinner } from '../types/index.js';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Logger interface for CLI output
|
|
5
|
+
* Provides rich colored output capabilities
|
|
6
|
+
*/
|
|
7
|
+
export interface ILogger {
|
|
8
|
+
/**
|
|
9
|
+
* Log info message (blue with ℹ icon)
|
|
10
|
+
*/
|
|
11
|
+
info(message: string): void;
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Log success message (green with ✓ icon)
|
|
15
|
+
*/
|
|
16
|
+
success(message: string): void;
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Log error message (red with ✗ icon)
|
|
20
|
+
*/
|
|
21
|
+
error(message: string): void;
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Log warning message (yellow with ⚠ icon)
|
|
25
|
+
*/
|
|
26
|
+
warn(message: string): void;
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Create a spinner for long-running operations
|
|
30
|
+
*/
|
|
31
|
+
spinner(message: string): LoggerSpinner;
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Log plain message without formatting
|
|
35
|
+
*/
|
|
36
|
+
log(message: string): void;
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Log with custom color
|
|
40
|
+
*/
|
|
41
|
+
logColor(
|
|
42
|
+
message: string,
|
|
43
|
+
color: 'green' | 'red' | 'yellow' | 'blue' | 'cyan' | 'magenta' | 'gray'
|
|
44
|
+
): void;
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* Log bold text
|
|
48
|
+
*/
|
|
49
|
+
logBold(message: string, color?: 'green' | 'red' | 'yellow' | 'blue' | 'cyan' | 'magenta'): void;
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* Log a separator line
|
|
53
|
+
*/
|
|
54
|
+
logSeparator(): void;
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* Log an empty line
|
|
58
|
+
*/
|
|
59
|
+
logNewLine(): void;
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* Log a section header
|
|
63
|
+
*/
|
|
64
|
+
logHeader(message: string): void;
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* Highlight text (typically numbers) in a different color
|
|
68
|
+
*/
|
|
69
|
+
highlight?(text: string): string;
|
|
70
|
+
}
|
package/tsconfig.build.json
CHANGED
package/tsconfig.json
CHANGED
package/.prettierignore
DELETED
|
@@ -1,93 +0,0 @@
|
|
|
1
|
-
import { getBrokenInternalLinks, MdxPath } from '@poetora/link-rot';
|
|
2
|
-
import * as previewing from '@poetora/previewing';
|
|
3
|
-
import { mockProcessExit } from 'vitest-mock-process';
|
|
4
|
-
|
|
5
|
-
import { runCommand } from './utils';
|
|
6
|
-
|
|
7
|
-
vi.mock('@poetora/link-rot', async () => {
|
|
8
|
-
const actual = await import('@poetora/link-rot');
|
|
9
|
-
return {
|
|
10
|
-
...actual,
|
|
11
|
-
getBrokenInternalLinks: vi.fn(),
|
|
12
|
-
};
|
|
13
|
-
});
|
|
14
|
-
|
|
15
|
-
const addLogSpy = vi.spyOn(previewing, 'addLog');
|
|
16
|
-
const clearLogsSpy = vi.spyOn(previewing, 'clearLogs');
|
|
17
|
-
const processExitMock = mockProcessExit();
|
|
18
|
-
|
|
19
|
-
describe('brokenLinks', () => {
|
|
20
|
-
beforeEach(() => {
|
|
21
|
-
vi.clearAllMocks();
|
|
22
|
-
});
|
|
23
|
-
|
|
24
|
-
afterEach(() => {
|
|
25
|
-
vi.clearAllMocks();
|
|
26
|
-
});
|
|
27
|
-
|
|
28
|
-
it('success with no broken links', async () => {
|
|
29
|
-
vi.mocked(getBrokenInternalLinks).mockResolvedValueOnce([]);
|
|
30
|
-
|
|
31
|
-
await runCommand('broken-links');
|
|
32
|
-
|
|
33
|
-
expect(addLogSpy).toHaveBeenCalledWith(
|
|
34
|
-
expect.objectContaining({
|
|
35
|
-
props: { message: 'checking for broken links...' },
|
|
36
|
-
})
|
|
37
|
-
);
|
|
38
|
-
expect(addLogSpy).toHaveBeenCalledWith(
|
|
39
|
-
expect.objectContaining({
|
|
40
|
-
props: { message: 'no broken links found' },
|
|
41
|
-
})
|
|
42
|
-
);
|
|
43
|
-
expect(processExitMock).toHaveBeenCalledWith(0);
|
|
44
|
-
});
|
|
45
|
-
|
|
46
|
-
it('fails with broken links', async () => {
|
|
47
|
-
vi.mocked(getBrokenInternalLinks).mockResolvedValueOnce([
|
|
48
|
-
{
|
|
49
|
-
relativeDir: '.',
|
|
50
|
-
filename: 'introduction.mdx',
|
|
51
|
-
originalPath: '/api/invalid-path',
|
|
52
|
-
pathType: 'internal',
|
|
53
|
-
} as MdxPath,
|
|
54
|
-
]);
|
|
55
|
-
|
|
56
|
-
await runCommand('broken-links');
|
|
57
|
-
|
|
58
|
-
expect(addLogSpy).toHaveBeenCalledWith(
|
|
59
|
-
expect.objectContaining({
|
|
60
|
-
props: { message: 'checking for broken links...' },
|
|
61
|
-
})
|
|
62
|
-
);
|
|
63
|
-
expect(clearLogsSpy).toHaveBeenCalled();
|
|
64
|
-
expect(addLogSpy).toHaveBeenCalledWith(
|
|
65
|
-
expect.objectContaining({
|
|
66
|
-
props: {
|
|
67
|
-
brokenLinksByFile: {
|
|
68
|
-
'introduction.mdx': ['/api/invalid-path'],
|
|
69
|
-
},
|
|
70
|
-
},
|
|
71
|
-
})
|
|
72
|
-
);
|
|
73
|
-
expect(processExitMock).toHaveBeenCalledWith(1);
|
|
74
|
-
});
|
|
75
|
-
|
|
76
|
-
it('fails when checking throws error', async () => {
|
|
77
|
-
vi.mocked(getBrokenInternalLinks).mockRejectedValueOnce(new Error('some error'));
|
|
78
|
-
|
|
79
|
-
await runCommand('broken-links');
|
|
80
|
-
|
|
81
|
-
expect(addLogSpy).toHaveBeenCalledWith(
|
|
82
|
-
expect.objectContaining({
|
|
83
|
-
props: { message: 'checking for broken links...' },
|
|
84
|
-
})
|
|
85
|
-
);
|
|
86
|
-
expect(addLogSpy).toHaveBeenCalledWith(
|
|
87
|
-
expect.objectContaining({
|
|
88
|
-
props: { message: 'some error' },
|
|
89
|
-
})
|
|
90
|
-
);
|
|
91
|
-
expect(processExitMock).toHaveBeenCalledWith(1);
|
|
92
|
-
});
|
|
93
|
-
});
|
|
@@ -1,92 +0,0 @@
|
|
|
1
|
-
import * as previewing from '@poetora/previewing';
|
|
2
|
-
import inquirer from 'inquirer';
|
|
3
|
-
import { mockProcessExit } from 'vitest-mock-process';
|
|
4
|
-
|
|
5
|
-
import { runCommand } from './utils';
|
|
6
|
-
|
|
7
|
-
vi.mock('@poetora/previewing', async () => {
|
|
8
|
-
const originalModule =
|
|
9
|
-
await vi.importActual<typeof import('@poetora/previewing')>('@poetora/previewing');
|
|
10
|
-
return {
|
|
11
|
-
...originalModule,
|
|
12
|
-
dev: vi.fn(),
|
|
13
|
-
};
|
|
14
|
-
});
|
|
15
|
-
|
|
16
|
-
vi.mock('readline/promises', () => {
|
|
17
|
-
return {
|
|
18
|
-
createInterface: () => {
|
|
19
|
-
return {
|
|
20
|
-
close: () => undefined,
|
|
21
|
-
question: (question: string) => {
|
|
22
|
-
console.log(question);
|
|
23
|
-
return 'y';
|
|
24
|
-
},
|
|
25
|
-
};
|
|
26
|
-
},
|
|
27
|
-
};
|
|
28
|
-
});
|
|
29
|
-
|
|
30
|
-
const allowedPorts = [3000, 5002];
|
|
31
|
-
|
|
32
|
-
vi.mock('detect-port', () => ({
|
|
33
|
-
default: (port: number) => (allowedPorts.includes(port) ? port : port + 1),
|
|
34
|
-
}));
|
|
35
|
-
|
|
36
|
-
const devSpy = vi.spyOn(previewing, 'dev');
|
|
37
|
-
const addLogSpy = vi.spyOn(previewing, 'addLog');
|
|
38
|
-
const processExitMock = mockProcessExit();
|
|
39
|
-
|
|
40
|
-
describe('checkPort', () => {
|
|
41
|
-
let originalArgv: string[];
|
|
42
|
-
|
|
43
|
-
beforeEach(() => {
|
|
44
|
-
// Remove all cached modules, otherwise the same results are shown in subsequent tests.
|
|
45
|
-
vi.resetModules();
|
|
46
|
-
|
|
47
|
-
// mock inquirer prompt
|
|
48
|
-
vi.spyOn(inquirer, 'prompt').mockResolvedValue({ action: 'continue' });
|
|
49
|
-
|
|
50
|
-
// Keep track of original process arguments.
|
|
51
|
-
originalArgv = process.argv;
|
|
52
|
-
});
|
|
53
|
-
|
|
54
|
-
afterEach(() => {
|
|
55
|
-
vi.resetAllMocks();
|
|
56
|
-
|
|
57
|
-
// Set process arguments back to the original value.
|
|
58
|
-
process.argv = originalArgv;
|
|
59
|
-
});
|
|
60
|
-
|
|
61
|
-
it('should run dev command', async () => {
|
|
62
|
-
await runCommand('dev');
|
|
63
|
-
|
|
64
|
-
expect(devSpy).toHaveBeenCalledWith(expect.objectContaining({ port: 3000 }));
|
|
65
|
-
});
|
|
66
|
-
|
|
67
|
-
it('port 5000 and 5001 should be taken and 5002 should be accepted by the user and available.', async () => {
|
|
68
|
-
await runCommand('dev', '--port=5000');
|
|
69
|
-
|
|
70
|
-
expect(addLogSpy).toHaveBeenCalledTimes(2);
|
|
71
|
-
expect(addLogSpy).toHaveBeenCalledWith(
|
|
72
|
-
expect.objectContaining({
|
|
73
|
-
props: { message: 'port 5000 is already in use. trying 5001 instead' },
|
|
74
|
-
})
|
|
75
|
-
);
|
|
76
|
-
expect(addLogSpy).toHaveBeenCalledWith(
|
|
77
|
-
expect.objectContaining({
|
|
78
|
-
props: { message: 'port 5001 is already in use. trying 5002 instead' },
|
|
79
|
-
})
|
|
80
|
-
);
|
|
81
|
-
});
|
|
82
|
-
|
|
83
|
-
it('fails after the 10th used port', async () => {
|
|
84
|
-
await runCommand('dev', '--port=8000');
|
|
85
|
-
|
|
86
|
-
expect(addLogSpy).toHaveBeenCalledTimes(10);
|
|
87
|
-
expect(addLogSpy).toHaveBeenLastCalledWith(
|
|
88
|
-
expect.objectContaining({ props: { message: 'no available port found' } })
|
|
89
|
-
);
|
|
90
|
-
expect(processExitMock).toHaveBeenCalledWith(1);
|
|
91
|
-
});
|
|
92
|
-
});
|