@poetora/cli 0.0.1 → 0.1.2

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.
Files changed (117) hide show
  1. package/.turbo/turbo-build.log +4 -0
  2. package/LICENSE +93 -0
  3. package/bin/accessibility.js +2 -2
  4. package/bin/cli-builder.d.ts +8 -0
  5. package/bin/cli-builder.js +178 -0
  6. package/bin/cli.d.ts +5 -11
  7. package/bin/cli.js +8 -200
  8. package/bin/commands/base.command.d.ts +13 -0
  9. package/bin/commands/base.command.js +40 -0
  10. package/bin/commands/check.command.d.ts +14 -0
  11. package/bin/commands/check.command.js +21 -0
  12. package/bin/commands/dev.command.d.ts +13 -0
  13. package/bin/commands/dev.command.js +40 -0
  14. package/bin/commands/index.d.ts +6 -0
  15. package/bin/commands/index.js +6 -0
  16. package/bin/commands/init.command.d.ts +16 -0
  17. package/bin/commands/init.command.js +88 -0
  18. package/bin/commands/link.command.d.ts +13 -0
  19. package/bin/commands/link.command.js +19 -0
  20. package/bin/commands/update.command.d.ts +10 -0
  21. package/bin/commands/update.command.js +13 -0
  22. package/bin/constants.js +1 -1
  23. package/bin/errors/cli-error.d.ts +26 -0
  24. package/bin/errors/cli-error.js +53 -0
  25. package/bin/errors/index.d.ts +1 -0
  26. package/bin/errors/index.js +1 -0
  27. package/bin/index.d.ts +1 -1
  28. package/bin/index.js +6 -6
  29. package/bin/mdxAccessibility.js +2 -2
  30. package/bin/services/accessibility-check.service.d.ts +10 -0
  31. package/bin/services/accessibility-check.service.js +144 -0
  32. package/bin/services/index.d.ts +7 -0
  33. package/bin/services/index.js +7 -0
  34. package/bin/services/link.service.d.ts +7 -0
  35. package/bin/services/link.service.js +40 -0
  36. package/bin/services/openapi-check.service.d.ts +7 -0
  37. package/bin/services/openapi-check.service.js +43 -0
  38. package/bin/services/port.service.d.ts +7 -0
  39. package/bin/services/port.service.js +26 -0
  40. package/bin/services/template.service.d.ts +22 -0
  41. package/bin/services/template.service.js +127 -0
  42. package/bin/services/update.service.d.ts +10 -0
  43. package/bin/services/update.service.js +57 -0
  44. package/bin/services/version.service.d.ts +16 -0
  45. package/bin/services/version.service.js +102 -0
  46. package/bin/types/common.d.ts +38 -0
  47. package/bin/types/common.js +21 -0
  48. package/bin/types/index.d.ts +2 -0
  49. package/bin/types/index.js +2 -0
  50. package/bin/types/options.d.ts +23 -0
  51. package/bin/types/options.js +1 -0
  52. package/bin/utils/console-logger.d.ts +16 -0
  53. package/bin/utils/console-logger.js +65 -0
  54. package/bin/utils/index.d.ts +2 -0
  55. package/bin/utils/index.js +2 -0
  56. package/bin/utils/logger.interface.d.ts +15 -0
  57. package/bin/utils/logger.interface.js +1 -0
  58. package/package.json +29 -29
  59. package/src/accessibility.ts +2 -2
  60. package/src/cli-builder.ts +267 -0
  61. package/src/cli.ts +15 -0
  62. package/src/commands/__tests__/base.command.test.ts +145 -0
  63. package/src/commands/__tests__/dev.command.test.ts +241 -0
  64. package/src/commands/__tests__/init.command.test.ts +281 -0
  65. package/{__test__ → src/commands/__tests__}/utils.ts +1 -1
  66. package/src/commands/base.command.ts +97 -0
  67. package/src/commands/check.command.ts +40 -0
  68. package/src/commands/dev.command.ts +63 -0
  69. package/src/commands/index.ts +6 -0
  70. package/src/commands/init.command.ts +125 -0
  71. package/src/commands/link.command.ts +39 -0
  72. package/src/commands/update.command.ts +23 -0
  73. package/src/constants.ts +1 -1
  74. package/src/errors/cli-error.ts +83 -0
  75. package/src/errors/index.ts +1 -0
  76. package/src/index.ts +6 -6
  77. package/src/mdxAccessibility.ts +3 -4
  78. package/src/services/__tests__/port.service.test.ts +83 -0
  79. package/src/services/__tests__/template.service.test.ts +234 -0
  80. package/src/services/__tests__/version.service.test.ts +165 -0
  81. package/src/services/accessibility-check.service.ts +226 -0
  82. package/src/services/index.ts +7 -0
  83. package/src/services/link.service.ts +65 -0
  84. package/src/services/openapi-check.service.ts +68 -0
  85. package/src/services/port.service.ts +47 -0
  86. package/src/services/template.service.ts +203 -0
  87. package/src/services/update.service.ts +76 -0
  88. package/src/services/version.service.ts +161 -0
  89. package/src/types/common.ts +53 -0
  90. package/src/types/index.ts +2 -0
  91. package/src/types/options.ts +42 -0
  92. package/src/utils/console-logger.ts +114 -0
  93. package/src/utils/index.ts +2 -0
  94. package/src/utils/logger.interface.ts +70 -0
  95. package/tsconfig.build.json +2 -1
  96. package/tsconfig.json +1 -1
  97. package/.prettierignore +0 -2
  98. package/__test__/brokenLinks.test.ts +0 -93
  99. package/__test__/checkPort.test.ts +0 -92
  100. package/__test__/openApiCheck.test.ts +0 -127
  101. package/__test__/update.test.ts +0 -108
  102. package/bin/accessibilityCheck.d.ts +0 -2
  103. package/bin/accessibilityCheck.js +0 -70
  104. package/bin/helpers.d.ts +0 -17
  105. package/bin/helpers.js +0 -104
  106. package/bin/init.d.ts +0 -1
  107. package/bin/init.js +0 -73
  108. package/bin/mdxLinter.d.ts +0 -2
  109. package/bin/mdxLinter.js +0 -45
  110. package/bin/update.d.ts +0 -3
  111. package/bin/update.js +0 -32
  112. package/src/accessibilityCheck.tsx +0 -145
  113. package/src/cli.tsx +0 -302
  114. package/src/helpers.tsx +0 -131
  115. package/src/init.tsx +0 -93
  116. package/src/mdxLinter.tsx +0 -88
  117. package/src/update.tsx +0 -37
@@ -0,0 +1,161 @@
1
+ import { execSync } from 'node: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,2 @@
1
+ export * from './common.js';
2
+ export * from './options.js';
@@ -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,2 @@
1
+ export * from './console-logger.js';
2
+ export * from './logger.interface.js';
@@ -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
+ }
@@ -12,5 +12,6 @@
12
12
  "declaration": true,
13
13
  "declarationMap": false,
14
14
  "inlineSources": false
15
- }
15
+ },
16
+ "exclude": ["__tests__", "**/__tests__", "**/*.test.ts", "**/*.spec.ts"]
16
17
  }
package/tsconfig.json CHANGED
@@ -17,5 +17,5 @@
17
17
  "verbatimModuleSyntax": false,
18
18
  "noImplicitReturns": false
19
19
  },
20
- "include": ["src/**/*.ts", "src/**/*.tsx", "__test__/**/*.ts"]
20
+ "include": ["src/**/*.ts", "src/**/*.tsx", "__tests__/**/*.ts"]
21
21
  }
package/.prettierignore DELETED
@@ -1,2 +0,0 @@
1
- /bin
2
- /node_modules
@@ -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
- });