Skip to content

Commit

Permalink
feat: add project preview command (#1367)
Browse files Browse the repository at this point in the history
* feat: add project previiew command

* chore: use stdout instead of console.log

* Update packages/cli/src/commands/preview-project/index.ts

Co-authored-by: Andrew Tatomyr <[email protected]>

* fix: apply port argument

* chore: command defaults, naming, and descriptions adjustments

---------

Co-authored-by: Andrew Tatomyr <[email protected]>
  • Loading branch information
volodymyr-rutskyi and tatomyr authored Jan 16, 2024
1 parent ac878d4 commit 8e29966
Show file tree
Hide file tree
Showing 5 changed files with 131 additions and 1 deletion.
23 changes: 23 additions & 0 deletions packages/cli/src/commands/preview-project/constants.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import { Product } from './types';

export const PRODUCT_PACKAGES = {
realm: '@redocly/realm',
'redoc-revel': '@redocly/redoc-revel',
'revel-reef': '@redocly/revel-reef',
'redoc-reef': '@redocly/redoc-reef',
redoc: '@redocly/redoc',
revel: '@redocly/revel',
reef: '@redocly/reef',
};

export const PRODUCT_NAMES: { [key in Product]: string } = {
redoc: 'Redoc',
revel: 'Revel',
reef: 'Reef',
realm: 'Realm',
'redoc-revel': 'Redoc + Revel',
'redoc-reef': 'Redoc + Reef',
'revel-reef': 'Revel + Reef',
};

export const PRODUCT_PLANS = ['pro', 'enterprise'] as const;
58 changes: 58 additions & 0 deletions packages/cli/src/commands/preview-project/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
import path = require('path');
import { existsSync, readFileSync } from 'fs';
import { spawn } from 'child_process';
import { PRODUCT_NAMES, PRODUCT_PACKAGES } from './constants';

import type { PreviewProjectOptions, Product } from './types';

export const previewProject = async (args: PreviewProjectOptions) => {
const { plan, port } = args;
const projectDir = args['source-dir'];

const product = args.product || tryGetProductFromPackageJson(projectDir);

if (!isValidProduct(product)) {
process.stderr.write(`Invalid product ${product}`);
throw new Error(`Project preview launch failed`);
}

const productName = PRODUCT_NAMES[product];
const packageName = PRODUCT_PACKAGES[product];

process.stdout.write(`\nLaunching preview of ${productName} ${plan} using NPX\n\n`);

spawn('npx', ['-y', packageName, 'develop', `--plan=${plan}`, `--port=${port || 4000}`], {
stdio: 'inherit',
cwd: projectDir,
});
};

const isValidProduct = (product: string | undefined): product is Product => {
if (!product) {
return false;
}

return !!PRODUCT_NAMES[product as Product];
};

const tryGetProductFromPackageJson = (projectDir: string): Product => {
const packageJsonPath = path.join(process.cwd(), projectDir, 'package.json');

if (existsSync(packageJsonPath)) {
try {
const packageJson = JSON.parse(readFileSync(packageJsonPath, 'utf-8'));
const packageJsonDeps = packageJson.dependencies || {};

for (const [product, packageName] of Object.entries(PRODUCT_PACKAGES)) {
if (packageJsonDeps[packageName]) {
process.stdout.write(`\n${packageName} detected in project's 'package.json'`);
return product as Product;
}
}
} catch (error) {
process.stdout.write(`Invalid 'package.json': ${packageJsonPath}. Using Realm.`);
}
}

return 'realm';
};
12 changes: 12 additions & 0 deletions packages/cli/src/commands/preview-project/types.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import { PRODUCT_PACKAGES, PRODUCT_PLANS } from './constants';

export type Product = keyof typeof PRODUCT_PACKAGES;
export type ProductPlan = typeof PRODUCT_PLANS[number];

export type PreviewProjectOptions = {
product?: Product | string;
plan: ProductPlan | string;
port?: number;
'source-dir': string;
config: string | undefined;
};
34 changes: 34 additions & 0 deletions packages/cli/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ import { version } from './update-version-notifier';
import type { Arguments } from 'yargs';
import type { OutputFormat, RuleSeverity } from '@redocly/openapi-core';
import type { BuildDocsArgv } from './commands/build-docs/types';
import { previewProject } from './commands/preview-project';
import { PRODUCT_PLANS } from './commands/preview-project/constants';

if (!('replaceAll' in String.prototype)) {
require('core-js/actual/string/replace-all');
Expand Down Expand Up @@ -417,6 +419,38 @@ yargs
})(argv);
}
)
.command(
'preview',
'Preview Redocly project using one of the product NPM packages.',
(yargs) =>
yargs.options({
product: {
type: 'string',
choices: ['redoc', 'revel', 'reef', 'realm', 'redoc-revel', 'redoc-reef', 'revel-reef'],
description:
"Product used to launch preview. Default is inferred from project's package.json or 'realm' is used.",
},
plan: {
type: 'string',
choices: PRODUCT_PLANS,
default: 'enterprise',
},
port: {
type: 'number',
description: 'Preview port.',
default: 4000,
},
'source-dir': {
alias: 'd',
type: 'string',
description: 'Project directory.',
default: '.',
},
}),
(argv) => {
commandWrapper(previewProject)(argv);
}
)
.command(
'preview-docs [api]',
'Preview API reference docs for an API description.',
Expand Down
5 changes: 4 additions & 1 deletion packages/cli/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import type { StatsOptions } from './commands/stats';
import type { SplitOptions } from './commands/split';
import type { PreviewDocsOptions } from './commands/preview-docs';
import type { BuildDocsArgv } from './commands/build-docs/types';
import type { PreviewProjectOptions } from './commands/preview-project/types';

export type Totals = {
errors: number;
Expand All @@ -30,7 +31,9 @@ export type CommandOptions =
| BundleOptions
| LoginOptions
| PreviewDocsOptions
| BuildDocsArgv;
| BuildDocsArgv
| PreviewProjectOptions;

export type Skips = {
'skip-rule'?: string[];
'skip-decorator'?: string[];
Expand Down

1 comment on commit 8e29966

@github-actions
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Coverage report

St.
Category Percentage Covered / Total
🟡 Statements 75.8% 4100/5409
🟡 Branches 66.09% 2183/3303
🟡 Functions 68.14% 663/973
🟡 Lines 76% 3847/5062

Test suite run success

671 tests passing in 94 suites.

Report generated by 🧪jest coverage report action from 8e29966

Please sign in to comment.