diff --git a/package-lock.json b/package-lock.json index 6e6f60ddfe..1e105ee247 100644 --- a/package-lock.json +++ b/package-lock.json @@ -2535,6 +2535,10 @@ "@coveo/headless": "^2.0.0" } }, + "node_modules/@coveo/atomic-component-health-check": { + "resolved": "packages/ui/atomic/health-check", + "link": true + }, "node_modules/@coveo/atomic/node_modules/@stencil/core": { "version": "2.17.3", "resolved": "https://registry.npmjs.org/@stencil/core/-/core-2.17.3.tgz", @@ -30534,9 +30538,9 @@ } }, "node_modules/zod": { - "version": "3.20.6", - "resolved": "https://registry.npmjs.org/zod/-/zod-3.20.6.tgz", - "integrity": "sha512-oyu0m54SGCtzh6EClBVqDDlAYRz4jrVtKwQ7ZnsEmMI9HnzuZFj8QFwAY1M5uniIYACdGvv0PBWPF2kO0aNofA==", + "version": "3.21.4", + "resolved": "https://registry.npmjs.org/zod/-/zod-3.21.4.tgz", + "integrity": "sha512-m46AKbrzKVzOzs/DZgVnG5H55N1sv1M8qZU3A8RIKbs3mrACDNeIOeilDymVb2HdmP8uwshOCF4uJ8uM9rCqJw==", "funding": { "url": "https://github.com/sponsors/colinhacks" } @@ -31361,6 +31365,37 @@ "url": "https://github.com/chalk/wrap-ansi?sponsor=1" } }, + "packages/ui/atomic/health-check": { + "name": "@coveo/atomic-component-health-check", + "version": "0.0.1", + "license": "Apache-2.0", + "dependencies": { + "chalk": "4.1.2", + "zod": "^3.21.4" + }, + "bin": { + "atomic-meta-check": "dist/index.js" + }, + "devDependencies": { + "@coveo/verdaccio-starter": "^1.0.0", + "@types/jest": "^29.5.0", + "@types/node": "^18.14.6", + "jest": "^29.5.0", + "stdout-stderr": "^0.1.13", + "ts-jest": "^29.0.5", + "typescript": "^4.9.5" + } + }, + "packages/ui/atomic/health-check/node_modules/@types/jest": { + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/@types/jest/-/jest-29.5.0.tgz", + "integrity": "sha512-3Emr5VOl/aoBwnWcH/EFQvlSAmjV+XtV9GGu5mwdYew5vhQh0IUZx/60x0TzHDu09Bi7HMx10t/namdJw5QIcg==", + "dev": true, + "dependencies": { + "expect": "^29.0.0", + "pretty-format": "^29.0.0" + } + }, "packages/ui/atomic/template": { "name": "@coveo/create-atomic-template", "version": "1.37.1", diff --git a/packages/ui/atomic/health-check/.gitignore b/packages/ui/atomic/health-check/.gitignore new file mode 100644 index 0000000000..ed9f9cc128 --- /dev/null +++ b/packages/ui/atomic/health-check/.gitignore @@ -0,0 +1 @@ +coverage \ No newline at end of file diff --git a/packages/ui/atomic/health-check/__stub__/invalidProperties.json b/packages/ui/atomic/health-check/__stub__/invalidProperties.json new file mode 100644 index 0000000000..a62e2c9832 --- /dev/null +++ b/packages/ui/atomic/health-check/__stub__/invalidProperties.json @@ -0,0 +1,13 @@ +{ + "name": "invalid-properties", + "version": "1.0.0", + "main": "index.js", + "author": "", + "description": "Short description", + "unpkg": "path/to/file", + "keywords": ["foo", "bar"], + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1" + }, + "homepage": "https://github.com/coveo/cli" +} diff --git a/packages/ui/atomic/health-check/__stub__/missingProperties.json b/packages/ui/atomic/health-check/__stub__/missingProperties.json new file mode 100644 index 0000000000..348ad93854 --- /dev/null +++ b/packages/ui/atomic/health-check/__stub__/missingProperties.json @@ -0,0 +1,9 @@ +{ + "name": "missing-properties", + "version": "1.0.0", + "main": "index.js", + "author": "", + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1" + } +} diff --git a/packages/ui/atomic/health-check/__stub__/readme.md b/packages/ui/atomic/health-check/__stub__/readme.md new file mode 100644 index 0000000000..e69de29bb2 diff --git a/packages/ui/atomic/health-check/__stub__/validPackage.json b/packages/ui/atomic/health-check/__stub__/validPackage.json new file mode 100644 index 0000000000..97440d87e6 --- /dev/null +++ b/packages/ui/atomic/health-check/__stub__/validPackage.json @@ -0,0 +1,13 @@ +{ + "name": "valid-package", + "version": "1.0.0", + "main": "index.js", + "author": "", + "description": "Nulla fermentum ipsum vel quam euismod, id pulvinar magna aliquet. Aliquam in sapien sit amet est feugiat ultrices. Cras vulputate leo ut mattis interdum.", + "unpkg": "path/to/file", + "homepage": "https://github.com/foo/bar#readme", + "keywords": ["foo", "bar", "coveo-atomic-component"], + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1" + } +} diff --git a/packages/ui/atomic/health-check/jest.config.js b/packages/ui/atomic/health-check/jest.config.js new file mode 100644 index 0000000000..56f93c2916 --- /dev/null +++ b/packages/ui/atomic/health-check/jest.config.js @@ -0,0 +1,14 @@ +export default { + preset: 'ts-jest/presets/default-esm', + extensionsToTreatAsEsm: ['.ts'], + moduleNameMapper: { + '^(\\.{1,2}/.*)\\.js$': '$1', + }, + testEnvironment: 'node', + verbose: true, + collectCoverage: true, + clearMocks: true, + silent: true, + testTimeout: 60e3, + testPathIgnorePatterns: ['/node_modules/', '/dist/'], +}; diff --git a/packages/ui/atomic/health-check/package.json b/packages/ui/atomic/health-check/package.json new file mode 100644 index 0000000000..70431f52df --- /dev/null +++ b/packages/ui/atomic/health-check/package.json @@ -0,0 +1,45 @@ +{ + "name": "@coveo/atomic-component-health-check", + "type": "module", + "version": "0.0.1", + "description": "A Health checker for custom Atomic component", + "main": "./dist/index.js", + "author": "Coveo", + "homepage": "https://github.com/coveo/cli#readme", + "bin": { + "atomic-meta-check": "./dist/index.js" + }, + "publishConfig": { + "access": "public" + }, + "license": "Apache-2.0", + "scripts": { + "release:phase1": "npx -p=@coveord/release npm-publish", + "build": "rimraf dist && tsc -b tsconfig.json", + "test": "jest" + }, + "repository": { + "type": "git", + "url": "git+https://github.com/coveo/cli.git" + }, + "bugs": { + "url": "https://github.com/coveo/cli/issues" + }, + "files": [ + "dist" + ], + "keywords": [], + "dependencies": { + "chalk": "4.1.2", + "zod": "^3.21.4" + }, + "devDependencies": { + "@coveo/verdaccio-starter": "^1.0.0", + "@types/jest": "^29.5.0", + "@types/node": "^18.14.6", + "jest": "^29.5.0", + "stdout-stderr": "^0.1.13", + "ts-jest": "^29.0.5", + "typescript": "^4.9.5" + } +} diff --git a/packages/ui/atomic/health-check/project.json b/packages/ui/atomic/health-check/project.json new file mode 100644 index 0000000000..9dce617adf --- /dev/null +++ b/packages/ui/atomic/health-check/project.json @@ -0,0 +1,6 @@ +{ + "name": "atomic-component-health-check", + "root": "packages/ui/atomic/health-check", + "sourceRoot": "packages/ui/atomic/health-check/src", + "projectType": "application" +} diff --git a/packages/ui/atomic/health-check/readme.md b/packages/ui/atomic/health-check/readme.md new file mode 100644 index 0000000000..b6d40f5b13 --- /dev/null +++ b/packages/ui/atomic/health-check/readme.md @@ -0,0 +1,5 @@ + + +## Testing + +Before running the tests, make sure to build the project with `npm run build` diff --git a/packages/ui/atomic/health-check/src/__snapshots__/index.spec.ts.snap b/packages/ui/atomic/health-check/src/__snapshots__/index.spec.ts.snap new file mode 100644 index 0000000000..bae93089f0 --- /dev/null +++ b/packages/ui/atomic/health-check/src/__snapshots__/index.spec.ts.snap @@ -0,0 +1,46 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`@coveo/atomic-component-health-check when all conditions are met should print green checks only 1`] = ` +"✔ Readme file + +✔ Required properties in package.json + +" +`; + +exports[`@coveo/atomic-component-health-check when package.json conditions are not met should warn about invalid properties 1`] = ` +"✔ Readme file + +✖ Required properties in package.json + ✖ Invalid keywords: The package.json \`keywords\` array should include \`coveo-atomic-component\`, otherwise your component will not be listed along with other Coveo custom components. See https://docs.npmjs.com/cli/v9/configuring-npm/package-json#keywords + ✖ Invalid description: The component description must be at least 20 characters long + +Publish aborted because some conditions have not been met +Make sure to address the above errors before publishing again +" +`; + +exports[`@coveo/atomic-component-health-check when package.json conditions are not met should warn about missing properties 1`] = ` +"✔ Readme file + +✖ Required properties in package.json + ✖ Invalid unpkg: You must provide the path to the \`.esm.js\` file of your custom component. You can find it under the \`dist/\` folder once you build the component. + ✖ Invalid keywords: You must populate the \`keywords\` property. See https://docs.npmjs.com/cli/v9/configuring-npm/package-json#keywords + ✖ Invalid description: You must provide a description at least 20 characters long to explain the component purpose. + ✖ Invalid homepage: You must provide a URL to the component source code. See https://docs.npmjs.com/cli/v9/configuring-npm/package-json#homepage + +Publish aborted because some conditions have not been met +Make sure to address the above errors before publishing again +" +`; + +exports[`@coveo/atomic-component-health-check when readme condition is not met should warn about missing readme file 1`] = ` +"✖ Readme file + Missing README file. Make sure to include a \`README.md\` file in your component directory + +✔ Required properties in package.json + +Publish aborted because some conditions have not been met +Make sure to address the above errors before publishing again +" +`; diff --git a/packages/ui/atomic/health-check/src/__snapshots__/logger.spec.ts.snap b/packages/ui/atomic/health-check/src/__snapshots__/logger.spec.ts.snap new file mode 100644 index 0000000000..08ef955727 --- /dev/null +++ b/packages/ui/atomic/health-check/src/__snapshots__/logger.spec.ts.snap @@ -0,0 +1,22 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`Logger #failure should print an error message 1`] = ` +"✖ Better luck next time +" +`; + +exports[`Logger #log should print multiple lines to stdout 1`] = ` +"Maecenas purus lacus +Donec ut sem cursus +" +`; + +exports[`Logger #newLine should print a new line 1`] = ` +" +" +`; + +exports[`Logger #success should print a successful message 1`] = ` +"✔ You win! +" +`; diff --git a/packages/ui/atomic/health-check/src/assertions.spec.ts b/packages/ui/atomic/health-check/src/assertions.spec.ts new file mode 100644 index 0000000000..69f53a45a2 --- /dev/null +++ b/packages/ui/atomic/health-check/src/assertions.spec.ts @@ -0,0 +1,36 @@ +jest.mock('node:fs'); +jest.mock('./schema.js'); + +import {ensureReadme, ensureRequiredProperties} from './assertions.js'; +import {existsSync, readFileSync} from 'node:fs'; +import schema from './schema.js'; + +const mockedExistsSync = jest.mocked(existsSync); +const mockedReadFileSync = jest.mocked(readFileSync); +const mockedSchemaParse = jest.fn(); + +describe('assertions', () => { + beforeEach(() => { + jest.mocked(schema).parse.mockImplementation(mockedSchemaParse); + }); + + afterEach(() => { + jest.resetAllMocks(); + }); + + it('#ensureRequiredProperties should parse package.json', () => { + mockedReadFileSync.mockReturnValue('{}'); + ensureRequiredProperties(); + expect(mockedSchemaParse).toBeCalled(); + }); + + it('#ensureReadme should throw if readme file is missing', () => { + mockedExistsSync.mockReturnValue(false); + expect(() => ensureReadme()).toThrow(); + }); + + it('#ensureReadme should not throw if readme file is not missing', () => { + mockedExistsSync.mockReturnValue(true); + expect(() => ensureReadme()).not.toThrow(); + }); +}); diff --git a/packages/ui/atomic/health-check/src/assertions.ts b/packages/ui/atomic/health-check/src/assertions.ts new file mode 100644 index 0000000000..4297509094 --- /dev/null +++ b/packages/ui/atomic/health-check/src/assertions.ts @@ -0,0 +1,23 @@ +import packageJsonSchema from './schema.js'; +import {join} from 'node:path'; +import {readFileSync, existsSync} from 'node:fs'; +import {cwd} from 'process'; + +export function ensureRequiredProperties() { + const jsonPkg = readFileSync(join(cwd(), 'package.json')); + const parsed = JSON.parse(jsonPkg.toString()); + packageJsonSchema.parse(parsed); +} + +export function ensureReadme() { + const exists = existsSync(join(cwd(), 'readme.md')); + if (!exists) { + throw new Error( + 'Missing README file. Make sure to include a `README.md` file in your component directory' + ); + } +} + +export function ensureInternalScope() { + // TODO: CDX-1266: Ensure internal components tags are tagged with the appropriate scope. +} diff --git a/packages/ui/atomic/health-check/src/error.ts b/packages/ui/atomic/health-check/src/error.ts new file mode 100644 index 0000000000..5420474f89 --- /dev/null +++ b/packages/ui/atomic/health-check/src/error.ts @@ -0,0 +1,24 @@ +import chalk from 'chalk'; +import {ZodError} from 'zod'; +import {failure, groupEnd, groupStart, log} from './logger.js'; + +export function prettifyZodError({errors}: ZodError, indent = true) { + if (indent) { + groupStart(); + } + + for (const error of errors) { + const prefix = chalk.bold(`Invalid ${error.path.join('.')}: `); + failure(`${prefix}${error.message}`); + } + + if (indent) { + groupEnd(); + } +} + +export function prettifyError(error: any) { + if ('message' in error) { + log(error.message); + } +} diff --git a/packages/ui/atomic/health-check/src/index.spec.ts b/packages/ui/atomic/health-check/src/index.spec.ts new file mode 100644 index 0000000000..90a8d61dfd --- /dev/null +++ b/packages/ui/atomic/health-check/src/index.spec.ts @@ -0,0 +1,92 @@ +import {spawnSync} from 'node:child_process'; +import {cpSync} from 'fs-extra'; +import {mkdirSync, emptyDir} from 'fs-extra'; +import {join} from 'node:path'; +import {DirResult, dirSync} from 'tmp'; + +const execPath = join(__dirname, '..', 'dist'); + +const pathToStub = join(__dirname, '..', '__stub__'); +const healthCheck = (cwd: string) => spawnSync('node', [execPath], {cwd}); + +const addPackageJsonToProject = (stubFile: string, dest: string) => { + cpSync(join(pathToStub, stubFile), join(dest, 'package.json')); +}; + +const addReadmeToProject = (stubFile: string, dest: string) => { + cpSync(join(pathToStub, stubFile), join(dest, 'readme.md')); +}; + +describe('@coveo/atomic-component-health-check', () => { + let tempDirectory: DirResult; + let testDirectory: string; + + beforeAll(async () => { + tempDirectory = dirSync({unsafeCleanup: true, keep: true}); + testDirectory = join(tempDirectory.name, 'dummy-project'); + mkdirSync(testDirectory, {recursive: true}); + }); + + beforeEach(() => { + emptyDir(testDirectory); + }); + + afterAll(async () => { + tempDirectory.removeCallback(); + }); + + describe('when readme condition is not met', () => { + beforeAll(() => { + addPackageJsonToProject('validPackage.json', testDirectory); + }); + + it('should exit with status code 1', () => { + const {status} = healthCheck(testDirectory); + expect(status).toBe(1); + }); + + it('should warn about missing readme file', () => { + const {stdout} = healthCheck(testDirectory); + expect(stdout.toString()).toMatchSnapshot(); + }); + }); + + describe('when package.json conditions are not met', () => { + beforeEach(() => { + addReadmeToProject('readme.md', testDirectory); + }); + + it('should exit with status code 1', () => { + addPackageJsonToProject('missingProperties.json', testDirectory); + const {status} = healthCheck(testDirectory); + expect(status).toBe(1); + }); + + it.each([ + { + title: 'should warn about missing properties', + stubPackage: 'missingProperties.json', + }, + { + title: 'should warn about invalid properties', + stubPackage: 'invalidProperties.json', + }, + ])('$title', ({stubPackage}) => { + addPackageJsonToProject(stubPackage, testDirectory); + const {stdout} = healthCheck(testDirectory); + expect(stdout.toString()).toMatchSnapshot(); + }); + }); + + describe('when all conditions are met', () => { + beforeEach(() => { + addReadmeToProject('readme.md', testDirectory); + addPackageJsonToProject('validPackage.json', testDirectory); + }); + + it('should print green checks only', () => { + const {stdout} = healthCheck(testDirectory); + expect(stdout.toString()).toMatchSnapshot(); + }); + }); +}); diff --git a/packages/ui/atomic/health-check/src/index.ts b/packages/ui/atomic/health-check/src/index.ts new file mode 100644 index 0000000000..8b14ba2b29 --- /dev/null +++ b/packages/ui/atomic/health-check/src/index.ts @@ -0,0 +1,15 @@ +#!/usr/bin/env node + +import {ensureReadme, ensureRequiredProperties} from './assertions.js'; +import {Inspector} from './inspector.js'; + +try { + new Inspector() + .check(ensureReadme, 'Readme file') + .check(ensureRequiredProperties, 'Required properties in package.json') + // .check(ensureInternalScope, 'Valid scope') //TODO: CDX-1266 + .report(); +} catch (error) { + console.error('Something went wrong during health check:', error); + process.exit(1); +} diff --git a/packages/ui/atomic/health-check/src/inspector.spec.ts b/packages/ui/atomic/health-check/src/inspector.spec.ts new file mode 100644 index 0000000000..1caf3180a4 --- /dev/null +++ b/packages/ui/atomic/health-check/src/inspector.spec.ts @@ -0,0 +1,89 @@ +jest.mock('./logger'); + +import {Inspector, Assertion} from './inspector'; +import {failure, log, success} from './logger'; + +const mockedSuccess = jest.mocked(success); +const mockedFail = jest.mocked(failure); +const mockedLog = jest.mocked(log); +let mockedExit: jest.SpyInstance; + +const doMockProcessExit = () => { + mockedExit = jest.spyOn(process, 'exit').mockImplementation((number) => { + throw new Error('process.exit: ' + number); + }); +}; +const noopAssertion: Assertion = () => {}; +const failedAssertion: Assertion = () => { + throw 'oups!'; +}; + +describe('Inspector', () => { + let inspector: Inspector; + + beforeAll(() => { + doMockProcessExit(); + }); + + beforeEach(() => { + inspector = new Inspector(); + }); + + afterAll(() => { + mockedExit.mockRestore(); + }); + + describe('when some assertions are invalid', () => { + beforeEach(() => { + inspector + .check(noopAssertion, 'First assertion') + .check(failedAssertion, 'Second assertion') + .check(noopAssertion, 'third assertion'); + }); + + it('should log success and fail messages', () => { + expect(mockedFail).toBeCalledTimes(1); + expect(mockedSuccess).toBeCalledTimes(2); + }); + + it('should log a report', () => { + expect(() => { + inspector.report(); + }).toThrow(); + expect(mockedLog).toBeCalled(); + }); + + it('should exit the process', async () => { + expect(() => { + inspector.report(); + }).toThrow('process.exit: 1'); + expect(mockedExit).toBeCalledTimes(1); + }); + }); + + describe('when all assertions are valid', () => { + beforeEach(() => { + inspector + .check(noopAssertion, 'First assertion') + .check(noopAssertion, 'Second assertion') + .check(noopAssertion, 'third assertion') + .report(); + }); + + it('should only log success messages', () => { + expect(mockedSuccess).toBeCalledTimes(3); + }); + + it('should not log fail messages', () => { + expect(mockedFail).not.toBeCalled(); + }); + + it('should not print a report', () => { + expect(mockedLog).not.toBeCalled(); + }); + + it('should not exit the process', async () => { + expect(mockedExit).not.toBeCalled(); + }); + }); +}); diff --git a/packages/ui/atomic/health-check/src/inspector.ts b/packages/ui/atomic/health-check/src/inspector.ts new file mode 100644 index 0000000000..05fa548bdd --- /dev/null +++ b/packages/ui/atomic/health-check/src/inspector.ts @@ -0,0 +1,57 @@ +import {ZodError} from 'zod'; +import {prettifyError, prettifyZodError} from './error.js'; +import chalk from 'chalk'; +import { + failure, + groupEnd, + groupStart, + log, + newLine, + success, +} from './logger.js'; + +export type Assertion = () => void | never; + +export class Inspector { + private hasErrors = false; + + public check(assertion: Assertion, message: string) { + try { + assertion(); + success(chalk.bold(message)); + } catch (error) { + failure(chalk.bold(message)); + this.printError(error); + this.hasErrors = true; + } finally { + newLine(); + } + + return this; + } + + public report() { + if (this.hasErrors) { + log( + 'Publish aborted because some conditions have not been met', + 'Make sure to address the above errors before publishing again' + // TODO: CDX-1356: Add a link to custom component best practices + ); + this.terminate(); + } + } + + private printError(error: any) { + groupStart(); + if (error instanceof ZodError) { + prettifyZodError(error); + } else if (error instanceof Error) { + prettifyError(error); + } + groupEnd(); + } + + private terminate() { + process.exit(1); + } +} diff --git a/packages/ui/atomic/health-check/src/logger.spec.ts b/packages/ui/atomic/health-check/src/logger.spec.ts new file mode 100644 index 0000000000..67880a2cfb --- /dev/null +++ b/packages/ui/atomic/health-check/src/logger.spec.ts @@ -0,0 +1,32 @@ +import {stdout} from 'stdout-stderr'; +import {failure, log, newLine, success} from './logger'; + +describe('Logger', () => { + beforeEach(() => { + stdout.start(); + }); + + afterEach(() => { + stdout.stop(); + }); + + it('#log should print multiple lines to stdout', () => { + log('Maecenas purus lacus', 'Donec ut sem cursus'); + expect(stdout.output).toMatchSnapshot(); + }); + + it('#success should print a successful message', () => { + success('You win!'); + expect(stdout.output).toMatchSnapshot(); + }); + + it('#failure should print an error message', () => { + failure('Better luck next time'); + expect(stdout.output).toMatchSnapshot(); + }); + + it('#newLine should print a new line', () => { + newLine(); + expect(stdout.output).toMatchSnapshot(); + }); +}); diff --git a/packages/ui/atomic/health-check/src/logger.ts b/packages/ui/atomic/health-check/src/logger.ts new file mode 100644 index 0000000000..7c955bfd0c --- /dev/null +++ b/packages/ui/atomic/health-check/src/logger.ts @@ -0,0 +1,27 @@ +import chalk from 'chalk'; + +export function log(...messages: string[]) { + for (const message of messages) { + console.log(message); + } +} + +export function groupStart() { + console.group(); +} + +export function groupEnd() { + console.groupEnd(); +} + +export function newLine() { + console.log(); +} + +export function success(message: string) { + log([chalk.green('✔'), message].join(' ')); +} + +export function failure(message: string) { + log([chalk.red('✖'), message].join(' ')); +} diff --git a/packages/ui/atomic/health-check/src/schema.ts b/packages/ui/atomic/health-check/src/schema.ts new file mode 100644 index 0000000000..e1cf74280b --- /dev/null +++ b/packages/ui/atomic/health-check/src/schema.ts @@ -0,0 +1,38 @@ +import {z} from 'zod'; + +export default z.object({ + name: z.string({ + required_error: 'You must provide a name for your custom component.', + }), + unpkg: z.string({ + required_error: + 'You must provide the path to the `.esm.js` file of your custom component. You can find it under the `dist/` folder once you build the component.', + }), + keywords: z + .string({ + required_error: + 'You must populate the `keywords` property. See https://docs.npmjs.com/cli/v9/configuring-npm/package-json#keywords', + }) + .array() + .refine((keywords) => keywords.includes('coveo-atomic-component'), { + message: + 'The package.json `keywords` array should include `coveo-atomic-component`, otherwise your component will not be listed along with other Coveo custom components. See https://docs.npmjs.com/cli/v9/configuring-npm/package-json#keywords', + }), + description: z + .string({ + required_error: + 'You must provide a description at least 20 characters long to explain the component purpose.', + }) + .min(20, { + message: 'The component description must be at least 20 characters long', + }), + homepage: z + .string({ + required_error: + 'You must provide a URL to the component source code. See https://docs.npmjs.com/cli/v9/configuring-npm/package-json#homepage', + }) + .url({ + message: + 'Please provide a valid url to the component homepage. See https://docs.npmjs.com/cli/v9/configuring-npm/package-json#homepage', + }), +}); diff --git a/packages/ui/atomic/health-check/tsconfig.json b/packages/ui/atomic/health-check/tsconfig.json new file mode 100644 index 0000000000..94bc379b79 --- /dev/null +++ b/packages/ui/atomic/health-check/tsconfig.json @@ -0,0 +1,14 @@ +{ + "extends": "../../../../tsconfig.base.json", + "compilerOptions": { + "skipLibCheck": true, + "outDir": "dist", + "module": "Node16", + "target": "ESNext", + "moduleResolution": "Node16", + "sourceMap": false, + "declaration": false, + "esModuleInterop": true + }, + "exclude": ["node_modules", "src/**/*.spec.ts"] +}