@poetora/cli 0.1.8 → 0.1.10

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 (46) hide show
  1. package/bin/cli-builder.js +1 -1
  2. package/bin/services/version.service.d.ts +1 -1
  3. package/bin/services/version.service.js +12 -10
  4. package/package.json +8 -3
  5. package/.turbo/turbo-build.log +0 -4
  6. package/src/accessibility.ts +0 -180
  7. package/src/cli-builder.ts +0 -274
  8. package/src/cli.ts +0 -22
  9. package/src/commands/__tests__/base.command.test.ts +0 -139
  10. package/src/commands/__tests__/dev.command.test.ts +0 -241
  11. package/src/commands/__tests__/init.command.test.ts +0 -281
  12. package/src/commands/__tests__/utils.ts +0 -20
  13. package/src/commands/base.command.ts +0 -97
  14. package/src/commands/check.command.ts +0 -40
  15. package/src/commands/dev.command.ts +0 -63
  16. package/src/commands/index.ts +0 -6
  17. package/src/commands/init.command.ts +0 -125
  18. package/src/commands/link.command.ts +0 -39
  19. package/src/commands/update.command.ts +0 -23
  20. package/src/constants.ts +0 -4
  21. package/src/errors/cli-error.ts +0 -83
  22. package/src/errors/index.ts +0 -1
  23. package/src/index.ts +0 -110
  24. package/src/mdxAccessibility.ts +0 -132
  25. package/src/middlewares.ts +0 -73
  26. package/src/services/__tests__/port.service.test.ts +0 -83
  27. package/src/services/__tests__/template.service.test.ts +0 -234
  28. package/src/services/__tests__/version.service.test.ts +0 -165
  29. package/src/services/accessibility-check.service.ts +0 -226
  30. package/src/services/index.ts +0 -7
  31. package/src/services/link.service.ts +0 -65
  32. package/src/services/openapi-check.service.ts +0 -68
  33. package/src/services/port.service.ts +0 -47
  34. package/src/services/template.service.ts +0 -203
  35. package/src/services/update.service.ts +0 -76
  36. package/src/services/version.service.ts +0 -161
  37. package/src/start.ts +0 -6
  38. package/src/types/common.ts +0 -53
  39. package/src/types/index.ts +0 -2
  40. package/src/types/options.ts +0 -42
  41. package/src/utils/console-logger.ts +0 -123
  42. package/src/utils/index.ts +0 -2
  43. package/src/utils/logger.interface.ts +0 -70
  44. package/tsconfig.build.json +0 -17
  45. package/tsconfig.json +0 -21
  46. package/vitest.config.ts +0 -8
