diff --git a/packages/analyzer/fixtures/cli-readme-flag/README.md b/packages/analyzer/fixtures/cli-readme-flag/README.md
new file mode 100644
index 00000000..659391ac
--- /dev/null
+++ b/packages/analyzer/fixtures/cli-readme-flag/README.md
@@ -0,0 +1,36 @@
+# `my-element.js`:
+
+## class: `MyElement`, `my-element`
+
+### Superclass
+
+| Name | Module | Package |
+| ------------- | ------ | ------- |
+| `HTMLElement` | | |
+
+### Fields
+
+| Name | Privacy | Type | Default | Description | Inherited From |
+| ----- | ------- | -------- | ------- | ----------- | -------------- |
+| `foo` | | `string` | `'bar'` | | |
+
+
+
+## class: `MyWindow`, `my-window`
+
+### Superclass
+
+| Name | Module | Package |
+| ------------- | ------ | ------- |
+| `HTMLElement` | | |
+
+
+
+## Exports
+
+| Kind | Name | Declaration | Module | Package |
+| --------------------------- | ------------ | ----------- | ------------- | ------- |
+| `custom-element-definition` | `my-foo` | MyFoo | /foo.js | |
+| `custom-element-definition` | `my-bar` | MyBar | | foo |
+| `custom-element-definition` | `my-element` | MyElement | my-element.js | |
+| `custom-element-definition` | `my-window` | MyWindow | my-element.js | |
diff --git a/packages/analyzer/fixtures/cli-readme-flag/custom-elements.json b/packages/analyzer/fixtures/cli-readme-flag/custom-elements.json
new file mode 100644
index 00000000..ec9872be
--- /dev/null
+++ b/packages/analyzer/fixtures/cli-readme-flag/custom-elements.json
@@ -0,0 +1,76 @@
+{
+ "schemaVersion": "1.0.0",
+ "readme": "",
+ "modules": [
+ {
+ "kind": "javascript-module",
+ "path": "my-element.js",
+ "declarations": [
+ {
+ "kind": "class",
+ "description": "",
+ "name": "MyElement",
+ "members": [
+ {
+ "kind": "field",
+ "name": "foo",
+ "type": {
+ "text": "string"
+ },
+ "default": "'bar'"
+ }
+ ],
+ "superclass": {
+ "name": "HTMLElement"
+ },
+ "tagName": "my-element",
+ "customElement": true
+ },
+ {
+ "kind": "class",
+ "description": "",
+ "name": "MyWindow",
+ "superclass": {
+ "name": "HTMLElement"
+ },
+ "tagName": "my-window",
+ "customElement": true
+ }
+ ],
+ "exports": [
+ {
+ "kind": "custom-element-definition",
+ "name": "my-foo",
+ "declaration": {
+ "name": "MyFoo",
+ "module": "/foo.js"
+ }
+ },
+ {
+ "kind": "custom-element-definition",
+ "name": "my-bar",
+ "declaration": {
+ "name": "MyBar",
+ "package": "foo"
+ }
+ },
+ {
+ "kind": "custom-element-definition",
+ "name": "my-element",
+ "declaration": {
+ "name": "MyElement",
+ "module": "my-element.js"
+ }
+ },
+ {
+ "kind": "custom-element-definition",
+ "name": "my-window",
+ "declaration": {
+ "name": "MyWindow",
+ "module": "my-element.js"
+ }
+ }
+ ]
+ }
+ ]
+}
diff --git a/packages/analyzer/fixtures/cli-readme-flag/fixture/README.md b/packages/analyzer/fixtures/cli-readme-flag/fixture/README.md
new file mode 100644
index 00000000..659391ac
--- /dev/null
+++ b/packages/analyzer/fixtures/cli-readme-flag/fixture/README.md
@@ -0,0 +1,36 @@
+# `my-element.js`:
+
+## class: `MyElement`, `my-element`
+
+### Superclass
+
+| Name | Module | Package |
+| ------------- | ------ | ------- |
+| `HTMLElement` | | |
+
+### Fields
+
+| Name | Privacy | Type | Default | Description | Inherited From |
+| ----- | ------- | -------- | ------- | ----------- | -------------- |
+| `foo` | | `string` | `'bar'` | | |
+
+
+
+## class: `MyWindow`, `my-window`
+
+### Superclass
+
+| Name | Module | Package |
+| ------------- | ------ | ------- |
+| `HTMLElement` | | |
+
+
+
+## Exports
+
+| Kind | Name | Declaration | Module | Package |
+| --------------------------- | ------------ | ----------- | ------------- | ------- |
+| `custom-element-definition` | `my-foo` | MyFoo | /foo.js | |
+| `custom-element-definition` | `my-bar` | MyBar | | foo |
+| `custom-element-definition` | `my-element` | MyElement | my-element.js | |
+| `custom-element-definition` | `my-window` | MyWindow | my-element.js | |
diff --git a/packages/analyzer/fixtures/cli-readme-flag/fixture/custom-elements.json b/packages/analyzer/fixtures/cli-readme-flag/fixture/custom-elements.json
new file mode 100644
index 00000000..ec9872be
--- /dev/null
+++ b/packages/analyzer/fixtures/cli-readme-flag/fixture/custom-elements.json
@@ -0,0 +1,76 @@
+{
+ "schemaVersion": "1.0.0",
+ "readme": "",
+ "modules": [
+ {
+ "kind": "javascript-module",
+ "path": "my-element.js",
+ "declarations": [
+ {
+ "kind": "class",
+ "description": "",
+ "name": "MyElement",
+ "members": [
+ {
+ "kind": "field",
+ "name": "foo",
+ "type": {
+ "text": "string"
+ },
+ "default": "'bar'"
+ }
+ ],
+ "superclass": {
+ "name": "HTMLElement"
+ },
+ "tagName": "my-element",
+ "customElement": true
+ },
+ {
+ "kind": "class",
+ "description": "",
+ "name": "MyWindow",
+ "superclass": {
+ "name": "HTMLElement"
+ },
+ "tagName": "my-window",
+ "customElement": true
+ }
+ ],
+ "exports": [
+ {
+ "kind": "custom-element-definition",
+ "name": "my-foo",
+ "declaration": {
+ "name": "MyFoo",
+ "module": "/foo.js"
+ }
+ },
+ {
+ "kind": "custom-element-definition",
+ "name": "my-bar",
+ "declaration": {
+ "name": "MyBar",
+ "package": "foo"
+ }
+ },
+ {
+ "kind": "custom-element-definition",
+ "name": "my-element",
+ "declaration": {
+ "name": "MyElement",
+ "module": "my-element.js"
+ }
+ },
+ {
+ "kind": "custom-element-definition",
+ "name": "my-window",
+ "declaration": {
+ "name": "MyWindow",
+ "module": "my-element.js"
+ }
+ }
+ ]
+ }
+ ]
+}
diff --git a/packages/analyzer/fixtures/cli-readme-flag/package/README.md b/packages/analyzer/fixtures/cli-readme-flag/package/README.md
new file mode 100644
index 00000000..3527bdb4
--- /dev/null
+++ b/packages/analyzer/fixtures/cli-readme-flag/package/README.md
@@ -0,0 +1,36 @@
+## `my-element.js`:
+
+### class: `MyElement`, `my-element`
+
+#### Superclass
+
+| Name | Module | Package |
+| ------------- | ------ | ------- |
+| `HTMLElement` | | |
+
+#### Fields
+
+| Name | Privacy | Type | Default | Description | Inherited From |
+| ----- | ------- | -------- | ------- | ----------- | -------------- |
+| `foo` | | `string` | `'bar'` | | |
+
+
+
+### class: `MyWindow`, `my-window`
+
+#### Superclass
+
+| Name | Module | Package |
+| ------------- | ------ | ------- |
+| `HTMLElement` | | |
+
+
+
+### Exports
+
+| Kind | Name | Declaration | Module | Package |
+| --------------------------- | ------------ | ----------- | ------------- | ------- |
+| `custom-element-definition` | `my-foo` | MyFoo | /foo.js | |
+| `custom-element-definition` | `my-bar` | MyBar | | foo |
+| `custom-element-definition` | `my-element` | MyElement | my-element.js | |
+| `custom-element-definition` | `my-window` | MyWindow | my-element.js | |
diff --git a/packages/analyzer/fixtures/cli-readme-flag/package/my-element.js b/packages/analyzer/fixtures/cli-readme-flag/package/my-element.js
new file mode 100644
index 00000000..01fc0c90
--- /dev/null
+++ b/packages/analyzer/fixtures/cli-readme-flag/package/my-element.js
@@ -0,0 +1,12 @@
+import {MyFoo} from './foo.js';
+import {MyBar} from 'foo';
+
+class MyElement extends HTMLElement {
+ foo = 'bar';
+}
+class MyWindow extends HTMLElement {}
+
+customElements.define('my-foo', MyFoo);
+customElements.define('my-bar', MyBar);
+customElements.define('my-element', MyElement);
+window.customElements.define('my-window', MyWindow);
\ No newline at end of file
diff --git a/packages/analyzer/fixtures/cli-readme-flag/package/package.json b/packages/analyzer/fixtures/cli-readme-flag/package/package.json
new file mode 100644
index 00000000..93b73a80
--- /dev/null
+++ b/packages/analyzer/fixtures/cli-readme-flag/package/package.json
@@ -0,0 +1,4 @@
+{
+ "name": "my-el",
+ "customElements": "../custom-elements.json"
+}
diff --git a/packages/analyzer/index.js b/packages/analyzer/index.js
index 284205b3..7ea9addf 100755
--- a/packages/analyzer/index.js
+++ b/packages/analyzer/index.js
@@ -9,10 +9,11 @@ import chokidar from 'chokidar';
import debounce from 'debounce';
import { create } from './src/create.js';
-import {
- getUserConfig,
- getCliConfig,
- addFrameworkPlugins,
+import {
+ getUserConfig,
+ getCliConfig,
+ addFrameworkPlugins,
+ addReadmePlugin,
addCustomElementsPropertyToPackageJson,
mergeGlobsAndExcludes,
timestamp,
@@ -24,7 +25,7 @@ import {
const mainDefinitions = [{ name: 'command', defaultOption: true }];
const mainOptions = commandLineArgs(mainDefinitions, { stopAtFirstUnknown: true });
const argv = mainOptions._unknown || [];
-
+
if (mainOptions.command === 'analyze') {
const cliConfig = getCliConfig(argv)
@@ -41,20 +42,20 @@ import {
async function run() {
/**
* Create modules for `create()`
- *
+ *
* By default, the analyzer doesn't actually compile a users source code with the TS compiler
* API. This means that by default, the typeChecker is not available in plugins.
- *
+ *
* If users want to use the typeChecker, they can do so by adding a `overrideModuleCreation` property
* in their custom-elements-manifest.config.js. `overrideModuleCreation` is a function that should return
* an array of sourceFiles.
*/
- const modules = userConfig?.overrideModuleCreation
+ const modules = userConfig?.overrideModuleCreation
? userConfig.overrideModuleCreation({ts, globs})
: globs.map(glob => {
const relativeModulePath = path.relative(process.cwd(), glob);
const source = fs.readFileSync(relativeModulePath).toString();
-
+
return ts.createSourceFile(
relativeModulePath,
source,
@@ -62,10 +63,14 @@ import {
true,
);
});
-
+
let plugins = await addFrameworkPlugins(mergedOptions);
- plugins = [...plugins, ...(userConfig?.plugins || [])];
-
+ plugins = [
+ ...plugins,
+ ...await addReadmePlugin(mergedOptions),
+ ...(userConfig?.plugins || [])
+ ];
+
/**
* Create the manifest
*/
@@ -93,9 +98,9 @@ import {
*/
if(mergedOptions.watch) {
const fileWatcher = chokidar.watch(globs);
-
+
const onChange = debounce(run, 100);
-
+
fileWatcher.addListener('change', onChange);
fileWatcher.addListener('unlink', onChange);
}
@@ -108,4 +113,4 @@ import {
} else {
console.log(MENU);
}
-})();
\ No newline at end of file
+})();
diff --git a/packages/analyzer/package.json b/packages/analyzer/package.json
index 950f947d..591872cc 100644
--- a/packages/analyzer/package.json
+++ b/packages/analyzer/package.json
@@ -43,6 +43,7 @@
"command-line-args": "^5.1.2",
"comment-parser": "^1.1.5",
"custom-elements-manifest": "^1.0.0",
+ "cem-plugin-readme": "0.1.2",
"debounce": "^1.2.1",
"globby": "^11.0.4",
"typescript": "^4.3.2"
diff --git a/packages/analyzer/src/utils/cli.js b/packages/analyzer/src/utils/cli.js
index e1bbaee2..18c06f6d 100644
--- a/packages/analyzer/src/utils/cli.js
+++ b/packages/analyzer/src/utils/cli.js
@@ -5,10 +5,10 @@ import commandLineArgs from 'command-line-args';
import { has } from './index.js';
const IGNORE = [
- '!node_modules/**/*.*',
- '!bower_components/**/*.*',
- '!**/*.test.{js,ts}',
- '!**/*.suite.{js,ts}',
+ '!node_modules/**/*.*',
+ '!bower_components/**/*.*',
+ '!**/*.test.{js,ts}',
+ '!**/*.suite.{js,ts}',
'!**/*.config.{js,ts}'
];
@@ -54,7 +54,11 @@ export const DEFAULTS = {
litelement: false,
stencil: false,
fast: false,
- catalyst: false
+ catalyst: false,
+ readme: true,
+ header: '',
+ footer: '',
+ headingOffset: 0,
}
export function getCliConfig(argv) {
@@ -68,8 +72,12 @@ export function getCliConfig(argv) {
{ name: 'stencil', type: Boolean },
{ name: 'fast', type: Boolean },
{ name: 'catalyst', type: Boolean },
+ { name: 'readme', type: Boolean },
+ { name: 'header', type: String },
+ { name: 'footer', type: String },
+ { name: 'headingOffset', type: Number },
];
-
+
return commandLineArgs(optionDefinitions, { argv });
}
@@ -103,6 +111,22 @@ export function timestamp() {
return date.toLocaleTimeString();
}
+export async function addReadmePlugin({ readme, ...options }) {
+ if (!readme)
+ return [];
+ else {
+ const { headingOffset, header, footer, outdir } = options;
+ return [
+ await import('cem-plugin-readme').then(m => m.readmePlugin({
+ footer,
+ from: outdir,
+ header,
+ headingOffset,
+ })),
+ ];
+ }
+}
+
export function addCustomElementsPropertyToPackageJson(outdir) {
const packageJsonPath = `${process.cwd()}${path.sep}package.json`;
const packageJson = JSON.parse(fs.readFileSync(packageJsonPath).toString());
@@ -123,19 +147,23 @@ export const MENU = `
@custom-elements-manifest/analyzer
Available commands:
- | Command/option | Type | Description | Example |
- | ---------------- | ---------- | ----------------------------------------------------------- | --------------------- |
- | analyze | | Analyze your components | |
- | --globs | string[] | Globs to analyze | \`--globs "foo.js"\` |
- | --exclude | string[] | Globs to exclude | \`--exclude "foo.js"\` |
- | --outdir | string | Directory to output the Manifest to | \`--outdir dist\` |
- | --watch | boolean | Enables watch mode, generates a new manifest on file change | \`--watch\` |
- | --dev | boolean | Enables extra logging for debugging | \`--dev\` |
- | --litelement | boolean | Enable special handling for LitElement syntax | \`--litelement\` |
- | --fast | boolean | Enable special handling for FASTElement syntax | \`--fast\` |
- | --stencil | boolean | Enable special handling for Stencil syntax | \`--stencil\` |
- | --catalyst | boolean | Enable special handling for Catalyst syntax | \`--catalyst\` |
+ | Command/option | Type | Description | Example |
+ | ---------------- | ---------- | ----------------------------------------------------------- | ---------------------------------- |
+ | analyze | | Analyze your components | |
+ | --globs | string[] | Globs to analyze | \`--globs "foo.js"\` |
+ | --exclude | string[] | Globs to exclude | \`--exclude "foo.js"\` |
+ | --outdir | string | Directory to output the Manifest to | \`--outdir dist\` |
+ | --watch | boolean | Enables watch mode, generates a new manifest on file change | \`--watch\` |
+ | --dev | boolean | Enables extra logging for debugging | \`--dev\` |
+ | --litelement | boolean | Enable special handling for LitElement syntax | \`--litelement\` |
+ | --fast | boolean | Enable special handling for FASTElement syntax | \`--fast\` |
+ | --stencil | boolean | Enable special handling for Stencil syntax | \`--stencil\` |
+ | --catalyst | boolean | Enable special handling for Catalyst syntax | \`--catalyst\` |
+ | --readme | boolean | Create a README.md file | \`--readme\` |
+ | --header | string | Markdown header file for the README.md | \`--header README.head.md\` |
+ | --footer | string | Markdown footer file for the README.md | \`--footer README.foot.md\` |
+ | --headingOffset | number | Number of levels to offset headings in the README.md | \`--headingOffset 1\` |
Example:
custom-elements-manifest analyze --litelement --globs "**/*.js" --exclude "foo.js" "bar.js"
-`
\ No newline at end of file
+`
diff --git a/packages/analyzer/test/cli.test.js b/packages/analyzer/test/cli.test.js
new file mode 100644
index 00000000..efda10d9
--- /dev/null
+++ b/packages/analyzer/test/cli.test.js
@@ -0,0 +1,55 @@
+import { test } from 'uvu';
+import * as assert from 'uvu/assert';
+import path from 'path';
+import fs from 'fs';
+import * as child_process from 'child_process';
+import { promisify } from 'util'
+
+const exec = promisify(child_process.exec);
+
+const fixturesDir = path.join(process.cwd(), 'fixtures');
+let testCases = fs.readdirSync(fixturesDir).filter(x => x.startsWith('cli-'));
+
+const runSingle = testCases.find(_case => _case.startsWith('+'));
+if (runSingle) {
+ testCases = [runSingle];
+}
+
+testCases.forEach(testCase => {
+ test(`Testcase ${testCase}`, async () => {
+ // skips tests
+ if (testCase.startsWith('-')) {
+ assert.equal(true, true);
+ return;
+ }
+
+ const fixturePath = path.join(fixturesDir, testCase, 'fixture');
+ const fixture = JSON.parse(fs.readFileSync(path.join(fixturePath, 'custom-elements.json'), 'utf-8'));
+
+ const packagePath = path.join(fixturesDir, testCase, 'package');
+
+ const outputPath = path.join(fixturesDir, testCase);
+
+ try {
+ const { stdout, stderr } = await exec('node ../../../index.js analyze --readme --outdir ..', { cwd: packagePath });
+ console.log(stdout)
+ if (stderr)
+ throw new Error(stderr);
+ } catch (e) {
+ console.error(e); // should contain code (exit code) and signal (that caused the termination).
+ }
+
+ const result = JSON.parse(fs.readFileSync(path.join(outputPath, 'custom-elements.json'), 'utf-8'));
+
+ assert.equal(result, fixture);
+
+ if (testCase.includes('readme')) {
+ assert.equal(
+ fs.readFileSync(path.join(outputPath, 'README.md'), 'utf8'),
+ fs.readFileSync(path.join(fixturePath, 'README.md'), 'utf8'),
+ );
+ }
+ });
+});
+
+test.run();
diff --git a/packages/analyzer/test/integration.test.js b/packages/analyzer/test/integration.test.js
index e42e4dc3..1eed70b1 100644
--- a/packages/analyzer/test/integration.test.js
+++ b/packages/analyzer/test/integration.test.js
@@ -9,7 +9,7 @@ import ts from 'typescript';
import { create } from '../src/create.js';
const fixturesDir = path.join(process.cwd(), 'fixtures');
-let testCases = fs.readdirSync(fixturesDir);
+let testCases = fs.readdirSync(fixturesDir).filter(x => !x.startsWith('cli-'));
const runSingle = testCases.find(_case => _case.startsWith('+'));
if (runSingle) {
@@ -37,7 +37,7 @@ testCases.forEach(testCase => {
.map(glob => {
const relativeModulePath = `.${path.sep}${path.relative(process.cwd(), glob)}`;
const source = fs.readFileSync(relativeModulePath).toString();
-
+
return ts.createSourceFile(
relativeModulePath,
source,
@@ -52,13 +52,20 @@ testCases.forEach(testCase => {
const config = await import(manifestPathFileURL);
plugins = [...config.default.plugins];
} catch {}
-
+
const result = create({modules, plugins});
fs.writeFileSync(outputPath, JSON.stringify(result, null, 2));
assert.equal(result, fixture);
+
+ if (testCase === 'readme-flag')
+ assert.equal(
+ fs.readFileSync(path.join(path.dirname(outputPath), 'README.md')),
+ fs.readFileSync(path.join(path.dirname(fixturePath), 'README.md')),
+ '--readme flag'
+ )
});
});
-test.run();
\ No newline at end of file
+test.run();
diff --git a/plugins/readme/README.md b/plugins/readme/README.md
index 82ef29e8..4ed9033c 100644
--- a/plugins/readme/README.md
+++ b/plugins/readme/README.md
@@ -4,13 +4,13 @@ Generates a `README.md` file for a custom element package
## Options
-| Option | Type | Description | Default |
-| ------------- | ------- | ------------------------------------------------------ | ----------------------- |
-| from | string | absolute path to package root | 2 dirs above the plugin |
-| to | string | relative path from package root | `'README.md'` |
-| headingOffset | integer | number of levels to offset generated markdown headings | `1` |
-| header | string | relative path to header file | `undefined` |
-| footer | string | relative path to footer file | `undefined` |
+| Option | Type | Description | Default |
+| ------------- | ------- | ------------------------------------------------------ | ------------- |
+| from | string | Path to package root (relative to current workign dir) | `.` |
+| to | string | relative path from package root | `'README.md'` |
+| headingOffset | integer | number of levels to offset generated markdown headings | `1` |
+| header | string | relative path to header file | `undefined` |
+| footer | string | relative path to footer file | `undefined` |
## Example
diff --git a/plugins/readme/index.js b/plugins/readme/index.js
index a262f86d..e701f594 100644
--- a/plugins/readme/index.js
+++ b/plugins/readme/index.js
@@ -1,12 +1,10 @@
import { customElementsManifestToMarkdown } from '@custom-elements-manifest/to-markdown';
-
import { mkdirSync, readFileSync, writeFileSync } from 'fs';
-import { fileURLToPath } from 'url';
-import { dirname, join } from 'path';
+import { dirname, isAbsolute, join, resolve } from 'path';
/**
* @typedef {import('@custom-elements-manifest/to-markdown').Options} Options
- * @property {string} [from] absolute path to package root
+ * @property {string} [from] path to package root, relative to current working directory
* @property {string} [to="README.md"] relative path from package root to output file
* @property {number} [headingOffset=1] offset for markdown heading level
* @property {string} [header] relative path to header file
@@ -21,7 +19,7 @@ export function readmePlugin(options) {
const {
header,
footer,
- from = join(dirname(fileURLToPath(import.meta.url)), '..', '..'),
+ from = '.',
to = 'README.md',
headingOffset = 1,
exportKinds,
@@ -29,7 +27,9 @@ export function readmePlugin(options) {
return {
name: 'readme',
packageLinkPhase({ customElementsManifest }) {
- const outPath = join(from, to);
+ const absPath = isAbsolute(from) ? from : resolve(process.cwd(), from);
+
+ const outPath = join(absPath, to);
try {
const head = header && readFileSync(join(from, header));
diff --git a/yarn.lock b/yarn.lock
index 0efb13ff..578f578d 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -298,6 +298,13 @@ ccount@^2.0.0:
resolved "https://registry.yarnpkg.com/ccount/-/ccount-2.0.0.tgz#3d6fb55803832766a24c6f339abc507297eb5d25"
integrity sha512-VOR0NWFYX65n9gELQdcpqsie5L5ihBXuZGAgaPEp/U7IOSjnPMEH6geE+2f6lcekaNEfWzAHS45mPvSo5bqsUA==
+cem-plugin-readme@0.1.2:
+ version "0.1.2"
+ resolved "https://registry.yarnpkg.com/cem-plugin-readme/-/cem-plugin-readme-0.1.2.tgz#65a4d6c8973bb9c42e2a68fb3053a353e5475379"
+ integrity sha512-K28QXc6nG22p+aHzdPnQQi3uM02HLkbERCqDCwLT11mmQMr+WS5sbXwnR4YYUhPc/kUbASUu+OoFLlgmQ+7RgQ==
+ dependencies:
+ "@custom-elements-manifest/to-markdown" "^0.0.9"
+
chalk@^2.0.0, chalk@^2.4.1:
version "2.4.2"
resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424"