Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

docs: Add links to symbols #32

Merged
merged 2 commits into from
May 14, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 3 additions & 10 deletions docs/.vitepress/config.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { defineConfig } from 'vitepress';
import { typescriptDocs } from './plugins/typescript-docs';
import { defineTypescriptDocs } from './plugins/typescript-docs';

const ogDescription = 'Next Generation Frontend Tooling';
const ogTitle = 'Web Ext Core';
Expand Down Expand Up @@ -93,18 +93,11 @@ const apiItemGroup = {
};

export default defineConfig({
...defineTypescriptDocs(packageDirnames),

title: `Web Ext Core`,
description: 'Web Extension Development Made Easy',

ignoreDeadLinks: [/^\/api\/.*/],

vite: {
plugins: [typescriptDocs()],
define: {
__PACKAGES__: JSON.stringify(packageDirnames),
},
},

head: [
['link', { rel: 'icon', type: 'image/svg+xml', href: '/logo.svg' }],
['meta', { property: 'og:type', content: 'website' }],
Expand Down
120 changes: 98 additions & 22 deletions docs/.vitepress/plugins/typescript-docs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,104 @@ import { Listr, ListrTask, ListrTaskWrapper } from 'listr2';
import { Project, Symbol, SourceFile, Node, ts, JSDocableNode, JSDoc } from 'ts-morph';
import * as prettier from 'prettier';
import chokidar from 'chokidar';
import { defineConfig } from 'vitepress';
import { parseHTML } from 'linkedom';

export function defineTypescriptDocs(packageDirnames: string[]) {
const ctx: Ctx = {
watchers: [],
symbolMap: {},
};

function plugin(): Plugin {
let mode: 'build' | 'serve';
let hasGenerated = false;

return {
name: 'generate-ts-docs',
configResolved(config) {
mode = config.command;
},
async buildStart() {
if (hasGenerated) return;
hasGenerated = true;

const allPackages = await getPackages();
await generateAll(ctx, allPackages, mode, mode === 'serve');
},
async buildEnd() {
removeWatchListeners(ctx);
},
};
}

return defineConfig({
ignoreDeadLinks: [/^\/api\/.*/],

vite: {
plugins: [plugin()],
define: {
__PACKAGES__: JSON.stringify(packageDirnames),
},
},

transformHtml(code, id) {
const [_, thisPkg] = id.match(/\/api\/(.*)\.html$/) ?? [];
if (!thisPkg) return;

const { document } = parseHTML(code);
/**
* Creates an anchor element to a symbol's package.
*/
const createLink = (
symbolName: string,
thisPkg: string,
packages: string[],
): HTMLAnchorElement => {
const a = document.createElement('a');
a.textContent = symbolName;
if (packages.includes(thisPkg)) {
a.href = '#' + symbolName.toLowerCase();
} else {
a.href = `/api/${packages[0]}#${symbolName.toLowerCase()}`;
}
return a;
};

// Code blocks - same text color, underlined
document.querySelectorAll('pre span').forEach(span => {
Object.entries(ctx.symbolMap).forEach(([symbolName, packages]) => {
if (span.textContent !== symbolName) return;

const a = createLink(symbolName, thisPkg, packages);
a.style.color = 'inherit';
a.style.textDecoration = 'underline';
span.replaceChildren(a);
});
});

// Inline code - primary color, underlined links
document.querySelectorAll('p code, li code').forEach(block =>
Object.entries(ctx.symbolMap).forEach(([symbolName, packages]) => {
// Look for matching full word
if (
!block.textContent
?.replace(/[.,\/#!$%\^&\*;:{}=\-_`~()]/g, '')
.split(/\s+/)
.includes(symbolName)
)
return;

const a = createLink(symbolName, thisPkg, packages);
a.style.textDecoration = 'underline';
block.innerHTML = block.innerHTML.replace(symbolName, a.outerHTML);
}),
);

return document.toString();
},
});
}

type Plugin = NonNullable<NonNullable<UserConfig['vite']>['plugins']>[0];
type SymbolLinks = { [symbolName: string]: string };
Expand All @@ -26,28 +124,6 @@ const EXCLUDED_SYMBOLS = [
'TReturn',
];

export function typescriptDocs(): Plugin {
const ctx: Ctx = {
watchers: [],
symbolMap: {},
};
let mode: 'build' | 'serve';

return {
name: 'typescript-docs',
configResolved(config) {
mode = config.command;
},
async buildStart() {
const allPackages = await getPackages();
await generateAll(ctx, allPackages, mode, mode === 'serve');
},
async buildEnd() {
removeWatchListeners(ctx);
},
};
}

/**
* context passed into each task
*/
Expand Down
9 changes: 4 additions & 5 deletions docs/api/job-scheduler.md
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ interface IntervalJob {
}
```

A job that executes on a set interval, starting when the job is scheduled.
A job that executes on a set interval, starting when the job is scheduled for the first time.

### Properties

Expand All @@ -84,11 +84,10 @@ A job that executes on a set interval, starting when the job is scheduled.
- ***`type: 'interval'`***

- ***`duration: number`***<br/>Interval in milliseconds. Due to limitations of the alarms API, it must be greater than 1
minute and it will be rounded to the nearest minute.
minute.

- ***`immediate?: boolean`*** (default: `false`)<br/>Execute the job immediately when it is scheduled for the first time. If `false`, it will
execute for the first time after `durationInMs`. This has no effect when updating an existing
job.
execute for the first time after `duration`. This has no effect when updating an existing job.

- ***`execute: ExecuteFn`***

Expand Down Expand Up @@ -123,7 +122,7 @@ interface JobSchedulerConfig {
}
```

Cofnigure how the messenger behaves.
Configures how the job scheduler behaves.

### Properties

Expand Down
4 changes: 2 additions & 2 deletions docs/api/messaging.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ interface ExtensionMessagingConfig {
}
```

Cofnigure how the messenger behaves.
Configure how the messenger behaves.

### Properties

Expand Down Expand Up @@ -110,7 +110,7 @@ Unlike the regular `chrome.runtime` messaging APIs, there are no limitations to
## `ProtocolWithReturn`

:::danger Deprecated
Use the function syntax instead: <https://webext-core.aklinker1.io/messaging/protocol-maps.html#syntax>
Use the function syntax instead: <https://webext-core.aklinker1.io/guide/messaging/protocol-maps.html#syntax>
:::

```ts
Expand Down
4 changes: 3 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@
"docs:build": "vitepress build docs",
"docs:serve": "vitepress serve docs",
"docs:test": "vitest -r docs",
"docs:generate": "typedoc --plugin typedoc-plugin-markdown",
"build": "turbo run build",
"prepare": "husky install"
},
Expand All @@ -28,5 +27,8 @@
"vitepress": "1.0.0-alpha.75",
"vitest": "^0.29.2",
"webextension-polyfill": "^0.10.0"
},
"dependencies": {
"linkedom": "^0.14.26"
}
}
2 changes: 1 addition & 1 deletion packages/messaging/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ export interface ExtensionMessagingConfig {
*
* > Internally, this is just an object with random keys for the data and return types.
*
* @deprecated Use the function syntax instead: <https://webext-core.aklinker1.io/messaging/protocol-maps.html#syntax>
* @deprecated Use the function syntax instead: <https://webext-core.aklinker1.io/guide/messaging/protocol-maps.html#syntax>
*
* @example
* interface ProtocolMap {
Expand Down
26 changes: 13 additions & 13 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.