@@ -27,7 +27,7 @@ export class CliBuilder {
27
27
  const updateCommand = new UpdateCommand(this.logger, updateService, this.packageName);
28
28
  return (yargs(hideBin(process.argv))
29
29
  .scriptName(this.packageName)
30
- .version()
30
+ .version(versionService.getCliVersion())
31
31
  .middleware(checkNodeVersion)
32
32
  .middleware(suppressConsoleWarnings)
33
33
  .command('dev', 'initialize a local preview environment', (yargs) => yargs
@@ -4,7 +4,7 @@ export declare class VersionService {
4
4
  constructor(packageName?: string);
5
5
  parseNodeVersion(): NodeVersion;
6
6
  checkNodeVersion(): ValidationResult;
7
- getCliVersion(): string | undefined;
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 yargs from 'yargs';
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
- if (version === 'unknown') {
68
- version = LOCAL_LINKED_CLI_VERSION;
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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@poetora/cli",
3
- "version": "0.1.8",
3
+ "version": "0.1.10",
4
4
  "description": "The CLI for Poetora documentation Engine",
5
5
  "engines": {
6
6
  "node": ">=18.0.0"
@@ -20,7 +20,12 @@
20
20
  "access": "public",
21
21
  "registry": "https://registry.npmjs.org/"
22
22
  },
23
+ "main": "./bin/index.js",
23
24
  "exports": "./bin/index.js",
25
+ "files": [
26
+ "bin",
27
+ "LICENSE"
28
+ ],
24
29
  "bin": {
25
30
  "poet": "bin/index.js",
26
31
  "poetora": "bin/index.js"
@@ -44,8 +49,8 @@
44
49
  "@poetora/link-rot": "0.0.7",
45
50
  "@poetora/prebuild": "0.1.6",
46
51
  "@poetora/previewing": "0.1.9",
47
- "@poetora/shared": "0.1.6",
48
- "@poetora/validation": "0.1.6"
52
+ "@poetora/validation": "0.1.6",
53
+ "@poetora/shared": "0.1.6"
49
54
  },
50
55
  "devDependencies": {
51
56
  "@tsconfig/recommended": "1.0.2",
@@ -1,4 +0,0 @@
1
-
2
- > @poetora/cli@0.1.7 build /home/runner/work/poetora/poetora/packages/cli
3
- > tsc --project tsconfig.build.json
4
-
@@ -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
- }
@@ -1,274 +0,0 @@
1
- import chalk from 'chalk';
2
- import type { Argv } from 'yargs';
3
- import yargs from 'yargs';
4
- import { hideBin } from 'yargs/helpers';
5
- import {
6
- CheckCommand,
7
- DevCommand,
8
- InitCommand,
9
- LinkCommand,
10
- UpdateCommand,
11
- } from './commands/index.js';
12
- import { checkNodeVersion, suppressConsoleWarnings } from './middlewares.js';
13
- import {
14
- AccessibilityCheckService,
15
- LinkService,
16
- OpenApiCheckService,
17
- PortService,
18
- TemplateService,
19
- UpdateService,
20
- VersionService,
21
- } from './services/index.js';
22
- import type { DevOptions, OpenApiCheckOptions, RenameOptions } from './types/index.js';
23
- import type { ILogger } from './utils/index.js';
24
- import { ConsoleLogger } from './utils/index.js';
25
-
26
- /**
27
- * CLI Builder - Orchestrates all commands using yargs
28
- */
29
- export class CliBuilder {
30
- private logger: ILogger;
31
-
32
- constructor(private readonly packageName: string = 'poet') {
33
- this.logger = new ConsoleLogger();
34
- }
35
-
36
- /**
37
- * Build and configure the CLI
38
- */
39
- build(): Argv {
40
- // Create services
41
- const versionService = new VersionService(this.packageName);
42
- const portService = new PortService(this.logger);
43
- const templateService = new TemplateService();
44
- const openApiCheckService = new OpenApiCheckService(this.logger);
45
- const accessibilityCheckService = new AccessibilityCheckService();
46
- const linkService = new LinkService(this.logger);
47
- const updateService = new UpdateService(this.logger, versionService, this.packageName);
48
-
49
- // Create commands
50
- const devCommand = new DevCommand(this.logger, versionService, portService, this.packageName);
51
- const initCommand = new InitCommand(this.logger, templateService, this.packageName);
52
- const checkCommand = new CheckCommand(
53
- this.logger,
54
- openApiCheckService,
55
- accessibilityCheckService,
56
- this.packageName
57
- );
58
- const linkCommand = new LinkCommand(this.logger, linkService, this.packageName);
59
- const updateCommand = new UpdateCommand(this.logger, updateService, this.packageName);
60
-
61
- return (
62
- yargs(hideBin(process.argv))
63
- .scriptName(this.packageName)
64
- .version()
65
- .middleware(checkNodeVersion) // Check Node.js version before any command
66
- .middleware(suppressConsoleWarnings) // Suppress known console warnings
67
- // Dev command
68
- .command(
69
- 'dev',
70
- 'initialize a local preview environment',
71
- (yargs) =>
72
- yargs
73
- .option('port', {
74
- type: 'number',
75
- description: 'port to run the preview server on',
76
- default: 3000,
77
- })
78
- .option('open', {
79
- type: 'boolean',
80
- default: true,
81
- description: 'open a local preview in the browser',
82
- })
83
- .option('local-schema', {
84
- type: 'boolean',
85
- default: false,
86
- hidden: true,
87
- description:
88
- 'use a locally hosted schema file (note: only https protocol is supported in production)',
89
- })
90
- .option('client-version', {
91
- type: 'string',
92
- hidden: true,
93
- description: 'the version of the client to use for cli testing',
94
- })
95
- .option('groups', {
96
- type: 'array',
97
- description: 'Mock user groups for local development and testing',
98
- example: '--groups admin user',
99
- })
100
- .option('disable-openapi', {
101
- type: 'boolean',
102
- default: false,
103
- description: 'Disable OpenAPI file generation',
104
- }),
105
- async (argv) => {
106
- try {
107
- await devCommand.run(argv as DevOptions);
108
- } catch (error) {
109
- this.logger.error(error instanceof Error ? error.message : 'Unknown error');
110
- process.exit(1);
111
- }
112
- }
113
- )
114
- // Init/New command
115
- .command(
116
- ['new [directory]', 'init [directory]'],
117
- 'Create a new Poetora documentation site',
118
- (yargs) =>
119
- yargs.positional('directory', {
120
- describe: 'The directory to initialize your documentation',
121
- type: 'string',
122
- default: '.',
123
- }),
124
- async (argv) => {
125
- try {
126
- await initCommand.run({ directory: argv.directory as string });
127
- } catch (error) {
128
- this.logger.error(error instanceof Error ? error.message : 'Unknown error');
129
- process.exit(1);
130
- }
131
- }
132
- )
133
- // OpenAPI check command
134
- .command(
135
- 'openapi-check <filename>',
136
- 'check if an OpenAPI spec is valid',
137
- (yargs) =>
138
- yargs
139
- .positional('filename', {
140
- describe:
141
- 'the filename of the OpenAPI spec (e.g. ./openapi.yaml) or the URL to the OpenAPI spec',
142
- type: 'string',
143
- demandOption: true,
144
- })
145
- .option('local-schema', {
146
- type: 'boolean',
147
- default: false,
148
- description:
149
- 'use a locally hosted schema file (note: only https protocol is supported in production)',
150
- }),
151
- async (argv) => {
152
- try {
153
- await checkCommand.checkOpenApi({
154
- filename: argv.filename as string,
155
- localSchema: argv.localSchema,
156
- } as OpenApiCheckOptions);
157
- process.exit(0);
158
- } catch (error) {
159
- this.logger.error(error instanceof Error ? error.message : 'Unknown error');
160
- process.exit(1);
161
- }
162
- }
163
- )
164
- // Accessibility check command
165
- .command(
166
- ['a11y', 'accessibility-check', 'a11y-check', 'accessibility'],
167
- 'check for accessibility issues in documentation',
168
- () => undefined,
169
- async () => {
170
- try {
171
- const exitCode = await checkCommand.checkAccessibility();
172
- process.exit(exitCode);
173
- } catch (error) {
174
- this.logger.error(error instanceof Error ? error.message : 'Unknown error');
175
- process.exit(1);
176
- }
177
- }
178
- )
179
- // Broken links command
180
- .command(
181
- 'broken-links',
182
- 'check for invalid internal links',
183
- () => undefined,
184
- async () => {
185
- try {
186
- const brokenLinks = await linkCommand.checkBrokenLinks();
187
- const hasBrokenLinks = Object.keys(brokenLinks).length > 0;
188
- process.exit(hasBrokenLinks ? 1 : 0);
189
- } catch (error) {
190
- this.logger.error(error instanceof Error ? error.message : 'Unknown error');
191
- process.exit(1);
192
- }
193
- }
194
- )
195
- // Rename command
196
- .command(
197
- 'rename <from> <to>',
198
- 'rename a file and update all internal link references',
199
- (yargs) =>
200
- yargs
201
- .positional('from', {
202
- describe: 'the file to rename',
203
- type: 'string',
204
- })
205
- .positional('to', {
206
- describe: 'the new name for the file',
207
- type: 'string',
208
- })
209
- .demandOption(['from', 'to'])
210
- .option('force', {
211
- type: 'boolean',
212
- default: false,
213
- description: 'rename files and skip errors',
214
- })
215
- .epilog(`example: \`${this.packageName} rename introduction.mdx overview.mdx\``),
216
- async (argv) => {
217
- try {
218
- await linkCommand.renameFile({
219
- from: argv.from as string,
220
- to: argv.to as string,
221
- force: argv.force,
222
- } as RenameOptions);
223
- process.exit(0);
224
- } catch (error) {
225
- this.logger.error(error instanceof Error ? error.message : 'Unknown error');
226
- process.exit(1);
227
- }
228
- }
229
- )
230
- // Update command
231
- .command(
232
- 'update',
233
- 'update the CLI to the latest version',
234
- () => undefined,
235
- async () => {
236
- try {
237
- await updateCommand.run({});
238
- process.exit(0);
239
- } catch (error) {
240
- this.logger.error(error instanceof Error ? error.message : 'Unknown error');
241
- process.exit(1);
242
- }
243
- }
244
- )
245
- // Version command
246
- .command(
247
- ['version', 'v'],
248
- 'display the current version of the CLI and client',
249
- () => undefined,
250
- async () => {
251
- const versions = versionService.getVersions();
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}`);
255
- process.exit(0);
256
- }
257
- )
258
- // Error handling
259
- .strictCommands()
260
- .demandCommand(1, 'unknown command. see above for the list of supported commands.')
261
-
262
- // Alias option flags --help = -h, default --version = -v
263
- .alias('h', 'help')
264
- .alias('v', 'version')
265
- );
266
- }
267
-
268
- /**
269
- * Parse and execute CLI
270
- */
271
- async run(): Promise<void> {
272
- await this.build().parseAsync();
273
- }
274
- }
package/src/cli.ts DELETED
@@ -1,22 +0,0 @@
1
- #!/usr/bin/env node
2
- import { Logs } from '@poetora/previewing';
3
- import { render } from 'ink';
4
- import React from 'react';
5
-
6
- import { CliBuilder } from './cli-builder.js';
7
-
8
- export interface CliOptions {
9
- packageName: string;
10
- }
11
-
12
- export const cli = (options: CliOptions): void => {
13
- // Initialize ink rendering for logs
14
- render(React.createElement(Logs));
15
-
16
- const builder = new CliBuilder(options.packageName);
17
-
18
- builder.run().catch((error) => {
19
- console.error('Fatal error:', error);
20
- process.exit(1);
21
- });
22
- };