Skip to content
Merged
3 changes: 2 additions & 1 deletion packages/contentstack-auth/.mocharc.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@
"require": [
"test/helpers/init.js",
"ts-node/register",
"source-map-support/register"
"source-map-support/register",
"test/helpers/mocha-root-hooks.js"
],
"watch-extensions": [
"ts"
Expand Down
11 changes: 11 additions & 0 deletions packages/contentstack-auth/test/helpers/mocha-root-hooks.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
/**
* @contentstack/cli-utilities uses lazy-loaded Chalk 5; preload before tests that hit cliux.
*/
const { loadChalk } = require('@contentstack/cli-utilities');

exports.mochaHooks = {
beforeAll() {
this.timeout(30_000);
return loadChalk();
},
};
3 changes: 2 additions & 1 deletion packages/contentstack-config/.mocharc.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
{
"require": [
"ts-node/register",
"source-map-support/register"
"source-map-support/register",
"test/helpers/mocha-root-hooks.js"
],
"watch-extensions": [
"ts"
Expand Down
11 changes: 11 additions & 0 deletions packages/contentstack-config/test/helpers/mocha-root-hooks.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
/**
* @contentstack/cli-utilities uses lazy-loaded Chalk 5; preload before tests that hit cliux.success etc.
*/
const { loadChalk } = require('@contentstack/cli-utilities');

exports.mochaHooks = {
beforeAll() {
this.timeout(30_000);
return loadChalk();
},
};
3 changes: 2 additions & 1 deletion packages/contentstack-utilities/.mocharc.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@
"require": [
"test/helpers/init.js",
"ts-node/register",
"source-map-support/register"
"source-map-support/register",
"test/helpers/mocha-root-hooks.js"
],
"watch-extensions": [
"ts"
Expand Down
2 changes: 1 addition & 1 deletion packages/contentstack-utilities/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@
"@contentstack/marketplace-sdk": "^1.5.0",
"@oclif/core": "^4.3.0",
"axios": "^1.13.5",
"chalk": "^4.1.2",
"chalk": "^5.6.2",
"cli-cursor": "^3.1.0",
"cli-progress": "^3.12.0",
"cli-table": "^0.3.11",
Expand Down
27 changes: 27 additions & 0 deletions packages/contentstack-utilities/src/chalk.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
/**
* Chalk 5 is ESM-only. We load it via dynamic import and cache for use in CommonJS.
*/
let chalkInstance: typeof import('chalk').default | null = null;

export type ChalkInstance = typeof import('chalk').default;

/**
* Load chalk (ESM) and cache it. Call this once during CLI init before any chalk usage.
*/
export async function loadChalk(): Promise<ChalkInstance> {
if (!chalkInstance) {
const chalkModule = await import('chalk');
chalkInstance = chalkModule.default;
}
return chalkInstance;
}

/**
* Get the cached chalk instance. Must call loadChalk() first (e.g. in init hook).
*/
export function getChalk(): ChalkInstance {
if (!chalkInstance) {
throw new Error('Chalk not loaded. Ensure loadChalk() is called during init (e.g. in utils-init hook).');
}
return chalkInstance;
}
13 changes: 7 additions & 6 deletions packages/contentstack-utilities/src/cli-ux.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import chalk, { Chalk } from 'chalk';
import { getChalk, ChalkInstance } from './chalk';
import inquirer from 'inquirer';
import { ux as cliux, Args, Flags, Command } from '@oclif/core';
import { Ora, default as ora } from 'ora';
Expand Down Expand Up @@ -29,10 +29,11 @@ class CLIInterface {

print(message: string, opts?: PrintOptions): void {
if (opts) {
let chalkFn: Chalk = chalk;
const chalk = getChalk();
let chalkFn: ChalkInstance = chalk;

if (opts.color) chalkFn = chalkFn[opts.color] as Chalk;
if (opts.bold) chalkFn = chalkFn.bold as Chalk;
if (opts.color) chalkFn = chalkFn[opts.color] as ChalkInstance;
if (opts.bold) chalkFn = chalkFn.bold as ChalkInstance;

cliux.stdout(chalkFn(messageHandler.parse(message)));
return;
Expand All @@ -42,11 +43,11 @@ class CLIInterface {
}

success(message: string): void {
cliux.stdout(chalk.green(messageHandler.parse(message)));
cliux.stdout(getChalk().green(messageHandler.parse(message)));
}

error(message: string, ...params: any): void {
cliux.stdout(chalk.red(messageHandler.parse(message) + (params && params.length > 0 ? ': ' : '')), ...params);
cliux.stdout(getChalk().red(messageHandler.parse(message) + (params && params.length > 0 ? ': ' : '')), ...params);
}

loader(message: string = ''): void {
Expand Down
8 changes: 4 additions & 4 deletions packages/contentstack-utilities/src/config-handler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import Conf from 'conf';
import has from 'lodash/has';
import { v4 as uuid } from 'uuid';
import { existsSync, unlinkSync, readFileSync } from 'fs';
import chalk from 'chalk';
import { getChalk } from './chalk';
import { cliux } from '.';

const ENC_KEY = process.env.ENC_KEY || 'encryptionKey';
Expand Down Expand Up @@ -85,7 +85,7 @@ class Config {

safeDeleteConfigIfInvalid(configFilePath: string) {
if (existsSync(configFilePath) && !this.isConfigFileValid(configFilePath)) {
console.warn(chalk.yellow(`Warning: Detected corrupted config at ${configFilePath}. Removing...`));
console.warn(getChalk().yellow(`Warning: Detected corrupted config at ${configFilePath}. Removing...`));
unlinkSync(configFilePath);
}
}
Expand Down Expand Up @@ -152,7 +152,7 @@ class Config {
const oldConfigData = this.getConfigDataAndUnlinkConfigFile(config);
this.getEncryptedConfig(oldConfigData, true);
} catch (_error) {
cliux.print(chalk.red('Error: Config file is corrupted'));
cliux.print(getChalk().red('Error: Config file is corrupted'));
cliux.print(_error);
process.exit(1);
}
Expand Down Expand Up @@ -203,7 +203,7 @@ class Config {
this.getDecryptedConfig(_configData); // NOTE reinitialize the config with old data and new decrypted file
} catch (__error) {
// console.trace(error.message)
cliux.print(chalk.red('Error: Config file is corrupted'));
cliux.print(getChalk().red('Error: Config file is corrupted'));
cliux.print(_error);
process.exit(1);
}
Expand Down
18 changes: 11 additions & 7 deletions packages/contentstack-utilities/src/content-type-utils.ts
Original file line number Diff line number Diff line change
@@ -1,21 +1,24 @@
import { existsSync, readdirSync, readFileSync } from 'node:fs';
import { resolve as pResolve } from 'node:path';
import { FsUtility } from './fs-utility';

/**
* Reads all content type schema files from a directory
* @param dirPath - Path to content types directory
* @param ignoredFiles - Files to ignore (defaults to schema.json, .DS_Store, __master.json, __priority.json)
* @returns Array of content type schemas
* @returns Array of content type schemas (empty if the path is missing or has no eligible files)
*/
export function readContentTypeSchemas(
dirPath: string,
ignoredFiles: string[] = ['schema.json', '.DS_Store', '__master.json', '__priority.json', 'field_rules_uid.json'],
): Record<string, unknown>[] | null {
const fsUtil = new FsUtility();
const files = fsUtil.readdir(dirPath);
): Record<string, unknown>[] {
if (!existsSync(dirPath)) {
return [];
}

const files = readdirSync(dirPath);

if (!files || files.length === 0) {
return null;
return [];
}

const contentTypes: Record<string, unknown>[] = [];
Expand All @@ -33,7 +36,8 @@ export function readContentTypeSchemas(

try {
const filePath = pResolve(dirPath, file);
const contentType = fsUtil.readFile(filePath);
const raw = readFileSync(filePath, 'utf8');
const contentType = JSON.parse(raw) as Record<string, unknown>;
if (contentType) {
contentTypes.push(contentType as Record<string, unknown>);
}
Expand Down
2 changes: 2 additions & 0 deletions packages/contentstack-utilities/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,8 @@ export {
export { FlagInput, ArgInput, FlagDefinition } from '@oclif/core/lib/interfaces/parser';

export { default as TablePrompt } from './inquirer-table-prompt';
export { loadChalk, getChalk } from './chalk';
export type { ChalkInstance } from './chalk';

export { Logger };
export { default as authenticationHandler } from './authentication-handler';
Expand Down
16 changes: 8 additions & 8 deletions packages/contentstack-utilities/src/inquirer-table-prompt.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
*/

import * as readline from 'readline';
import chalk from 'chalk';
import { getChalk } from './chalk';
import figures from 'figures';
import cliCursor from 'cli-cursor';
import Table from 'cli-table';
Expand Down Expand Up @@ -182,13 +182,13 @@ class TablePrompt {
if (!this.spaceKeyPressed) {
msg +=
' (Press ' +
chalk.cyan.bold('<space>') +
getChalk().cyan.bold('<space>') +
' to select, ' +
chalk.cyan.bold('<Up/Down>') +
getChalk().cyan.bold('<Up/Down>') +
' rows, ' +
chalk.cyan.bold('<Left/Right>') +
getChalk().cyan.bold('<Left/Right>') +
' columns, ' +
chalk.cyan.bold('<Enter>') +
getChalk().cyan.bold('<Enter>') +
' to confirm)';
}
return msg;
Expand All @@ -197,8 +197,8 @@ class TablePrompt {
private render(): void {
const [firstIndex, lastIndex] = this.paginate();
const table = new Table({
head: [chalk.reset.dim(`${firstIndex + 1}-${lastIndex + 1} of ${this.rows.length}`)].concat(
this.columns.map((c) => chalk.reset.bold(pluckName(c))),
head: [getChalk().reset.dim(`${firstIndex + 1}-${lastIndex + 1} of ${this.rows.length}`)].concat(
this.columns.map((c) => getChalk().reset.bold(pluckName(c))),
),
});

Expand All @@ -214,7 +214,7 @@ class TablePrompt {
columnValues.push(`${isSelected ? '[' : ' '} ${cellValue} ${isSelected ? ']' : ' '}`);
}
const chalkModifier =
this.status !== 'answered' && this.pointer === rowIndex ? chalk.reset.bold.cyan : chalk.reset;
this.status !== 'answered' && this.pointer === rowIndex ? getChalk().reset.bold.cyan : getChalk().reset;
table.push({ [chalkModifier(pluckName(row))]: columnValues });
}

Expand Down
Loading
Loading