Skip to content

Commit

Permalink
Merge pull request #9 from remcohaszing/browser-support
Browse files Browse the repository at this point in the history
Add browser support
  • Loading branch information
remcohaszing authored Oct 2, 2022
2 parents 8a6a5bb + e1a698c commit 3021ff2
Show file tree
Hide file tree
Showing 67 changed files with 1,580 additions and 499 deletions.
1 change: 1 addition & 0 deletions .c8rc.json
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
{
"100": true,
"include": ["index.ts"],
"reporter": ["html", "lcov", "text"]
}
5 changes: 5 additions & 0 deletions .eslintrc.yaml
Original file line number Diff line number Diff line change
@@ -1,2 +1,7 @@
extends:
- remcohaszing
rules:
no-param-reassign: off
'@typescript-eslint/consistent-type-imports':
- error
- prefer: type-imports
5 changes: 5 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,12 @@ jobs:
node-version: ${{ matrix.node-version }}
- run: npm --global install npm@8
if: ${{ matrix.node-version == 14 }}
- uses: actions/cache@v3
with:
path: ~/.cache/ms-playwright
key: playwright-${{ hashFiles('package-lock.json') }}
- run: npm ci
- run: npx playwright install
- run: npm test
- uses: codecov/codecov-action@v3
if: ${{ matrix.node-version == 18 }}
Expand Down
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
coverage/
dist/
node_modules/
test-results/
*.d.ts
*.js
*.log
Expand Down
3 changes: 1 addition & 2 deletions .prettierignore
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
__fixtures__/*/output.md
__snapshots__/
**/*-snapshots/*
coverage/
dist/
7 changes: 7 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -48,15 +48,22 @@ console.log(value);
These options are passed to
[`puppeteer.launch()`](https://pptr.dev/#?product=Puppeteer&show=api-puppeteerlaunchoptions).

- **Note**: This options is required in Node.js. In the browser this option is unused.

#### `svgo`

These options are passed to the [SVGO](https://github.com/svg/svgo) constructor. Set to `null` to
disable minifying using SVGO completely.

**Note**: This options is only supported in Node.js. In the browser this option is unused.

#### `mermaidOptions`

The [mermaid options](https://mermaid-js.github.io/mermaid/#/Setup) to use.

**Note**: This options is only supported in Node.js. In the browser this option is unused. If you
use this in a browser, call `mermaid.initialize()` manually.

## License

[MIT](LICENSE.md) © [Remco Haszing](https://github.com/remcohaszing)
39 changes: 39 additions & 0 deletions browser.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import { fromDom } from 'hast-util-from-dom';
import { type Code, type Parent, type Root } from 'mdast';
import mermaid from 'mermaid';
import { type Plugin } from 'unified';
import { visit } from 'unist-util-visit';

// eslint-disable-next-line jsdoc/require-jsdoc
function transformer(ast: Root): void {
const instances: [string, number, Parent][] = [];

visit(ast, { type: 'code', lang: 'mermaid' }, (node: Code, index, parent: Parent) => {
instances.push([node.value, index, parent]);
});

// Nothing to do. No need to start puppeteer in this case.
if (!instances.length) {
return;
}

const results = instances.map(([code], index) =>
// @ts-expect-error The mermaid types are wrong.
mermaid.render(`remark-mermaid-${index}`, code),
);

const wrapper = document.createElement('div');
for (const [i, [, index, parent]] of instances.entries()) {
const value = results[i];
wrapper.innerHTML = value;
parent.children.splice(index, 1, {
type: 'paragraph',
children: [{ type: 'html', value }],
data: { hChildren: [fromDom(wrapper.firstChild!)] },
});
}
}

const remarkMermaid: Plugin<[], Root> = () => transformer;

export default remarkMermaid;
42 changes: 27 additions & 15 deletions index.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
import { createRequire } from 'module';

import { fromParse5 } from 'hast-util-from-parse5';
import { Code, Parent, Root } from 'mdast';
import { Mermaid } from 'mermaid';
import { type Code, type Parent, type Root } from 'mdast';
import { type Mermaid } from 'mermaid';
import { parseFragment } from 'parse5';
import puppeteer, { Browser, Page, PuppeteerLaunchOptions } from 'puppeteer-core';
import { optimize, OptimizedSvg, OptimizeOptions } from 'svgo';
import { Plugin } from 'unified';
import puppeteer, { type Browser, type Page, type PuppeteerLaunchOptions } from 'puppeteer-core';
import { optimize, type OptimizedSvg, type OptimizeOptions } from 'svgo';
import { type Plugin } from 'unified';
import { visit } from 'unist-util-visit';

const mermaidScript = {
Expand Down Expand Up @@ -76,7 +76,9 @@ export const defaultSVGOOptions: OptimizeOptions = {

export interface RemarkMermaidOptions {
/**
* Launc options to pass to puppeteer.
* Launch options to pass to puppeteer.
*
* **Note**: This options is required in Node.js. In the browser this option is unused.
*/
launchOptions: PuppeteerLaunchOptions;

Expand All @@ -85,24 +87,31 @@ export interface RemarkMermaidOptions {
*
* Set to `null` explicitly to disable this.
*
* **Note**: This options is only supported in Node.js. In the browser this option is unused.
*
* @default defaultSVGOOptions
*/
svgo?: OptimizeOptions | null;

/**
* The mermaid options to use.
*
* **Note**: This options is only supported in Node.js. In the browser this option is unused. If
* you use this in a browser, call `mermaid.initialize()` manually.
*/
mermaidOptions?: Parameters<typeof mermaid['initialize']>[0];
}

/**
* @param options Options that may be used to tweak the output.
*/
const remarkMermaid: Plugin<[RemarkMermaidOptions], Root> = ({
launchOptions,
mermaidOptions = {},
svgo = defaultSVGOOptions,
}) => {
const remarkMermaid: Plugin<[RemarkMermaidOptions?], Root> = (options) => {
if (!options?.launchOptions?.executablePath) {
throw new Error('The option `launchOptions.executablePath` is required when using Node.js');
}

const { launchOptions, mermaidOptions, svgo = defaultSVGOOptions } = options;

let browserPromise: Promise<Browser> | undefined;
let count = 0;

Expand Down Expand Up @@ -135,14 +144,17 @@ const remarkMermaid: Plugin<[RemarkMermaidOptions], Root> = ({
results = await page.evaluate(
// We can’t calculate coverage on this function, as it’s run by Chrome, not Node.
/* c8 ignore start */
(codes, initOptions) =>
codes.map((code) => {
const id = 'a';
(codes, initOptions) => {
if (initOptions) {
mermaid.initialize(initOptions);
}
return codes.map((code) => {
const id = 'a';
const div = document.createElement('div');
div.innerHTML = mermaid.render(id, code);
return div.innerHTML;
}),
});
},
/* C8 ignore stop */
instances.map((instance) => instance[0]),
mermaidOptions,
Expand Down
Loading

0 comments on commit 3021ff2

Please sign in to comment.