diff --git a/.changeset/lemon-bottles-act.md b/.changeset/lemon-bottles-act.md new file mode 100644 index 0000000..7e2a9e5 --- /dev/null +++ b/.changeset/lemon-bottles-act.md @@ -0,0 +1,5 @@ +--- +'@chialab/plasma': minor +--- + +Do not require a package.json anymore. diff --git a/README.md b/README.md index 6187d16..216f985 100644 --- a/README.md +++ b/README.md @@ -18,10 +18,7 @@ Generate Custom Elements wrappers for Angular, React, Svelte and Vue. Plasma transformations are based on [Custom Element Manifest](https://github.com/webcomponents/custom-elements-manifest) (CEM) specifications. The CEM is a JSON files that describes a Custom Element, its properties, events and slots. Plasma uses the CEM to generate wrappers for the supported frameworks. -In order to run the `plasma` cli you need: - -- a `package.json` file. Plasma uses the `name` field to import the Custom Element definition and the `customElements` field to detect the CEM file; -- a CEM file. You can generate the CEM for most of the Web Components library using this [Analyzer](https://github.com/open-wc/custom-elements-manifest/tree/master/packages/analyzer). +You can generate the CEM for most of the Web Components library using this [Analyzer](https://github.com/open-wc/custom-elements-manifest/tree/master/packages/analyzer). ## Installation @@ -40,19 +37,18 @@ npm run plasma ### Options ``` -npm run plasma --help - Usage: plasma [options] Generate Custom Elements wrappers for Angular, React, Svelte and Vue. Arguments: - input source directory + input custom elements manifest path Options: -V, --version output the version number - -f, --frameworks the framework to convert to + -e, --entrypoint entrypoint to the package -o, --outdir output directory + -f, --frameworks the framework to convert to -y, --yes convert all candidates to all available frameworks -h, --help display help for command ``` diff --git a/package.json b/package.json index c115c3d..082bf0a 100644 --- a/package.json +++ b/package.json @@ -40,7 +40,7 @@ "build": "yarn clear && tsc --project tsconfig.build.json && node scripts/build.js", "lint": "prettier --check . && eslint .", "test:manifest": "custom-elements-manifest analyze --config ./test/cem.config.mjs --outdir test", - "test:generate": "./dist/cli.js test --outdir 'test/src/[framework]' -y", + "test:generate": "./dist/cli.js test --entrypoint 'plasma-test' --outdir 'test/src/[framework]' -y", "test": "vitest", "prepack": "yarn build && publint" }, @@ -65,7 +65,6 @@ "eslint": "^8.0.0", "jsdom": "^23.0.0", "listr2": "^7.0.2", - "package-up": "^5.0.0", "preact": "^10.19.2", "prettier": "^3.0.0", "prompts": "^2.4.0", diff --git a/src/cli.ts b/src/cli.ts index cc18155..145fb52 100644 --- a/src/cli.ts +++ b/src/cli.ts @@ -5,10 +5,9 @@ import { fileURLToPath } from 'node:url'; import chalk from 'chalk'; import { program } from 'commander'; import { Listr } from 'listr2'; -import { packageUp } from 'package-up'; import prompts from 'prompts'; import { candidates, SUPPORTED, transform, UNSUPPORTED, type Frameworks } from './index'; -import { parseManifestFromPackage, parsePackageJson } from './parser'; +import { findManifest } from './utils'; const colorFramework = (framework: string) => { switch (framework) { @@ -35,9 +34,10 @@ program .description(json.description) .version(json.version) - .argument('[input]', 'source directory') - .option('-f, --frameworks ', 'the framework to convert to') + .argument('[input]', 'custom elements manifest path') + .requiredOption('-e, --entrypoint ', 'entrypoint to the package') .requiredOption('-o, --outdir ', 'output directory') + .option('-f, --frameworks ', 'the framework to convert to') .option('-y, --yes', 'convert all candidates to all available frameworks') .action( @@ -45,26 +45,20 @@ program sourceDir, options: { outdir: string; - entrypoint?: string; + entrypoint: string; frameworks?: Frameworks[]; yes?: boolean; } ) => { sourceDir = sourceDir ? resolve(sourceDir) : process.cwd(); - const input = await packageUp({ cwd: sourceDir }); - if (!input) { - throw new Error('No package.json found'); - } - - const json = await parsePackageJson(input); - const manifest = await parseManifestFromPackage(input, json); + const manifest = await findManifest(sourceDir); if (!manifest) { throw new Error('No custom elements manifest found'); } const yes = options.yes || !process.stdout.isTTY; - const data = Array.from(candidates(json, manifest)); + const data = Array.from(candidates(manifest)); if (data.length === 0) { throw new Error('No components found'); } @@ -135,6 +129,7 @@ program const outDir = options.outdir.replace(/\[framework\]/g, framework); const outFile = await transform(entry, framework, { + entrypoint: options.entrypoint, outdir: outDir, }); task.title = `Converted ${chalk.whiteBright(component)} to ${colorFramework( diff --git a/src/parser.ts b/src/parser.ts deleted file mode 100644 index 8386d69..0000000 --- a/src/parser.ts +++ /dev/null @@ -1,27 +0,0 @@ -import { readFile } from 'node:fs/promises'; -import { dirname, resolve } from 'node:path'; -import type { Package } from 'custom-elements-manifest'; -import type { PackageJson as PackageJsonBase } from 'type-fest'; - -export type PackageJson = PackageJsonBase & { - customElements?: string; -}; - -export async function parseJson(fileName: string) { - const contents = await readFile(fileName, 'utf-8'); - const json = JSON.parse(contents); - - return json; -} - -export async function parsePackageJson(fileName: string) { - return JSON.parse(await readFile(fileName, 'utf-8')) as PackageJson; -} - -export async function parseManifestFromPackage(fileName: string, data: PackageJson) { - if (!data.customElements) { - return null; - } - - return parseJson(resolve(dirname(fileName), data.customElements)) as Promise; -} diff --git a/src/preact.ts b/src/preact.ts index 5288958..d4ca022 100644 --- a/src/preact.ts +++ b/src/preact.ts @@ -4,14 +4,19 @@ import { capitalize, filterPublicMemebers } from './utils'; import type { Entry } from './walker'; export interface PreactTransformOptions { + /** + * The entrypoint to the package. + */ + entrypoint: string; + /** * The output directory to write the converted components to. */ outdir: string; } -export function generatePreactComponent(entry: Entry) { - const { packageJson, definition, declaration } = entry; +export function generatePreactComponent(entry: Entry, options: PreactTransformOptions) { + const { definition, declaration } = entry; const props = filterPublicMemebers(declaration).map((member) => member.name); const eventProps = @@ -25,7 +30,7 @@ export function generatePreactComponent(entry: Entry) { return `import { h } from 'preact'; import { useRef, useEffect } from 'preact/hooks'; -import '${packageJson.name}'; +import '${options.entrypoint}'; const properties = ${JSON.stringify(props)}; const events = ${JSON.stringify(eventProps)}; @@ -62,11 +67,11 @@ export const ${declaration.name} = ({ children, ...props }) => { };`; } -export function generatePreactTypings(entry: Entry) { - const { packageJson, declaration } = entry; +export function generatePreactTypings(entry: Entry, options: PreactTransformOptions) { + const { declaration } = entry; const imports = `import { FunctionComponent, JSX } from 'preact'; -import { ${declaration.name} as Base${declaration.name} } from '${packageJson.name}'; +import { ${declaration.name} as Base${declaration.name} } from '${options.entrypoint}'; `; const propertiesTypings = filterPublicMemebers(declaration).map( @@ -95,8 +100,8 @@ export async function transformPreact(entry: Entry, options: PreactTransformOpti recursive: true, }); await Promise.all([ - writeFile(outFile, generatePreactComponent(entry)), - writeFile(declFile, generatePreactTypings(entry)), + writeFile(outFile, generatePreactComponent(entry, options)), + writeFile(declFile, generatePreactTypings(entry, options)), ]); return outFile; diff --git a/src/react.ts b/src/react.ts index d84cd93..263b4a8 100644 --- a/src/react.ts +++ b/src/react.ts @@ -4,6 +4,11 @@ import { capitalize, filterPublicMemebers } from './utils'; import type { Entry } from './walker'; export interface ReactTransformOptions { + /** + * The entrypoint to the package. + */ + entrypoint: string; + /** * The output directory to write the converted components to. */ @@ -163,8 +168,8 @@ function getAttributes(tagName: string) { } } -export function generateReactComponent(entry: Entry) { - const { packageJson, definition, declaration } = entry; +export function generateReactComponent(entry: Entry, options: ReactTransformOptions) { + const { definition, declaration } = entry; const props = filterPublicMemebers(declaration).map((member) => member.name); const eventProps = @@ -177,7 +182,7 @@ export function generateReactComponent(entry: Entry) { ) ?? {}; return `import React, { useRef, useEffect } from 'react'; -import '${packageJson.name}'; +import '${options.entrypoint}'; const properties = ${JSON.stringify(props)}; const events = ${JSON.stringify(eventProps)}; @@ -214,11 +219,11 @@ export const ${declaration.name} = ({ children, ...props }) => { };`; } -export function generateReactTypings(entry: Entry) { - const { packageJson, definition, declaration } = entry; +export function generateReactTypings(entry: Entry, options: ReactTransformOptions) { + const { definition, declaration } = entry; const imports = `import React from 'react'; -import { ${declaration.name} as Base${declaration.name} } from '${packageJson.name}'; +import { ${declaration.name} as Base${declaration.name} } from '${options.entrypoint}'; `; const propertiesTypings = filterPublicMemebers(declaration).map( @@ -250,8 +255,8 @@ export async function transformReact(entry: Entry, options: ReactTransformOption recursive: true, }); await Promise.all([ - writeFile(outFile, generateReactComponent(entry)), - writeFile(declFile, generateReactTypings(entry)), + writeFile(outFile, generateReactComponent(entry, options)), + writeFile(declFile, generateReactTypings(entry, options)), ]); return outFile; diff --git a/src/svelte.ts b/src/svelte.ts index c4239ec..db0400a 100644 --- a/src/svelte.ts +++ b/src/svelte.ts @@ -4,6 +4,11 @@ import { filterPublicMemebers } from './utils'; import type { Entry } from './walker'; export interface SvelteTransformOptions { + /** + * The entrypoint to the package. + */ + entrypoint: string; + /** * The output directory to write the converted components to. */ @@ -163,8 +168,8 @@ function getAttributes(tagName: string) { } } -export function generateSvelteComponent(entry: Entry) { - const { packageJson, definition, declaration } = entry; +export function generateSvelteComponent(entry: Entry, options: SvelteTransformOptions) { + const { definition, declaration } = entry; const props: string[] = []; const setters: string[] = []; @@ -196,7 +201,7 @@ export function generateSvelteComponent(entry: Entry) { return `