Merge branch 'develop' into update-routerMode-docs

This commit is contained in:
Joe Pea 2023-07-16 10:18:21 -07:00 committed by GitHub
commit dab6e1c1be
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
115 changed files with 4691 additions and 17282 deletions

View File

@ -1,5 +0,0 @@
{
"sandboxes": ["2d17z"],
"packages": [".", "packages/docsify-server-renderer"],
"node": "16"
}

View File

@ -4,6 +4,5 @@ build
docs
lib
node_modules
packages/docsify-server-renderer/build.js
server.js
themes

View File

@ -1,4 +1,4 @@
const prettierConfig = require('./.prettierrc');
const prettierConfig = require('./.prettierrc.json');
module.exports = {
root: true,
@ -63,7 +63,6 @@ module.exports = {
yoda: ['error', 'never'],
// Import rules
// Search way how integrate with `lerna`
'import/imports-first': ['error'],
'import/newline-after-import': ['error'],
'import/no-duplicates': ['error'],

17
.github/dependabot.yml vendored Normal file
View File

@ -0,0 +1,17 @@
# To get started with Dependabot version updates, you'll need to specify which
# package ecosystems to update and where the package manifests are located.
# Please see the documentation for all configuration options:
# https://docs.github.com/github/administering-a-repository/configuration-options-for-dependency-updates
version: 2
updates:
- package-ecosystem: npm # See documentation for possible values
directory: "/" # Location of package manifests
open-pull-requests-limit: 10
schedule:
interval: "weekly"
- package-ecosystem: "github-actions"
directory: "/"
open-pull-requests-limit: 10
schedule:
interval: monthly

View File

@ -1,10 +1,6 @@
name: Build & Test
on:
push:
branches: [master, develop]
pull_request:
branches: [master, develop]
on: [push]
jobs:
lint:
@ -13,9 +9,9 @@ jobs:
matrix:
node-version: ['lts/*']
steps:
- uses: actions/checkout@v2
- uses: actions/checkout@v3
- name: Setup Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v2
uses: actions/setup-node@v3
with:
node-version: ${{ matrix.node-version }}
cache: 'npm'
@ -26,10 +22,6 @@ jobs:
- name: Lint
run: npm run lint
- name: Verify dependencies [server-renderer]
working-directory: ./packages/docsify-server-renderer
run: npm ci --ignore-scripts
test-jest:
runs-on: ${{ matrix.os }}
strategy:
@ -38,9 +30,9 @@ jobs:
node-version: ['lts/*']
os: ['macos-latest', 'ubuntu-latest', 'windows-latest']
steps:
- uses: actions/checkout@v2
- uses: actions/checkout@v3
- name: Setup Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v2
uses: actions/setup-node@v3
with:
node-version: ${{ matrix.node-version }}
cache: 'npm'
@ -59,9 +51,9 @@ jobs:
matrix:
node-version: ['lts/*']
steps:
- uses: actions/checkout@v2
- uses: actions/checkout@v3
- name: Setup Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v2
uses: actions/setup-node@v3
with:
node-version: ${{ matrix.node-version }}
cache: 'npm'
@ -74,7 +66,7 @@ jobs:
- name: E2E Tests (Playwright)
run: npm run test:e2e
- name: Store artifacts
uses: actions/upload-artifact@v2
uses: actions/upload-artifact@v3
if: failure()
with:
name: ${{ matrix.os }}-${{ matrix.node-version }}-artifacts

View File

@ -1,5 +1,4 @@
.eslintignore
.eslintrc
.eslintrc.cjs
.github
.gitignore
.travis.yml

View File

@ -1,4 +0,0 @@
module.exports = {
arrowParens: 'avoid',
singleQuote: true,
};

4
.prettierrc.json Normal file
View File

@ -0,0 +1,4 @@
{
"arrowParens": "avoid",
"singleQuote": true
}

19
.vscode/launch.json vendored
View File

@ -7,18 +7,18 @@
{
"type": "node",
"request": "launch",
"name": "Run tests",
"name": "Run unit tests",
"runtimeExecutable": "npm",
"runtimeArgs": ["run-script", "test"],
"runtimeArgs": ["test"],
"console": "integratedTerminal"
},
{
"type": "node",
"request": "launch",
"name": "Run current test file",
"runtimeExecutable": "npm",
"runtimeArgs": ["run-script", "test"],
"args": ["--", "-i", "${relativeFile}", "--testPathIgnorePatterns"],
"runtimeExecutable": "npx",
"runtimeArgs": ["jest"],
"args": ["-i", "${relativeFile}", "--testPathIgnorePatterns"],
"console": "integratedTerminal"
},
{
@ -41,10 +41,9 @@
"type": "node",
"request": "launch",
"name": "Update current test file snapshot(s)",
"runtimeExecutable": "npm",
"runtimeArgs": ["run-script", "test"],
"runtimeExecutable": "npx",
"runtimeArgs": ["jest"],
"args": [
"--",
"-i",
"${relativeFile}",
"--updateSnapshot",
@ -56,8 +55,8 @@
"type": "node",
"request": "launch",
"name": "Update selected test name snapshot(s)",
"runtimeExecutable": "npm",
"runtimeArgs": ["run-script", "test"],
"runtimeExecutable": "npx",
"runtimeArgs": ["jest"],
"args": [
"--",
"-i",

View File

@ -4,7 +4,8 @@
First, thank you for considering contributing to docsify! It's people like you that make the open source community such a great community! 😊
We welcome any type of contribution, not only code. You can help with
We welcome any type of contribution, not only code. You can help with
- **QA**: file bug reports, the more details you can give the better (e.g. screenshots with the console open)
- **Marketing**: writing blog posts, howto's, printing stickers, ...
- **Community**: presenting the project at meetups, organizing a dedicated meetup for the local community, ...
@ -13,12 +14,50 @@ We welcome any type of contribution, not only code. You can help with
## Your First Contribution
Working on your first Pull Request? You can learn how from this *free* series, [How to Contribute to an Open Source Project on GitHub](https://app.egghead.io/playlists/how-to-contribute-to-an-open-source-project-on-github).
Working on your first Pull Request ever? You can learn how from this _free_ series, [How to Contribute to an Open Source Project on GitHub](https://app.egghead.io/playlists/how-to-contribute-to-an-open-source-project-on-github).
## Online one-click setup for Contributing
You can use Gitpod (a free online VS Code-like IDE) for contributing. With a single click it'll launch a workspace and automatically:
- clone the docsify repo.
- install the dependencies.
- start `npm run dev`.
```bash
npm install && npm run dev
```
So that you can start straight away.
[![Open in Gitpod](https://gitpod.io/button/open-in-gitpod.svg)](https://gitpod.io/#https://github.com/docsifyjs/docsify)
- Fork it!
- Create your feature branch: `git checkout -b my-new-feature`
- Commit your changes: `git add . && git commit -m 'Add some feature'`
- Push to the branch: `git push origin my-new-feature`
- Submit a pull request
## Submitting code
Any code change should be submitted as a pull request. The description should explain what the code does and give steps to execute it. The pull request should also contain tests.
## Testing
Ensure that things work by running:
```sh
npm test
```
## Test Snapshots
If a snapshot fails, or to add new snapshots, run:
```sh
npx jest --updateSnapshot
```
## Code review process
The bigger the pull request, the longer it will take to review and merge. Try to break down large pull requests in smaller chunks that are easier to review and merge.
@ -41,14 +80,12 @@ You can also reach us at hello@docsify.opencollective.com.
Thank you to all the people who have already contributed to docsify!
<a href="graphs/contributors"><img src="https://opencollective.com/docsify/contributors.svg?width=890" /></a>
### Backers
Thank you to all our backers! [[Become a backer](https://opencollective.com/docsify#backer)]
<a href="https://opencollective.com/docsify#backers" target="_blank"><img src="https://opencollective.com/docsify/backers.svg?width=890"></a>
### Sponsors
Thank you to all our sponsors! (please ask your company to also support this open source project by [becoming a sponsor](https://opencollective.com/docsify#sponsor))

View File

@ -32,7 +32,10 @@
- [`develop` branch preview](https://docsify-preview.vercel.app/)
- [Documentation](https://docsify.js.org)
- [CLI](https://github.com/docsifyjs/docsify-cli)
- CDN: [UNPKG](https://unpkg.com/docsify/) | [jsDelivr](https://cdn.jsdelivr.net/npm/docsify/) | [cdnjs](https://cdnjs.com/libraries/docsify)
- CDN:
- [UNPKG](https://unpkg.com/docsify/)
- [jsDelivr](https://cdn.jsdelivr.net/npm/docsify/)
- [cdnjs](https://cdnjs.com/libraries/docsify)
- [Awesome docsify](https://github.com/docsifyjs/awesome-docsify)
- [Community chat](https://discord.gg/3NwKFyR)
@ -44,7 +47,6 @@
- Multiple themes
- Useful plugin API
- Compatible with IE11
- Experimental SSR support ([example](https://github.com/docsifyjs/docsify-ssr-demo))
- Support embedded files
## Quick start
@ -63,34 +65,14 @@ Move to [awesome-docsify](https://github.com/docsifyjs/awesome-docsify#showcase)
| Project | Description |
| ------------------------------------------------ | ---------------------------------------- |
| [docute](https://github.com/egoist/docute) | 📜 Effortlessly documentation done right |
| [docpress](https://github.com/docpress/docpress) | Documentation website generator |
| [Docusaurus](https://docusaurus.io) | Docusaurus makes it easy to maintain Open Source documentation websites |
| [GitBook](https://www.gitbook.com) | Where technical teams document |
| [MkDocs](https://www.mkdocs.org) | Project documentation with Markdown |
| [VuePress](https://vuepress.vuejs.org) | Vue-powered Static Site Generator |
## Contributing
### Online one-click setup for Contributing
You can use Gitpod (a free online VS Code-like IDE) for contributing. With a single click it'll launch a workspace and automatically:
- clone the docsify repo.
- install the dependencies.
- start `npm run dev`.
So that you can start straight away.
[![Open in Gitpod](https://gitpod.io/button/open-in-gitpod.svg)](https://gitpod.io/#https://github.com/docsifyjs/docsify)
- Fork it!
- Create your feature branch: `git checkout -b my-new-feature`
- Commit your changes: `git add . && git commit -m 'Add some feature'`
- Push to the branch: `git push origin my-new-feature`
- Submit a pull request
## Development
```bash
npm run bootstrap && npm run dev
```
See [CONTRIBUTING.md](./CONTRIBUTING.md).
## Backers

View File

@ -1,12 +0,0 @@
module.exports = {
presets: [
[
'@babel/preset-env',
{
targets: {
node: 'current',
},
},
],
],
};

12
babel.config.json Normal file
View File

@ -0,0 +1,12 @@
{
"presets": [
[
"@babel/preset-env",
{
"targets": {
"node": "current"
}
}
]
]
}

View File

@ -1,13 +1,18 @@
const rollup = require('rollup')
const buble = require('rollup-plugin-buble')
const commonjs = require('rollup-plugin-commonjs')
const nodeResolve = require('rollup-plugin-node-resolve')
const { uglify } = require('rollup-plugin-uglify')
const replace = require('rollup-plugin-replace')
const isProd = process.env.NODE_ENV === 'production'
const version = process.env.VERSION || require('../package.json').version
const chokidar = require('chokidar')
const path = require('path')
import * as rollup from 'rollup';
import commonjs from '@rollup/plugin-commonjs';
import nodeResolve from '@rollup/plugin-node-resolve';
import uglify from '@rollup/plugin-terser';
import replace from '@rollup/plugin-replace';
import chokidar from 'chokidar';
import path from 'path';
import { relative } from './util.js';
import { promises as fs } from 'fs';
const pkgPath = relative(import.meta, '..', 'package.json');
const pkgString = (await fs.readFile(pkgPath)).toString();
const pkg = JSON.parse(pkgString);
const isProd = process.env.NODE_ENV === 'production';
const version = process.env.VERSION || pkg.version;
/**
* @param {{
@ -22,15 +27,10 @@ async function build(opts) {
.rollup({
input: opts.input,
plugins: (opts.plugins || []).concat([
buble({
transforms: {
dangerousForOf: true
}}),
commonjs(),
nodeResolve(),
replace({
__VERSION__: version,
'process.env.SSR': false
})
]),
onwarn: function (message) {
@ -80,6 +80,7 @@ async function buildAllPlugin() {
var plugins = [
{name: 'search', input: 'search/index.js'},
{name: 'ga', input: 'ga.js'},
{name: 'gtag', input: 'gtag.js'},
{name: 'matomo', input: 'matomo.js'},
{name: 'emoji', input: 'emoji.js'},
{name: 'external-script', input: 'external-script.js'},

View File

@ -1,14 +1,17 @@
var fs = require('fs')
var read = fs.readFileSync
var write = fs.writeFileSync
var version = process.env.VERSION || require('../package.json').version
import fs from 'fs';
import { relative } from './util.js';
var read = fs.readFileSync;
var write = fs.writeFileSync;
const pkgPath = relative(import.meta, '..', 'package.json');
const pkg = JSON.parse(read(pkgPath).toString());
var version = process.env.VERSION || pkg.version;
var file = __dirname + '/../docs/_coverpage.md'
var cover = read(file, 'utf8').toString()
var file = relative(import.meta, '..', 'docs', '_coverpage.md');
var cover = read(file, 'utf8').toString();
console.log('Replace version number in cover page...')
console.log('Replace version number in cover page...');
cover = cover.replace(
/<small>(\S+)?<\/small>/g,
'<small>' + version + '</small>'
)
write(file, cover)
);
write(file, cover);

View File

@ -1,9 +1,10 @@
const fs = require('fs')
const path = require('path')
const {spawn} = require('child_process')
import fs from 'fs'
import path from 'path'
import {spawn} from 'child_process'
const relative = path => new URL(path, import.meta.url);
const args = process.argv.slice(2)
fs.readdir(path.join(__dirname, '../src/themes'), (err, files) => {
fs.readdir(relative('../src/themes'), (err, files) => {
if (err) {
console.error('err', err)
process.exit(1)

View File

@ -1,6 +1,6 @@
const axios = require('axios');
const fs = require('fs');
const path = require('path');
import axios from 'axios';
import fs from 'fs';
import path from 'path';
const filePaths = {
emojiMarkdown: path.resolve(process.cwd(), 'docs', 'emoji.md'),

View File

@ -1,12 +1,12 @@
const cssnano = require('cssnano').process
const path = require('path')
const fs = require('fs')
import cssnano from 'cssnano';
import path from 'path'
import fs from 'fs'
files = fs.readdirSync(path.resolve('lib/themes'))
const files = fs.readdirSync(path.resolve('lib/themes'))
files.forEach(file => {
file = path.resolve('lib/themes', file)
cssnano(fs.readFileSync(file)).then(result => {
cssnano.process(fs.readFileSync(file)).then(result => {
fs.writeFileSync(file, result.css)
}).catch(e => {
console.error(e)

View File

@ -12,22 +12,11 @@ echo
if [[ $REPLY =~ ^[Yy]$ ]]; then
echo "Releasing $VERSION ..."
# Removing test script as non - availibity of tests. Will Add it once tests are completed
# npm run test
# build
VERSION=$VERSION npm run build
# update packages
cd packages/docsify-server-renderer
npm version $VERSION
if [[ -z $RELEASE_TAG ]]; then
npm publish
else
npm publish --tag $RELEASE_TAG
fi
cd -
# TODO
# npm test
# commit
git add -A

View File

@ -1,35 +0,0 @@
var rollup = require('rollup')
var buble = require('rollup-plugin-buble')
var async = require('rollup-plugin-async')
var replace = require('rollup-plugin-replace')
rollup
.rollup({
input: 'packages/docsify-server-renderer/index.js',
plugins: [
async(),
replace({
__VERSION__: process.env.VERSION || require('../package.json').version,
'process.env.SSR': true
}),
buble({
transforms: {
generator: false
}
})
],
onwarn: function () {}
})
.then(function (bundle) {
var dest = 'packages/docsify-server-renderer/build.js'
console.log(dest)
return bundle.write({
format: 'cjs',
file: dest
})
})
.catch(function (err) {
console.error(err)
process.exit(1)
})

6
build/util.js Normal file
View File

@ -0,0 +1,6 @@
import url from 'url';
import path from 'path';
/** Get a new path relative to the current module (pass import.meta). */
export const relative = (meta, ...to) =>
path.resolve(path.dirname(url.fileURLToPath(meta.url)), ...to);

View File

@ -17,7 +17,6 @@ See the [Quick start](quickstart.md) guide for more details.
- Useful plugin API
- Emoji support
- Compatible with IE11
- Support server-side rendering ([example](https://github.com/docsifyjs/docsify-ssr-demo))
## Examples

View File

@ -22,7 +22,6 @@
- [Vue compatibility](vue.md)
- [CDN](cdn.md)
- [Offline Mode (PWA)](pwa.md)
- [Server-Side Rendering (SSR)](ssr.md)
- [Embed Files](embed-files.md)
- [Awesome docsify](awesome.md)

View File

@ -34,6 +34,8 @@ Below is a complete list of emoji shorthand codes. Docsify can be configured to
:accept: `:accept:`
:accessibility: `:accessibility:`
:accordion: `:accordion:`
:adhesive_bandage: `:adhesive_bandage:`
@ -920,6 +922,8 @@ Below is a complete list of emoji shorthand codes. Docsify can be configured to
:department_store: `:department_store:`
:dependabot: `:dependabot:`
:derelict_house: `:derelict_house:`
:desert: `:desert:`
@ -1238,6 +1242,8 @@ Below is a complete list of emoji shorthand codes. Docsify can be configured to
:fishing_pole_and_fish: `:fishing_pole_and_fish:`
:fishsticks: `:fishsticks:`
:fist: `:fist:`
:fist_left: `:fist_left:`

View File

@ -71,6 +71,8 @@ This plugin ignores diacritical marks when performing a full text search (e.g.,
## Google Analytics
> Google's Universal Analytics service will no longer process new data in standard properties beginning July 1, 2023. Prepare now by setting up and switching over to a Google Analytics 4 property and docsify's gtag.js plugin.
Install the plugin and configure the track id.
```html
@ -91,6 +93,31 @@ Configure by `data-ga`.
<script src="//cdn.jsdelivr.net/npm/docsify/lib/plugins/ga.min.js"></script>
```
## Google Analytics 4 (GA4)
Install the plugin and configure the track id.
```html
<script>
// Single ID
window.$docsify = {
gtag: 'UA-XXXXX-Y',
};
// Multiple IDs
window.$docsify = {
gtag: [
'G-XXXXXXXX', // Google Analytics 4 (GA4)
'UA-XXXXXXXX', // Google Universal Analytics (GA3)
'AW-XXXXXXXX', // Google Ads
'DC-XXXXXXXX', // Floodlight
],
};
</script>
<script src="//cdn.jsdelivr.net/npm/docsify/lib/docsify.min.js"></script>
<script src="//cdn.jsdelivr.net/npm/docsify/lib/plugins/gtag.min.js"></script>
```
## Emoji
Renders a larger collection of emoji shorthand codes. Without this plugin, Docsify is able to render only a limited number of emoji shorthand codes.

View File

@ -1,131 +0,0 @@
# Server-Side Rendering
!> :construction: SSR support is experimental and incomplete. We are working on it. Plugins and
some features of Docsify will not work in SSR mode yet. :construction:
<!--
This link is dead.
See https://docsify.now.sh
-->
Sample repo at https://github.com/docsifyjs/docsify-ssr-demo
## Why SSR?
- Better SEO
- Feeling cool
## Quick start
Install `now` and `docsify-cli` in your project.
```bash
npm i now docsify-cli -D
```
Edit `package.json`. The below assumes the documentation is in the `./docs` subdirectory.
```json
{
"name": "my-project",
"scripts": {
"start": "docsify start . -c ssr.config.js",
"deploy": "now -p"
},
"files": [
"docs"
],
"docsify": {
"config": {
"basePath": "https://docsify.js.org/",
"loadSidebar": true,
"loadNavbar": true,
"coverpage": true,
"name": "docsify"
}
}
}
```
!> The `basePath` just like webpack `publicPath`. We can use local or remote files.
We can preview the local site to see if it works.
```bash
npm start
# open http://localhost:4000
```
Publish it!
```bash
now -p
```
Now, you have support for SSR.
## Custom template
You can provide a template for an entire page's HTML, such as
```html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>docsify</title>
<meta name="viewport" content="width=device-width, initial-scale=1.0, minimum-scale=1.0">
<link rel="stylesheet" href="//cdn.jsdelivr.net/npm/docsify/themes/vue.css" title="vue">
</head>
<body>
<!--inject-app-->
<!--inject-config-->
<script src="//cdn.jsdelivr.net/npm/docsify/lib/docsify.js"></script>
<script src="//cdn.jsdelivr.net/npm/docsify/lib/plugins/search.js"></script>
<script src="//cdn.jsdelivr.net/npm/prismjs/components/prism-bash.min.js"></script>
<script src="//cdn.jsdelivr.net/npm/prismjs/components/prism-markdown.min.js"></script>
<script src="//cdn.jsdelivr.net/npm/prismjs/components/prism-nginx.min.js"></script>
</body>
</html>
```
The template should contain these comments for rendered app content.
- `<!--inject-app-->`
- `<!--inject-config-->`
## Configuration
You can configure it in a special config file, or `package.json`.
```js
module.exports = {
template: './ssr.html',
maxAge: 60 * 60 * 1000, // lru-cache config
config: {
// docsify config
}
}
```
## Deploy for your VPS
You can run `docsify start` directly on your Node server, or write your own server app with `docsify-server-renderer`.
```js
var Renderer = require('docsify-server-renderer')
var readFileSync = require('fs').readFileSync
// init
var renderer = new Renderer({
template: readFileSync('./docs/index.template.html', 'utf-8'),
config: {
name: 'docsify',
repo: 'docsifyjs/docsify'
}
})
renderer.renderToString(url)
.then(html => {})
.catch(err => {})
```

View File

@ -1,4 +1,4 @@
const { TEST_HOST } = require('./test/config/server.js');
import { TEST_HOST } from './test/config/server.js';
const sharedConfig = {
errorOnDeprecated: true,
@ -11,7 +11,8 @@ const sharedConfig = {
testURL: `${TEST_HOST}/_blank.html`,
};
module.exports = {
export default {
transform: {},
projects: [
// Unit Tests
{

View File

@ -1,7 +0,0 @@
{
"lerna": "2.0.0-rc.5",
"packages": [
"packages/*"
],
"version": "0.0.0"
}

19980
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -2,35 +2,35 @@
"name": "docsify",
"version": "4.13.0",
"description": "A magical documentation generator.",
"author": {
"name": "qingwei-li",
"email": "cinwell.li@gmail.com",
"url": "https://github.com/QingWei-Li"
},
"homepage": "https://docsify.js.org",
"repository": "github:docsifyjs/docsify",
"authors": "https://github.com/docsifyjs/docsify/graphs/contributors",
"license": "MIT",
"repository": {
"type": "git",
"url": "git+https://github.com/docsifyjs/docsify.git"
"collective": {
"url": "https://opencollective.com/docsify"
},
"type": "module",
"// The 'main' and 'unpkg' fields will remain as legacy for backwards compatbility for now. We will add deprectaion warnings to these outputs to give people time to see the warnings in their apps in a non-breaking way, and eventually we can remove the legacy stuff.": "",
"main": "lib/docsify.js",
"unpkg": "lib/docsify.min.js",
"// We're using the 'exports' field as an override of the 'main' field to provide the new ESM setup. Once we remove legacy 'main', we will remove the 'exports' field and have a simple ESM setup with only a 'main' field.": "",
"exports": {
".": "./src/Docsify.js",
"./*": "./*"
},
"files": [
"lib",
"themes"
],
"scripts": {
"bootstrap": "npm i && lerna bootstrap && npm run build:ssr",
"build:cover": "node build/cover.js",
"build:css:min": "mkdirp lib/themes && npm run css -- -o lib/themes && node build/mincss.js",
"build:css": "mkdirp themes && npm run css -- -o themes",
"build:emoji": "node ./build/emoji.js",
"build:js": "cross-env NODE_ENV=production node build/build.js",
"build:ssr": "node build/ssr.js",
"build:test": "npm run build && npm test",
"build": "rimraf lib themes && run-s build:js build:css build:css:min build:ssr build:cover build:emoji",
"build": "rimraf lib themes && run-s build:js build:css build:css:min build:cover build:emoji",
"css": "node build/css",
"dev:ssr": "run-p serve:ssr watch:*",
"dev": "run-p serve watch:*",
"docker:build:test": "npm run docker:cli -- build:test",
"docker:build": "docker build -f Dockerfile -t docsify-test:local .",
@ -47,12 +47,12 @@
"prepare": "npm run build",
"pub:next": "cross-env RELEASE_TAG=next sh build/release.sh",
"pub": "sh build/release.sh",
"serve:ssr": "cross-env SSR=1 node server",
"serve": "node server",
"test:e2e": "playwright test",
"test:integration": "jest --selectProjects integration",
"test:unit": "jest --selectProjects unit",
"test": "jest && run-s test:e2e",
"test:integration": "npm run jest -- --selectProjects integration",
"test:unit": "npm run jest -- --selectProjects unit",
"test": "npm run jest && run-s test:e2e",
"jest": "cross-env NODE_OPTIONS=--experimental-vm-modules jest",
"watch:css": "npm run css -- -o themes -w",
"watch:js": "node build/build.js"
},
@ -65,7 +65,7 @@
"*.js": "eslint --fix"
},
"dependencies": {
"marked": "^1.2.9",
"marked": "^4.2.12",
"medium-zoom": "^1.0.8",
"opencollective-postinstall": "^2.0.2",
"prismjs": "^1.29.0",
@ -77,41 +77,41 @@
"@babel/core": "^7.11.6",
"@babel/eslint-parser": "^7.16.5",
"@babel/preset-env": "^7.11.5",
"@eslint/js": "^8.43.0",
"@playwright/test": "^1.18.1",
"@rollup/plugin-commonjs": "^25.0.2",
"@rollup/plugin-node-resolve": "^15.1.0",
"@rollup/plugin-replace": "^5.0.2",
"@rollup/plugin-terser": "^0.4.3",
"@types/eslint": "^8.40.2",
"autoprefixer-stylus": "^1.0.0",
"axios": "^0.21.1",
"babel-jest": "^27.4.6",
"browser-sync": "^2.26.12",
"chokidar": "^3.4.2",
"common-tags": "^1.8.0",
"conventional-changelog-cli": "^2.1.0",
"conventional-changelog-cli": "^3.0.0",
"copy-dir": "^1.2.0",
"cross-env": "^6.0.3",
"cross-env": "^7.0.3",
"cssnano": "^4.1.10",
"eslint": "^8.7.0",
"eslint-config-prettier": "^8.3.0",
"eslint-plugin-import": "^2.20.1",
"eslint-plugin-jest": "^26.0.0",
"eslint-plugin-playwright": "^0.8.0",
"eslint-plugin-prettier": "^4.0.0",
"husky": "^3.1.0",
"eslint": "^8.43.0",
"eslint-config-prettier": "^8.8.0",
"eslint-plugin-import": "^2.27.5",
"eslint-plugin-jest": "^27.2.2",
"eslint-plugin-playwright": "^0.15.1",
"eslint-plugin-prettier": "^4.2.1",
"globals": "^13.20.0",
"husky": "^8.0.3",
"jest": "^27.4.7",
"lerna": "^5.5.1",
"lint-staged": "^10.4.0",
"lint-staged": "^13.2.2",
"live-server": "^1.2.1",
"mkdirp": "^0.5.1",
"mkdirp": "^3.0.0",
"npm-run-all": "^4.1.5",
"prettier": "^2.5.1",
"prettier": "^2.8.8",
"rimraf": "^3.0.0",
"rollup": "^1.23.1",
"rollup-plugin-async": "^1.2.0",
"rollup-plugin-buble": "^0.19.8",
"rollup-plugin-commonjs": "^10.1.0",
"rollup-plugin-node-resolve": "^5.2.0",
"rollup-plugin-replace": "^2.2.0",
"rollup-plugin-uglify": "^6.0.4",
"rollup": "^3.25.3",
"serve-handler": "^6.1.2",
"stylus": "^0.54.5",
"stylus": "^0.59.0",
"vue2": "npm:vue@^2.6.12",
"vue3": "npm:vue@^3.0.0",
"xhr-mock": "^2.5.1"
@ -122,8 +122,5 @@
"documentation",
"creator",
"generator"
],
"collective": {
"url": "https://opencollective.com/docsify"
}
]
}

View File

@ -1,4 +0,0 @@
build.js
node_modules
*.log
.git

View File

@ -1,46 +0,0 @@
# docsify-server-renderer
## Install
```bash
yarn add docsify-server-renderer
```
## Usage
```js
var Renderer = require('docsify-server-renderer')
var readFileSync = require('fs').readFileSync
// init
var renderer = new Renderer({
template: readFileSync('./docs/index.template.html', 'utf-8'),
config: {
name: 'docsify',
repo: 'docsifyjs/docsify'
}
})
renderer.renderToString(url)
.then(html => {})
.catch(err => {})
```
*index.template.html*
```html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>docsify</title>
<meta name="viewport" content="width=device-width, initial-scale=1.0, minimum-scale=1.0">
<link rel="stylesheet" href="//cdn.jsdelivr.net/npm/docsify/themes/vue.css" title="vue">
</head>
<body>
<!--inject-app-->
<!--inject-config-->
<script src="//cdn.jsdelivr.net/npm/docsify/lib/docsify.js"></script>
</body>
</html>
```

View File

@ -1,212 +0,0 @@
import { readFileSync } from 'fs';
import { resolve, basename } from 'path';
import resolvePathname from 'resolve-pathname';
import fetch from 'node-fetch';
import debug from 'debug';
import { AbstractHistory } from '../../src/core/router/history/abstract';
import { Compiler } from '../../src/core/render/compiler';
import { isAbsolutePath } from '../../src/core/router/util';
import * as tpl from '../../src/core/render/tpl';
import { prerenderEmbed } from '../../src/core/render/embed';
function cwd(...args) {
return resolve(process.cwd(), ...args);
}
function isExternal(url) {
let match = url.match(
/^([^:/?#]+:)?(?:\/\/([^/?#]*))?([^?#]+)?(\?[^#]*)?(#.*)?/
);
if (
typeof match[1] === 'string' &&
match[1].length > 0 &&
match[1].toLowerCase() !== location.protocol
) {
return true;
}
if (
typeof match[2] === 'string' &&
match[2].length > 0 &&
match[2].replace(
new RegExp(
':(' + { 'http:': 80, 'https:': 443 }[location.protocol] + ')?$'
),
''
) !== location.host
) {
return true;
}
return false;
}
function mainTpl(config) {
let html = `<nav class="app-nav${
config.repo ? '' : ' no-badge'
}"><!--navbar--></nav>`;
if (config.repo) {
html += tpl.corner(config.repo);
}
if (config.coverpage) {
html += tpl.cover();
}
html += tpl.main(config);
return html;
}
export default class Renderer {
constructor({ template, config, cache }) {
this.html = template;
this.config = config = Object.assign({}, config, {
routerMode: 'history',
});
this.cache = cache;
this.router = new AbstractHistory(config);
this.compiler = new Compiler(config, this.router);
this.router.getCurrentPath = () => this.url;
this._renderHtml(
'inject-config',
`<script>window.$docsify = ${JSON.stringify(config)}</script>`
);
this._renderHtml('inject-app', mainTpl(config));
this.template = this.html;
}
_getPath(url) {
const file = this.router.getFile(url);
return isAbsolutePath(file) ? file : cwd(`./${file}`);
}
async renderToString(url) {
this.url = url = this.router.parse(url).path;
this.isRemoteUrl = isExternal(this.url);
const { loadSidebar, loadNavbar, coverpage } = this.config;
const mainFile = this._getPath(url);
this._renderHtml('main', await this._render(mainFile, 'main'));
if (loadSidebar) {
const name = loadSidebar === true ? '_sidebar.md' : loadSidebar;
const sidebarFile = this._getPath(resolve(url, `./${name}`));
this._renderHtml('sidebar', await this._render(sidebarFile, 'sidebar'));
}
if (loadNavbar) {
const name = loadNavbar === true ? '_navbar.md' : loadNavbar;
const navbarFile = this._getPath(resolve(url, `./${name}`));
this._renderHtml('navbar', await this._render(navbarFile, 'navbar'));
}
if (coverpage) {
let path = null;
if (typeof coverpage === 'string') {
if (url === '/') {
path = coverpage;
}
} else if (Array.isArray(coverpage)) {
path = coverpage.indexOf(url) > -1 && '_coverpage.md';
} else {
const cover = coverpage[url];
path = cover === true ? '_coverpage.md' : cover;
}
const coverFile = this._getPath(resolve(url, `./${path}`));
this._renderHtml('cover', await this._render(coverFile), 'cover');
}
const html = this.html;
this.html = this.template;
return html;
}
_renderHtml(match, content) {
this.html = this.html.replace(new RegExp(`<!--${match}-->`, 'g'), content);
return this.html;
}
async _render(path, type) {
let html = await this._loadFile(path);
const { subMaxLevel, maxLevel } = this.config;
let tokens;
switch (type) {
case 'sidebar':
html =
this.compiler.sidebar(html, maxLevel) +
`<script>window.__SUB_SIDEBAR__ = ${JSON.stringify(
this.compiler.subSidebar(subMaxLevel)
)}</script>`;
break;
case 'cover':
html = this.compiler.cover(html);
break;
case 'main':
tokens = await new Promise(r => {
prerenderEmbed(
{
fetch: url => this._loadFile(this._getPath(url)),
compiler: this.compiler,
raw: html,
},
r
);
});
html = this.compiler.compile(tokens);
break;
case 'navbar':
case 'article':
default:
html = this.compiler.compile(html);
break;
}
return html;
}
async _loadFile(filePath) {
debug('docsify')(`load > ${filePath}`);
let content;
try {
if (isAbsolutePath(filePath)) {
const res = await fetch(filePath);
if (!res.ok) {
throw Error();
}
content = await res.text();
this.lock = 0;
} else {
content = await readFileSync(filePath, 'utf8');
this.lock = 0;
}
return content;
} catch (e) {
this.lock = this.lock || 0;
if (++this.lock > 10) {
this.lock = 0;
return;
}
const fileName = basename(filePath);
const result = await this._loadFile(
resolvePathname(`../${fileName}`, filePath)
);
return result;
}
}
}
Renderer.version = '__VERSION__';

View File

@ -1,266 +0,0 @@
{
"name": "docsify-server-renderer",
"version": "4.13.0",
"lockfileVersion": 2,
"requires": true,
"packages": {
"": {
"name": "docsify-server-renderer",
"version": "4.13.0",
"license": "MIT",
"dependencies": {
"debug": "^4.3.4",
"docsify": "^4.13.0",
"node-fetch": "^2.6.9",
"resolve-pathname": "^3.0.0"
}
},
"node_modules/debug": {
"version": "4.3.4",
"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz",
"integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==",
"dependencies": {
"ms": "2.1.2"
},
"engines": {
"node": ">=6.0"
},
"peerDependenciesMeta": {
"supports-color": {
"optional": true
}
}
},
"node_modules/docsify": {
"version": "4.13.0",
"resolved": "https://registry.npmjs.org/docsify/-/docsify-4.13.0.tgz",
"integrity": "sha512-dM2D0LZKrhK9e5cPwzOTO8FJ2l9IxgiSmTgLBIMjkBlTs1rAUT5camzekbk2AhH0Tw+5lzkNrSb7dmKFuTiLCA==",
"hasInstallScript": true,
"dependencies": {
"marked": "^1.2.9",
"medium-zoom": "^1.0.6",
"opencollective-postinstall": "^2.0.2",
"prismjs": "^1.27.0",
"strip-indent": "^3.0.0",
"tinydate": "^1.3.0",
"tweezer.js": "^1.4.0"
}
},
"node_modules/marked": {
"version": "1.2.9",
"resolved": "https://registry.npmjs.org/marked/-/marked-1.2.9.tgz",
"integrity": "sha512-H8lIX2SvyitGX+TRdtS06m1jHMijKN/XjfH6Ooii9fvxMlh8QdqBfBDkGUpMWH2kQNrtixjzYUa3SH8ROTgRRw==",
"bin": {
"marked": "bin/marked"
},
"engines": {
"node": ">= 8.16.2"
}
},
"node_modules/medium-zoom": {
"version": "1.0.6",
"resolved": "https://registry.npmjs.org/medium-zoom/-/medium-zoom-1.0.6.tgz",
"integrity": "sha512-UdiUWfvz9fZMg1pzf4dcuqA0W079o0mpqbTnOz5ip4VGYX96QjmbM+OgOU/0uOzAytxC0Ny4z+VcYQnhdifimg=="
},
"node_modules/min-indent": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/min-indent/-/min-indent-1.0.1.tgz",
"integrity": "sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg==",
"engines": {
"node": ">=4"
}
},
"node_modules/ms": {
"version": "2.1.2",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
"integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w=="
},
"node_modules/node-fetch": {
"version": "2.6.9",
"resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.9.tgz",
"integrity": "sha512-DJm/CJkZkRjKKj4Zi4BsKVZh3ValV5IR5s7LVZnW+6YMh0W1BfNA8XSs6DLMGYlId5F3KnA70uu2qepcR08Qqg==",
"dependencies": {
"whatwg-url": "^5.0.0"
},
"engines": {
"node": "4.x || >=6.0.0"
},
"peerDependencies": {
"encoding": "^0.1.0"
},
"peerDependenciesMeta": {
"encoding": {
"optional": true
}
}
},
"node_modules/opencollective-postinstall": {
"version": "2.0.3",
"resolved": "https://registry.npmjs.org/opencollective-postinstall/-/opencollective-postinstall-2.0.3.tgz",
"integrity": "sha512-8AV/sCtuzUeTo8gQK5qDZzARrulB3egtLzFgteqB2tcT4Mw7B8Kt7JcDHmltjz6FOAHsvTevk70gZEbhM4ZS9Q==",
"bin": {
"opencollective-postinstall": "index.js"
}
},
"node_modules/prismjs": {
"version": "1.27.0",
"resolved": "https://registry.npmjs.org/prismjs/-/prismjs-1.27.0.tgz",
"integrity": "sha512-t13BGPUlFDR7wRB5kQDG4jjl7XeuH6jbJGt11JHPL96qwsEHNX2+68tFXqc1/k+/jALsbSWJKUOT/hcYAZ5LkA==",
"engines": {
"node": ">=6"
}
},
"node_modules/resolve-pathname": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/resolve-pathname/-/resolve-pathname-3.0.0.tgz",
"integrity": "sha512-C7rARubxI8bXFNB/hqcp/4iUeIXJhJZvFPFPiSPRnhU5UPxzMFIl+2E6yY6c4k9giDJAhtV+enfA+G89N6Csng=="
},
"node_modules/strip-indent": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/strip-indent/-/strip-indent-3.0.0.tgz",
"integrity": "sha512-laJTa3Jb+VQpaC6DseHhF7dXVqHTfJPCRDaEbid/drOhgitgYku/letMUqOXFoWV0zIIUbjpdH2t+tYj4bQMRQ==",
"dependencies": {
"min-indent": "^1.0.0"
},
"engines": {
"node": ">=8"
}
},
"node_modules/tinydate": {
"version": "1.3.0",
"resolved": "https://registry.npmjs.org/tinydate/-/tinydate-1.3.0.tgz",
"integrity": "sha512-7cR8rLy2QhYHpsBDBVYnnWXm8uRTr38RoZakFSW7Bs7PzfMPNZthuMLkwqZv7MTu8lhQ91cOFYS5a7iFj2oR3w==",
"engines": {
"node": ">=4"
}
},
"node_modules/tr46": {
"version": "0.0.3",
"resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz",
"integrity": "sha1-gYT9NH2snNwYWZLzpmIuFLnZq2o="
},
"node_modules/tweezer.js": {
"version": "1.5.0",
"resolved": "https://registry.npmjs.org/tweezer.js/-/tweezer.js-1.5.0.tgz",
"integrity": "sha512-aSiJz7rGWNAQq7hjMK9ZYDuEawXupcCWgl3woQQSoDP2Oh8O4srWb/uO1PzzHIsrPEOqrjJ2sUb9FERfzuBabQ=="
},
"node_modules/webidl-conversions": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz",
"integrity": "sha1-JFNCdeKnvGvnvIZhHMFq4KVlSHE="
},
"node_modules/whatwg-url": {
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz",
"integrity": "sha1-lmRU6HZUYuN2RNNib2dCzotwll0=",
"dependencies": {
"tr46": "~0.0.3",
"webidl-conversions": "^3.0.0"
}
}
},
"dependencies": {
"debug": {
"version": "4.3.4",
"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz",
"integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==",
"requires": {
"ms": "2.1.2"
}
},
"docsify": {
"version": "4.13.0",
"resolved": "https://registry.npmjs.org/docsify/-/docsify-4.13.0.tgz",
"integrity": "sha512-dM2D0LZKrhK9e5cPwzOTO8FJ2l9IxgiSmTgLBIMjkBlTs1rAUT5camzekbk2AhH0Tw+5lzkNrSb7dmKFuTiLCA==",
"requires": {
"marked": "^1.2.9",
"medium-zoom": "^1.0.6",
"opencollective-postinstall": "^2.0.2",
"prismjs": "^1.27.0",
"strip-indent": "^3.0.0",
"tinydate": "^1.3.0",
"tweezer.js": "^1.4.0"
}
},
"marked": {
"version": "1.2.9",
"resolved": "https://registry.npmjs.org/marked/-/marked-1.2.9.tgz",
"integrity": "sha512-H8lIX2SvyitGX+TRdtS06m1jHMijKN/XjfH6Ooii9fvxMlh8QdqBfBDkGUpMWH2kQNrtixjzYUa3SH8ROTgRRw=="
},
"medium-zoom": {
"version": "1.0.6",
"resolved": "https://registry.npmjs.org/medium-zoom/-/medium-zoom-1.0.6.tgz",
"integrity": "sha512-UdiUWfvz9fZMg1pzf4dcuqA0W079o0mpqbTnOz5ip4VGYX96QjmbM+OgOU/0uOzAytxC0Ny4z+VcYQnhdifimg=="
},
"min-indent": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/min-indent/-/min-indent-1.0.1.tgz",
"integrity": "sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg=="
},
"ms": {
"version": "2.1.2",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
"integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w=="
},
"node-fetch": {
"version": "2.6.9",
"resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.9.tgz",
"integrity": "sha512-DJm/CJkZkRjKKj4Zi4BsKVZh3ValV5IR5s7LVZnW+6YMh0W1BfNA8XSs6DLMGYlId5F3KnA70uu2qepcR08Qqg==",
"requires": {
"whatwg-url": "^5.0.0"
}
},
"opencollective-postinstall": {
"version": "2.0.3",
"resolved": "https://registry.npmjs.org/opencollective-postinstall/-/opencollective-postinstall-2.0.3.tgz",
"integrity": "sha512-8AV/sCtuzUeTo8gQK5qDZzARrulB3egtLzFgteqB2tcT4Mw7B8Kt7JcDHmltjz6FOAHsvTevk70gZEbhM4ZS9Q=="
},
"prismjs": {
"version": "1.27.0",
"resolved": "https://registry.npmjs.org/prismjs/-/prismjs-1.27.0.tgz",
"integrity": "sha512-t13BGPUlFDR7wRB5kQDG4jjl7XeuH6jbJGt11JHPL96qwsEHNX2+68tFXqc1/k+/jALsbSWJKUOT/hcYAZ5LkA=="
},
"resolve-pathname": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/resolve-pathname/-/resolve-pathname-3.0.0.tgz",
"integrity": "sha512-C7rARubxI8bXFNB/hqcp/4iUeIXJhJZvFPFPiSPRnhU5UPxzMFIl+2E6yY6c4k9giDJAhtV+enfA+G89N6Csng=="
},
"strip-indent": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/strip-indent/-/strip-indent-3.0.0.tgz",
"integrity": "sha512-laJTa3Jb+VQpaC6DseHhF7dXVqHTfJPCRDaEbid/drOhgitgYku/letMUqOXFoWV0zIIUbjpdH2t+tYj4bQMRQ==",
"requires": {
"min-indent": "^1.0.0"
}
},
"tinydate": {
"version": "1.3.0",
"resolved": "https://registry.npmjs.org/tinydate/-/tinydate-1.3.0.tgz",
"integrity": "sha512-7cR8rLy2QhYHpsBDBVYnnWXm8uRTr38RoZakFSW7Bs7PzfMPNZthuMLkwqZv7MTu8lhQ91cOFYS5a7iFj2oR3w=="
},
"tr46": {
"version": "0.0.3",
"resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz",
"integrity": "sha1-gYT9NH2snNwYWZLzpmIuFLnZq2o="
},
"tweezer.js": {
"version": "1.5.0",
"resolved": "https://registry.npmjs.org/tweezer.js/-/tweezer.js-1.5.0.tgz",
"integrity": "sha512-aSiJz7rGWNAQq7hjMK9ZYDuEawXupcCWgl3woQQSoDP2Oh8O4srWb/uO1PzzHIsrPEOqrjJ2sUb9FERfzuBabQ=="
},
"webidl-conversions": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz",
"integrity": "sha1-JFNCdeKnvGvnvIZhHMFq4KVlSHE="
},
"whatwg-url": {
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz",
"integrity": "sha1-lmRU6HZUYuN2RNNib2dCzotwll0=",
"requires": {
"tr46": "~0.0.3",
"webidl-conversions": "^3.0.0"
}
}
}
}

View File

@ -1,23 +0,0 @@
{
"name": "docsify-server-renderer",
"version": "4.13.0",
"description": "docsify server renderer",
"author": {
"name": "qingwei-li",
"email": "cinwell.li@gmail.com",
"url": "https://github.com/QingWei-Li"
},
"homepage": "https://docsify.js.org",
"license": "MIT",
"repository": "docsifyjs/docsify",
"main": "build.js",
"scripts": {
"test": "echo 'hello'"
},
"dependencies": {
"debug": "^4.3.4",
"docsify": "^4.13.0",
"node-fetch": "^2.6.9",
"resolve-pathname": "^3.0.0"
}
}

View File

@ -1,4 +1,4 @@
const { devices } = require('@playwright/test');
import { devices } from '@playwright/test';
/**
* @see https://playwright.dev/docs/test-configuration
@ -61,4 +61,4 @@ const config = {
],
};
module.exports = config;
export default config;

View File

@ -1,4 +0,0 @@
{
"template": "node",
"node": "16"
}

View File

@ -1,55 +1,10 @@
const liveServer = require('live-server')
const isSSR = !!process.env.SSR
const middleware = []
if (isSSR) {
const Renderer = require('./packages/docsify-server-renderer/build.js')
const renderer = new Renderer({
template: `
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>docsify</title>
<meta name="viewport" content="width=device-width, initial-scale=1.0, minimum-scale=1.0">
<link rel="stylesheet" href="/themes/vue.css" title="vue">
</head>
<body>
<!--inject-app-->
<!--inject-config-->
<script src="/lib/docsify.js"></script>
</body>
</html>`,
config: {
name: 'docsify',
repo: 'docsifyjs/docsify',
basePath: 'https://docsify.js.org/',
loadNavbar: true,
loadSidebar: true,
subMaxLevel: 3,
auto2top: true,
alias: {
'/de-de/changelog': '/changelog',
'/zh-cn/changelog': '/changelog',
'/changelog':
'https://raw.githubusercontent.com/docsifyjs/docsify/master/CHANGELOG'
}
},
path: './'
})
middleware.push(function(req, res, next) {
if (/\.(css|js)$/.test(req.url)) {
return next()
}
renderer.renderToString(req.url).then(html => res.end(html))
})
}
import liveServer from 'live-server';
const middleware = [];
const params = {
port: 3000,
watch: ['lib', 'docs', 'themes'],
middleware
}
middleware,
};
liveServer.start(params)
liveServer.start(params);

View File

@ -6,8 +6,8 @@ import { VirtualRoutes } from './virtual-routes/index.js';
import initGlobalAPI from './global-api.js';
import config from './config.js';
import { isFn } from './util/core';
import { Lifecycle } from './init/lifecycle';
import { isFn } from './util/core.js';
import { Lifecycle } from './init/lifecycle.js';
/** @typedef {new (...args: any[]) => any} Constructor */

View File

@ -1,4 +1,4 @@
import { merge, hyphenate, isPrimitive, hasOwn } from './util/core';
import { merge, hyphenate, isPrimitive, hasOwn } from './util/core.js';
const currentScript = document.currentScript;

View File

@ -1,7 +1,7 @@
import { isMobile } from '../util/env';
import { body, on } from '../util/dom';
import * as sidebar from './sidebar';
import { scrollIntoView, scroll2Top } from './scroll';
import { isMobile } from '../util/env.js';
import { body, on } from '../util/dom.js';
import * as sidebar from './sidebar.js';
import { scrollIntoView, scroll2Top } from './scroll.js';
/** @typedef {import('../Docsify').Constructor} Constructor */

View File

@ -1,8 +1,8 @@
import Tweezer from 'tweezer.js';
import { isMobile } from '../util/env';
import * as dom from '../util/dom';
import { removeParams } from '../router/util';
import config from '../config';
import { isMobile } from '../util/env.js';
import * as dom from '../util/dom.js';
import { removeParams } from '../router/util.js';
import config from '../config.js';
const nav = {};
let hoverOver = false;
@ -147,7 +147,9 @@ export function scrollIntoView(path, id) {
return;
}
const topMargin = config().topMargin;
const section = dom.find('#' + id);
// Use [id='1234'] instead of #id to handle special cases such as reserved characters and pure number id
// https://stackoverflow.com/questions/37270787/uncaught-syntaxerror-failed-to-execute-queryselector-on-document
const section = dom.find("[id='" + id + "']");
section && scrollTo(section, topMargin);
const li = nav[getNavKey(path, id)];

View File

@ -1,6 +1,6 @@
/* eslint-disable no-unused-vars */
import { isMobile } from '../util/env';
import * as dom from '../util/dom';
import { isMobile } from '../util/env.js';
import * as dom from '../util/dom.js';
const title = dom.$.title;
/**

View File

@ -1,6 +1,6 @@
/* eslint-disable no-unused-vars */
import progressbar from '../render/progressbar';
import { noop, hasOwn } from '../util/core';
import progressbar from '../render/progressbar.js';
import { noop, hasOwn } from '../util/core.js';
const cache = {};

View File

@ -1,8 +1,8 @@
/* eslint-disable no-unused-vars */
import { getParentPath, stringifyQuery } from '../router/util';
import { noop, isExternal } from '../util/core';
import { getAndActive } from '../event/sidebar';
import { get } from './ajax';
import { getParentPath, stringifyQuery } from '../router/util.js';
import { noop, isExternal } from '../util/core.js';
import { getAndActive } from '../event/sidebar.js';
import { get } from './ajax.js';
function loadNested(path, qs, file, next, vm, first) {
path = first ? path : path.replace(/\/$/, '');

View File

@ -1,10 +1,10 @@
import prism from 'prismjs';
import marked from 'marked';
import * as util from './util';
import * as dom from './util/dom';
import { Compiler } from './render/compiler';
import { slugify } from './render/slugify';
import { get } from './fetch/ajax';
import { marked } from 'marked';
import * as util from './util/index.js';
import * as dom from './util/dom.js';
import { Compiler } from './render/compiler.js';
import { slugify } from './render/slugify.js';
import { get } from './fetch/ajax.js';
// TODO This is deprecated, kept for backwards compatibility. Remove in next
// major release. We'll tell people to get everything from the DOCSIFY global

View File

@ -1,5 +1,5 @@
import { documentReady } from './util/dom';
import { Docsify } from './Docsify';
import { documentReady } from './util/dom.js';
import { Docsify } from './Docsify.js';
/**
* Run Docsify

View File

@ -1,4 +1,4 @@
import { noop } from '../util/core';
import { noop } from '../util/core.js';
/** @typedef {import('../Docsify').Constructor} Constructor */

View File

@ -1,21 +1,21 @@
import marked from 'marked';
import { isAbsolutePath, getPath, getParentPath } from '../router/util';
import { isFn, merge, cached, isPrimitive } from '../util/core';
import { tree as treeTpl } from './tpl';
import { genTree } from './gen-tree';
import { slugify } from './slugify';
import { emojify } from './emojify';
import { marked } from 'marked';
import { isAbsolutePath, getPath, getParentPath } from '../router/util.js';
import { isFn, merge, cached, isPrimitive } from '../util/core.js';
import { tree as treeTpl } from './tpl.js';
import { genTree } from './gen-tree.js';
import { slugify } from './slugify.js';
import { emojify } from './emojify.js';
import {
getAndRemoveConfig,
removeAtag,
getAndRemoveDocisfyIgnorConfig,
} from './utils';
import { imageCompiler } from './compiler/image';
import { highlightCodeCompiler } from './compiler/code';
import { paragraphCompiler } from './compiler/paragraph';
import { taskListCompiler } from './compiler/taskList';
import { taskListItemCompiler } from './compiler/taskListItem';
import { linkCompiler } from './compiler/link';
} from './utils.js';
import { imageCompiler } from './compiler/image.js';
import { highlightCodeCompiler } from './compiler/code.js';
import { paragraphCompiler } from './compiler/paragraph.js';
import { taskListCompiler } from './compiler/taskList.js';
import { taskListItemCompiler } from './compiler/taskListItem.js';
import { linkCompiler } from './compiler/link.js';
const cachedLinks = {};
@ -149,7 +149,7 @@ export class Compiler {
if (config.include) {
if (!isAbsolutePath(href)) {
href = getPath(
process.env.SSR ? '' : this.contentBase,
this.contentBase,
getParentPath(this.router.getCurrentPath()),
href
);

View File

@ -1,6 +1,6 @@
import Prism from 'prismjs';
// See https://github.com/PrismJS/prism/pull/1367
import 'prismjs/components/prism-markup-templating';
import 'prismjs/components/prism-markup-templating.js';
export const highlightCodeCompiler = ({ renderer }) =>
(renderer.code = function (code, lang = 'markup') {

View File

@ -2,8 +2,8 @@ import {
getAndRemoveConfig,
removeAtag,
getAndRemoveDocisfyIgnorConfig,
} from '../utils';
import { slugify } from './slugify';
} from '../utils.js';
import { slugify } from './slugify.js';
export const headingCompiler = ({ renderer, router, _self }) =>
(renderer.code = (text, level) => {

View File

@ -1,5 +1,5 @@
import { getAndRemoveConfig } from '../utils';
import { isAbsolutePath, getPath, getParentPath } from '../../router/util';
import { getAndRemoveConfig } from '../utils.js';
import { isAbsolutePath, getPath, getParentPath } from '../../router/util.js';
export const imageCompiler = ({ renderer, contentBase, router }) =>
(renderer.image = (href, title, text) => {

View File

@ -1,5 +1,5 @@
import { getAndRemoveConfig } from '../utils';
import { isAbsolutePath } from '../../router/util';
import { getAndRemoveConfig } from '../utils.js';
import { isAbsolutePath } from '../../router/util.js';
export const linkCompiler = ({
renderer,

View File

@ -1,4 +1,4 @@
import { helper as helperTpl } from '../tpl';
import { helper as helperTpl } from '../tpl.js';
export const paragraphCompiler = ({ renderer }) =>
(renderer.paragraph = text => {

View File

@ -1,13 +1,13 @@
import stripIndent from 'strip-indent';
import { get } from '../fetch/ajax';
import { merge } from '../util/core';
import { get } from '../fetch/ajax.js';
import { merge } from '../util/core.js';
const cached = {};
function walkFetchEmbed({ embedTokens, compile, fetch }, cb) {
let token;
let step = 0;
let count = 1;
let count = 0;
if (!embedTokens.length) {
return cb({});
@ -73,18 +73,14 @@ function walkFetchEmbed({ embedTokens, compile, fetch }, cb) {
}
cb({ token, embedToken });
if (++count >= step) {
if (++count >= embedTokens.length) {
cb({});
}
};
})(token);
if (token.embed.url) {
if (process.env.SSR) {
fetch(token.embed.url).then(next);
} else {
get(token.embed.url).then(next);
}
get(token.embed.url).then(next);
} else {
next(token.embed.html);
}

View File

@ -21,6 +21,7 @@ export default {
"abc": "unicode/1f524.png?v8",
"abcd": "unicode/1f521.png?v8",
"accept": "unicode/1f251.png?v8",
"accessibility": "accessibility.png?v8",
"accordion": "unicode/1fa97.png?v8",
"adhesive_bandage": "unicode/1fa79.png?v8",
"adult": "unicode/1f9d1.png?v8",
@ -464,6 +465,7 @@ export default {
"deer": "unicode/1f98c.png?v8",
"denmark": "unicode/1f1e9-1f1f0.png?v8",
"department_store": "unicode/1f3ec.png?v8",
"dependabot": "dependabot.png?v8",
"derelict_house": "unicode/1f3da.png?v8",
"desert": "unicode/1f3dc.png?v8",
"desert_island": "unicode/1f3dd.png?v8",
@ -623,6 +625,7 @@ export default {
"fish": "unicode/1f41f.png?v8",
"fish_cake": "unicode/1f365.png?v8",
"fishing_pole_and_fish": "unicode/1f3a3.png?v8",
"fishsticks": "fishsticks.png?v8",
"fist": "unicode/270a.png?v8",
"fist_left": "unicode/1f91b.png?v8",
"fist_oncoming": "unicode/1f44a.png?v8",

View File

@ -1,15 +1,15 @@
/* eslint-disable no-unused-vars */
import tinydate from 'tinydate';
import * as dom from '../util/dom';
import cssVars from '../util/polyfill/css-vars';
import { getAndActive, sticky } from '../event/sidebar';
import { getPath, isAbsolutePath } from '../router/util';
import { isMobile, inBrowser } from '../util/env';
import { isPrimitive, merge } from '../util/core';
import { scrollActiveSidebar } from '../event/scroll';
import { Compiler } from './compiler';
import * as tpl from './tpl';
import { prerenderEmbed } from './embed';
import * as dom from '../util/dom.js';
import cssVars from '../util/polyfill/css-vars.js';
import { getAndActive, sticky } from '../event/sidebar.js';
import { getPath, isAbsolutePath } from '../router/util.js';
import { isMobile, inBrowser } from '../util/env.js';
import { isPrimitive, merge } from '../util/core.js';
import { scrollActiveSidebar } from '../event/scroll.js';
import { Compiler } from './compiler.js';
import * as tpl from './tpl.js';
import { prerenderEmbed } from './embed.js';
let vueGlobalData;

View File

@ -1,4 +1,4 @@
import * as dom from '../util/dom';
import * as dom from '../util/dom.js';
let barEl;
let timeId;

View File

@ -1,4 +1,4 @@
import { hasOwn } from '../util/core';
import { hasOwn } from '../util/core.js';
let cache = {};
const re = /[\u2000-\u206F\u2E00-\u2E7F\\'!"#$%&()*+,./:;<=>?@[\]^`{|}~]/g;

View File

@ -1,25 +0,0 @@
import { parseQuery } from '../util';
import { History } from './base';
export class AbstractHistory extends History {
constructor(config) {
super(config);
this.mode = 'abstract';
}
parse(path) {
let query = '';
const queryIndex = path.indexOf('?');
if (queryIndex >= 0) {
query = path.slice(queryIndex + 1);
path = path.slice(0, queryIndex);
}
return {
path,
file: this.getFile(path),
query: parseQuery(query),
};
}
}

View File

@ -5,8 +5,8 @@ import {
cleanPath,
replaceSlug,
resolvePath,
} from '../util';
import { noop, merge } from '../../util/core';
} from '../util.js';
import { noop, merge } from '../../util/core.js';
const cached = {};

View File

@ -1,8 +1,8 @@
import { isExternal, noop } from '../../util/core';
import { on } from '../../util/dom';
import { endsWith } from '../../util/str';
import { parseQuery, cleanPath, replaceSlug } from '../util';
import { History } from './base';
import { isExternal, noop } from '../../util/core.js';
import { on } from '../../util/dom.js';
import { endsWith } from '../../util/str.js';
import { parseQuery, cleanPath, replaceSlug } from '../util.js';
import { History } from './base.js';
function replaceHash(path) {
const i = location.href.indexOf('#');

View File

@ -1,7 +1,7 @@
import { isExternal, noop } from '../../util/core';
import { on } from '../../util/dom';
import { parseQuery, getPath } from '../util';
import { History } from './base';
import { isExternal, noop } from '../../util/core.js';
import { on } from '../../util/dom.js';
import { parseQuery, getPath } from '../util.js';
import { History } from './base.js';
export class HTML5History extends History {
constructor(config) {

View File

@ -1,8 +1,8 @@
import { supportsPushState } from '../util/env';
import * as dom from '../util/dom';
import { noop } from '../util/core';
import { HashHistory } from './history/hash';
import { HTML5History } from './history/html5';
import { supportsPushState } from '../util/env.js';
import * as dom from '../util/dom.js';
import { noop } from '../util/core.js';
import { HashHistory } from './history/hash.js';
import { HTML5History } from './history/html5.js';
/**
* @typedef {{

View File

@ -1,4 +1,4 @@
import { cached } from '../util/core';
import { cached } from '../util/core.js';
const decode = decodeURIComponent;
const encode = encodeURIComponent;

View File

@ -96,5 +96,8 @@ export function isExternal(url) {
) {
return true;
}
if (/^\/\\/.test(url)) {
return true;
}
return false;
}

View File

@ -1,5 +1,5 @@
import { isFn } from '../util/core';
import { inBrowser } from './env';
import { isFn } from '../util/core.js';
import { inBrowser } from './env.js';
const cacheNode = {};

View File

@ -1,4 +1,4 @@
export const inBrowser = !process.env.SSR;
export const inBrowser = true; // True for now, may change when we add SSR.
export const isMobile = inBrowser && document.body.clientWidth <= 600;

View File

@ -1,3 +1,3 @@
export * from './core';
export * from './env';
export * from '../router/util';
export * from './core.js';
export * from './env.js';
export * from '../router/util.js';

View File

@ -1,5 +1,5 @@
import * as dom from '../dom';
import { get } from '../../fetch/ajax';
import * as dom from '../dom.js';
import { get } from '../../fetch/ajax.js';
function replaceVar(block, color) {
block.innerHTML = block.innerHTML.replace(

View File

@ -1,4 +1,4 @@
import { startsWith, endsWith } from '../util/str';
import { startsWith, endsWith } from '../util/str.js';
/**
* Adds beginning of input (^) and end of input ($) assertions if needed into a regex string

View File

@ -1,5 +1,5 @@
import { makeExactMatcher } from './exact-match';
import { createNextFunction } from './next';
import { makeExactMatcher } from './exact-match.js';
import { createNextFunction } from './next.js';
/** @typedef {import('../Docsify').Constructor} Constructor */

View File

@ -1,4 +1,4 @@
import parser from './parser';
import parser from './parser.js';
const install = function (hook, vm) {
// Used to remove front matter from embedded pages if installed.

View File

@ -2,7 +2,7 @@
* Fork https://github.com/egoist/docute/blob/master/src/utils/front-matter.js
*/
/* eslint-disable */
import parser from './yaml'
import parser from './yaml.js'
var optionalByteOrderMark = '\\ufeff?'
var pattern =

72
src/plugins/gtag.js Normal file
View File

@ -0,0 +1,72 @@
/* eslint-disable no-console */
// From ./ga.js
function appendScript(id) {
const script = document.createElement('script');
script.async = true;
script.src = 'https://www.googletagmanager.com/gtag/js?id=' + id;
document.body.appendChild(script);
}
// global site tag instance initialized
function initGlobalSiteTag(id) {
appendScript(id);
window.dataLayer = window.dataLayer || [];
window.gtag =
window.gtag ||
function () {
window.dataLayer.push(arguments);
};
window.gtag('js', new Date());
window.gtag('config', id);
}
// add additional products to your tag
// https://developers.google.com/tag-platform/gtagjs/install
function initAdditionalTag(id) {
window.gtag('config', id);
}
function init(ids) {
if (Array.isArray(ids)) {
// set the first id to be a global site tag
initGlobalSiteTag(ids[0]);
// the rest ids
ids.forEach((id, index) => {
if (index > 0) {
initAdditionalTag(id);
}
});
} else {
initGlobalSiteTag(ids);
}
}
function collect() {
if (!window.gtag) {
init($docsify.gtag);
}
// usage: https://developers.google.com/analytics/devguides/collection/gtagjs/pages
window.gtag('event', 'page_view', {
/* eslint-disable camelcase */
page_title: document.title,
page_location: location.href,
page_path: location.pathname,
/* eslint-disable camelcase */
});
}
const install = function (hook) {
if (!$docsify.gtag) {
console.error('[Docsify] gtag is required.');
return;
}
hook.beforeEach(collect);
};
$docsify.plugins = [].concat(install, $docsify.plugins);

View File

@ -1,5 +1,5 @@
/* eslint-disable no-unused-vars */
import { search } from './search';
import { search } from './search.js';
let NO_DATA_TEXT = '';
let options;

View File

@ -1,6 +1,9 @@
/* eslint-disable no-unused-vars */
import { init as initComponent, update as updateComponent } from './component';
import { init as initSearch } from './search';
import {
init as initComponent,
update as updateComponent,
} from './component.js';
import { init as initSearch } from './search.js';
const CONFIG = {
placeholder: 'Type to search',

View File

@ -1,6 +1,6 @@
/* eslint-disable no-unused-vars */
import { getAndRemoveConfig } from '../../core/render/utils';
import { removeDocsifyIgnoreTag } from '../../core/util/str';
import { getAndRemoveConfig } from '../../core/render/utils.js';
import { removeDocsifyIgnoreTag } from '../../core/util/str.js';
let INDEXS = {};
@ -57,11 +57,9 @@ function getAllPaths(router) {
function getTableData(token) {
if (!token.text && token.type === 'table') {
token.cells.unshift(token.header);
token.text = token.cells
.map(function (rows) {
return rows.join(' | ');
})
token.rows.unshift(token.header);
token.text = token.rows
.map(columns => columns.map(r => r.text).join(' | '))
.join(' |\n ');
}
return token.text;

View File

@ -1,6 +1,8 @@
/* global afterEach, beforeAll, beforeEach */
import mock from 'xhr-mock';
import _mock from 'xhr-mock';
const mock = _mock.default;
const sideEffects = {
document: {

View File

@ -1,5 +1,5 @@
const server = require('./server.js');
import server from './server.js';
module.exports = async () => {
export default async () => {
await server.startAsync();
};

View File

@ -1,5 +1,5 @@
const server = require('./server.js');
import server from './server.js';
module.exports = async () => {
export default async () => {
server.stop();
};

View File

@ -1,5 +1,5 @@
const server = require('./server.js');
import server from './server.js';
module.exports = async config => {
export default async config => {
await server.startAsync();
};

View File

@ -1,5 +1,5 @@
const server = require('./server.js');
import server from './server.js';
module.exports = async config => {
export default async config => {
server.stop();
};

View File

@ -1,5 +1,8 @@
const browserSync = require('browser-sync').create();
const path = require('path');
import { create } from 'browser-sync';
import path from 'path';
import url from 'url';
const browserSync = create();
const hasStartArg = process.argv.includes('--start');
const serverConfig = {
@ -7,6 +10,11 @@ const serverConfig = {
port: hasStartArg ? 3002 : 3001,
};
const __filename = url.fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);
export const TEST_HOST = `http://${serverConfig.hostname}:${serverConfig.port}`;
function startServer(options = {}, cb = Function.prototype) {
const defaults = {
...serverConfig,
@ -73,7 +81,7 @@ function startServer(options = {}, cb = Function.prototype) {
console.log('\n');
// Set TEST_HOST environment variable
process.env.TEST_HOST = `http://${serverConfig.hostname}:${serverConfig.port}`;
process.env.TEST_HOST = TEST_HOST;
// Start server
browserSync.init(
@ -111,13 +119,20 @@ if (hasStartArg) {
});
}
// Display friendly message about manually starting a server instance
else if (require.main === module) {
else if (isMain(import.meta)) {
console.info('Use --start argument to manually start server instance');
}
module.exports = {
// Replacement for CommonJS `require.main === module`. https://2ality.com/2022/07/nodejs-esm-main.html
function isMain(meta) {
if (meta.url.startsWith('file:')) {
if (process.argv[1] === __filename) return true;
}
return false;
}
export default {
start: startServer,
startAsync: startServerAsync,
stop: stopServer,
TEST_HOST: `http://${serverConfig.hostname}:${serverConfig.port}`,
};

View File

@ -1,5 +1,5 @@
const docsifyInit = require('../helpers/docsify-init');
const { test, expect } = require('./fixtures/docsify-init-fixture');
import docsifyInit from '../helpers/docsify-init.js';
import { test, expect } from './fixtures/docsify-init-fixture.js';
test.describe('Configuration options', () => {
test('catchPluginErrors:true (handles uncaught errors)', async ({ page }) => {

View File

@ -1,81 +1,7 @@
// Modules, constants, and variables
// -----------------------------------------------------------------------------
const docsifyInit = require('../helpers/docsify-init');
const { test, expect } = require('./fixtures/docsify-init-fixture');
// Suite
// -----------------------------------------------------------------------------
test.describe('Example Tests', () => {
// Tests
// ---------------------------------------------------------------------------
test('dom manipulation', async ({ page }) => {
const testText = 'This is a test';
const testHTML = `<h1>Test</h1><p>${testText}</p>`;
// Inject HTML
await page.setContent(testHTML);
// Get reference to page element
const bodyElm = page.locator('body');
const pElm = page.locator('body > p');
// Add class to element and test
await bodyElm.evaluate(elm => elm.classList.add('foo'));
// Tests
await expect(bodyElm).toHaveClass('foo');
await expect(bodyElm).toContainText('Test');
await expect(pElm).toHaveCount(1);
await expect(pElm).toHaveText(testText);
await expect(pElm).not.toHaveText('NOPE');
});
test('javascript in browser context', async ({ page }) => {
// Get native DOM values
const clientDimensions = await page.evaluate(() => {
return {
width: document.documentElement.clientWidth,
height: document.documentElement.clientHeight,
};
});
expect(clientDimensions).toHaveProperty('width');
expect(typeof clientDimensions.width).toBe('number');
expect(clientDimensions).toHaveProperty('height');
expect(typeof clientDimensions.height).toBe('number');
// Get result of script executed in browser context
const scriptResult = await page.evaluate(
numbers => {
const result = numbers.reduce(
(accumulator, currentValue) => accumulator + currentValue
);
return Promise.resolve(result);
},
[1, 2, 3]
);
expect(scriptResult).toBe(6);
// Get result of local function executed in browser context
function add(...addends) {
return addends.reduce(
(accumulator, currentValue) => accumulator + currentValue
);
}
const functionResult = await page.evaluate(`
const add = ${add.toString()};
const result = add(1, 2, 3);
Promise.resolve(result);
`);
expect(functionResult).toBe(6);
});
import docsifyInit from '../helpers/docsify-init.js';
import { test, expect } from './fixtures/docsify-init-fixture.js';
test.describe('Creating a Docsify site (e2e tests in Playwright)', () => {
test('manual docsify site using playwright methods', async ({ page }) => {
// Add docsify target element
await page.setContent('<div id="app"></div>');

View File

@ -1,6 +1,6 @@
const base = require('@playwright/test');
import { test as _test, expect as _expect } from '@playwright/test';
exports.test = base.test.extend({
export const test = _test.extend({
page: async ({ page }, use) => {
global.page = page;
@ -13,4 +13,5 @@ exports.test = base.test.extend({
await use(page);
},
});
exports.expect = base.expect;
export const expect = _expect;

90
test/e2e/gtag.test.js Normal file
View File

@ -0,0 +1,90 @@
import docsifyInit from '../helpers/docsify-init.js';
import { test, expect } from './fixtures/docsify-init-fixture.js';
const gtagList = [
'AW-YYYYYY', // Google Ads
'DC-ZZZZZZ', // Floodlight
'G-XXXXXX', // Google Analytics 4 (GA4)
'UA-XXXXXX', // Google Universal Analytics (GA3)
];
test.describe('Gtag Plugin Tests', () => {
// page request listened, print collect url
function pageRequestListened(page) {
page.on('request', request => {
if (request.url().indexOf('www.google-analytics.com') !== -1) {
// console.log(request.url());
}
});
page.on('response', response => {
const request = response.request();
// googleads.g.doubleclick.net
// www.google-analytics.com
// www.googletagmanager.com
const reg =
/googleads\.g\.doubleclick\.net|www\.google-analytics\.com|www\.googletagmanager\.com/g;
if (request.url().match(reg)) {
// console.log(request.url(), response.status());
}
});
}
test('single gtag', async ({ page }) => {
pageRequestListened(page);
const docsifyInitConfig = {
config: {
gtag: gtagList[0],
},
scriptURLs: ['/lib/plugins/gtag.min.js'],
styleURLs: ['/lib/themes/vue.css'],
};
await docsifyInit({
...docsifyInitConfig,
});
const $docsify = await page.evaluate(() => window.$docsify);
// Verify config options
expect(typeof $docsify).toEqual('object');
// console.log($docsify.gtag, $docsify.gtag === '');
// Tests
expect($docsify.gtag).not.toEqual('');
});
test('multi gtag', async ({ page }) => {
pageRequestListened(page);
const docsifyInitConfig = {
config: {
gtag: gtagList,
},
scriptURLs: ['/lib/plugins/gtag.min.js'],
styleURLs: ['/lib/themes/vue.css'],
};
await docsifyInit({
...docsifyInitConfig,
});
const $docsify = await page.evaluate(() => window.$docsify);
// Verify config options
expect(typeof $docsify).toEqual('object');
// console.log($docsify.gtag, $docsify.gtag === '');
// Tests
expect($docsify.gtag).not.toEqual('');
});
test('data-ga attribute', async ({ page }) => {
pageRequestListened(page);
// TODO
});
});

View File

@ -1,5 +1,5 @@
const docsifyInit = require('../helpers/docsify-init');
const { test, expect } = require('./fixtures/docsify-init-fixture');
import docsifyInit from '../helpers/docsify-init.js';
import { test, expect } from './fixtures/docsify-init-fixture.js';
test.describe('Index file hosting', () => {
const sharedOptions = {

View File

@ -1,5 +1,5 @@
const docsifyInit = require('../helpers/docsify-init');
const { test, expect } = require('./fixtures/docsify-init-fixture');
import docsifyInit from '../helpers/docsify-init.js';
import { test, expect } from './fixtures/docsify-init-fixture.js';
test.describe('Plugins', () => {
test('Hook order', async ({ page }) => {

View File

@ -1,5 +1,5 @@
const docsifyInit = require('../helpers/docsify-init');
const { test, expect } = require('./fixtures/docsify-init-fixture');
import docsifyInit from '../helpers/docsify-init.js';
import { test, expect } from './fixtures/docsify-init-fixture.js';
test.describe('Search Plugin Tests', () => {
test('search readme', async ({ page }) => {

View File

@ -1,5 +1,5 @@
const docsifyInit = require('../helpers/docsify-init');
const { test, expect } = require('./fixtures/docsify-init-fixture');
import docsifyInit from '../helpers/docsify-init.js';
import { test, expect } from './fixtures/docsify-init-fixture.js';
test.describe('Security - Cross Site Scripting (XSS)', () => {
const sharedOptions = {

View File

@ -1,5 +1,5 @@
const docsifyInit = require('../helpers/docsify-init');
const { test, expect } = require('./fixtures/docsify-init-fixture');
import docsifyInit from '../helpers/docsify-init.js';
import { test, expect } from './fixtures/docsify-init-fixture.js';
// Suite
// -----------------------------------------------------------------------------

View File

@ -1,5 +1,5 @@
const docsifyInit = require('../helpers/docsify-init');
const { test, expect } = require('./fixtures/docsify-init-fixture');
import docsifyInit from '../helpers/docsify-init.js';
import { test, expect } from './fixtures/docsify-init-fixture.js';
/**
* Navigate to a specific route in the site
@ -8,6 +8,8 @@ const { test, expect } = require('./fixtures/docsify-init-fixture');
*/
async function navigateToRoute(page, route) {
await page.evaluate(r => (window.location.hash = r), route);
// TODO: playwright eslint now recommends not using networkidle
// eslint-disable-next-line
await page.waitForLoadState('networkidle');
}

View File

@ -1,6 +1,6 @@
const stripIndent = require('common-tags/lib/stripIndent');
const docsifyInit = require('../helpers/docsify-init');
const { test, expect } = require('./fixtures/docsify-init-fixture');
import stripIndent from 'common-tags/lib/stripIndent/index.js';
import docsifyInit from '../helpers/docsify-init.js';
import { test, expect } from './fixtures/docsify-init-fixture.js';
const vueURLs = [
'/node_modules/vue2/dist/vue.js',
@ -179,6 +179,7 @@ test.describe('Vue.js Compatibility', () => {
await expect(page.locator('#vuefor')).toHaveText('12345');
await expect(page.locator('#vuecomponent')).toHaveText('0');
await expect(page.locator('#vuecomponent')).toHaveText('0');
// eslint-disable-next-line playwright/prefer-web-first-assertions
expect(await page.locator('#vueglobaloptions p').innerText()).toBe('');
await expect(page.locator('#vuemounts p')).toHaveText('vuemounts');
await expect(page.locator('#vuescript p')).toHaveText('vuescript');

View File

@ -1,12 +1,13 @@
/* globals page */
import _mock, { proxy } from 'xhr-mock';
const axios = require('axios');
const mock = require('xhr-mock').default;
const prettier = require('prettier');
const stripIndent = require('common-tags/lib/stripIndent');
const { proxy } = require('xhr-mock');
const { waitForSelector } = require('./wait-for');
import axios from 'axios';
import prettier from 'prettier';
import stripIndent from 'common-tags/lib/stripIndent/index.js';
// import { TEST_HOST } from '../config/server.js';
import { waitForSelector } from './wait-for.js';
const mock = _mock.default;
const docsifyPATH = '../../lib/docsify.js'; // JSDOM
const docsifyURL = '/lib/docsify.js'; // Playwright
@ -262,7 +263,7 @@ async function docsifyInit(options = {}) {
const isDocsifyLoaded = 'Docsify' in window;
if (!isDocsifyLoaded) {
require(docsifyPATH);
await import(docsifyPATH);
}
} else if (isPlaywright) {
for (const url of settings.scriptURLs) {
@ -358,4 +359,4 @@ async function docsifyInit(options = {}) {
return Promise.resolve();
}
module.exports = docsifyInit;
export default docsifyInit;

View File

@ -125,8 +125,4 @@ function waitForText(cssSelector, text, options = {}) {
});
}
module.exports = {
waitForFunction,
waitForSelector,
waitForText,
};
export { waitForFunction, waitForSelector, waitForText };

View File

@ -0,0 +1 @@
module.exports = require('../unit/.eslintrc.cjs');

View File

@ -1 +0,0 @@
module.exports = require('../unit/.eslintrc');

Some files were not shown because too many files have changed in this diff Show More