Compare commits
3 Commits
v6.0.0-bet
...
docs
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
2ad39cf69e | ||
|
|
6929cb3001 | ||
|
|
5ee3063d01 |
@@ -50,3 +50,11 @@ jobs:
|
|||||||
- store_artifacts:
|
- store_artifacts:
|
||||||
path: build/apidoc
|
path: build/apidoc
|
||||||
destination: apidoc
|
destination: apidoc
|
||||||
|
|
||||||
|
- run:
|
||||||
|
name: Build Website
|
||||||
|
command: npm run build-site
|
||||||
|
|
||||||
|
- store_artifacts:
|
||||||
|
path: public
|
||||||
|
destination: website
|
||||||
|
|||||||
2
.gitignore
vendored
2
.gitignore
vendored
@@ -2,3 +2,5 @@
|
|||||||
/coverage/
|
/coverage/
|
||||||
/dist/
|
/dist/
|
||||||
node_modules/
|
node_modules/
|
||||||
|
/.cache/
|
||||||
|
/public/
|
||||||
|
|||||||
23
config/jsdoc/api-info/conf.json
Normal file
23
config/jsdoc/api-info/conf.json
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
{
|
||||||
|
"opts": {
|
||||||
|
"recurse": true,
|
||||||
|
"template": "node_modules/jsdoc-json"
|
||||||
|
},
|
||||||
|
"tags": {
|
||||||
|
"allowUnknownTags": true
|
||||||
|
},
|
||||||
|
"source": {
|
||||||
|
"includePattern": "\\.js$",
|
||||||
|
"include": [
|
||||||
|
"src/ol"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"plugins": [
|
||||||
|
"jsdoc-plugin-typescript",
|
||||||
|
"config/jsdoc/api-info/plugins/api",
|
||||||
|
"config/jsdoc/api-info/plugins/module"
|
||||||
|
],
|
||||||
|
"typescript": {
|
||||||
|
"moduleRoot": "src"
|
||||||
|
}
|
||||||
|
}
|
||||||
15
config/jsdoc/api-info/plugins/api.js
Normal file
15
config/jsdoc/api-info/plugins/api.js
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
|
||||||
|
/**
|
||||||
|
* Handle the api annotation.
|
||||||
|
* @param {Object} dictionary The tag dictionary.
|
||||||
|
*/
|
||||||
|
exports.defineTags = dictionary => {
|
||||||
|
|
||||||
|
dictionary.defineTag('api', {
|
||||||
|
onTagged: (doclet, tag) => {
|
||||||
|
doclet.api = true;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
170
config/jsdoc/api-info/plugins/module.js
Normal file
170
config/jsdoc/api-info/plugins/module.js
Normal file
@@ -0,0 +1,170 @@
|
|||||||
|
/**
|
||||||
|
* This plugin adds an `exportMap` property to @module doclets. Each export map
|
||||||
|
* is an object with properties named like the local identifier and values named
|
||||||
|
* like the exported identifier.
|
||||||
|
*
|
||||||
|
* For example, the code below
|
||||||
|
*
|
||||||
|
* export {foo as bar};
|
||||||
|
*
|
||||||
|
* would be a map like `{foo: 'bar'}`.
|
||||||
|
*
|
||||||
|
* In the case of an export declaration with a source, the export identifier is
|
||||||
|
* prefixed by the source. For example, this code
|
||||||
|
*
|
||||||
|
* export {foo as bar} from 'ol/bam';
|
||||||
|
*
|
||||||
|
* would be a map like `{'ol/bam foo': 'bar'}`.
|
||||||
|
*
|
||||||
|
* If a default export is a literal or object expression, the local name will be
|
||||||
|
* an empty string. For example
|
||||||
|
*
|
||||||
|
* export default {foo: 'bar'};
|
||||||
|
*
|
||||||
|
* would be a map like `{'': 'default'}`.
|
||||||
|
*/
|
||||||
|
const assert = require('assert');
|
||||||
|
const path = require('path');
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A lookup of export maps per source filepath.
|
||||||
|
*/
|
||||||
|
const exportMapLookup = {};
|
||||||
|
|
||||||
|
function loc(filepath, node) {
|
||||||
|
return `${filepath}:${node.loc.start.line}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
function nameFromChildIdentifier(filepath, node) {
|
||||||
|
assert.ok(node.id, `expected identifer in ${loc(filepath, node)}`);
|
||||||
|
assert.strictEqual(node.id.type, 'Identifier', `expected identifer in ${loc(filepath, node)}`);
|
||||||
|
return node.id.name;
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleExportNamedDeclaration(filepath, node) {
|
||||||
|
if (!(filepath in exportMapLookup)) {
|
||||||
|
exportMapLookup[filepath] = {};
|
||||||
|
}
|
||||||
|
const exportMap = exportMapLookup[filepath];
|
||||||
|
|
||||||
|
const declaration = node.declaration;
|
||||||
|
if (declaration) {
|
||||||
|
// `export class Foo{}` or `export function foo() {}`
|
||||||
|
if (declaration.type === 'ClassDeclaration' || declaration.type === 'FunctionDeclaration') {
|
||||||
|
const name = nameFromChildIdentifier(filepath, declaration);
|
||||||
|
exportMap[name] = name;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// `export const foo = 'bar', bam = 42`
|
||||||
|
if (declaration.type === 'VariableDeclaration') {
|
||||||
|
const declarations = declaration.declarations;
|
||||||
|
assert.ok(declarations.length > 0, `expected variable declarations in ${loc(filepath, declaration)}`);
|
||||||
|
for (const declarator of declarations) {
|
||||||
|
assert.strictEqual(declarator.type, 'VariableDeclarator', `unexpected "${declarator.type}" in ${loc(filepath, declarator)}`);
|
||||||
|
const name = nameFromChildIdentifier(filepath, declarator);
|
||||||
|
exportMap[name] = name;
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new Error(`Unexpected named export "${declaration.type}" in ${loc(filepath, declaration)}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
let prefix = '';
|
||||||
|
const source = node.source;
|
||||||
|
if (source) {
|
||||||
|
// `export foo from 'bar'`
|
||||||
|
assert.strictEqual(source.type, 'Literal', `unexpected export source "${source.type}" in ${loc(filepath, source)}`);
|
||||||
|
prefix = `${source.value} `;
|
||||||
|
}
|
||||||
|
|
||||||
|
const specifiers = node.specifiers;
|
||||||
|
assert.ok(specifiers.length > 0, `expected export specifiers in ${loc(filepath, node)}`);
|
||||||
|
// `export {foo, bar}` or `export {default as Foo} from 'bar'`
|
||||||
|
for (const specifier of specifiers) {
|
||||||
|
assert.strictEqual(specifier.type, 'ExportSpecifier', `unexpected export specifier in ${loc(filepath, specifier)}`);
|
||||||
|
|
||||||
|
const local = specifier.local;
|
||||||
|
assert.strictEqual(local.type, 'Identifier', `unexpected local specifier "${local.type} in ${loc(filepath, local)}`);
|
||||||
|
|
||||||
|
const exported = specifier.exported;
|
||||||
|
assert.strictEqual(local.type, 'Identifier', `unexpected exported specifier "${exported.type} in ${loc(filepath, exported)}`);
|
||||||
|
|
||||||
|
exportMap[prefix + local.name] = exported.name;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleDefaultDeclaration(filepath, node) {
|
||||||
|
if (!(filepath in exportMapLookup)) {
|
||||||
|
exportMapLookup[filepath] = {};
|
||||||
|
}
|
||||||
|
const exportMap = exportMapLookup[filepath];
|
||||||
|
|
||||||
|
const declaration = node.declaration;
|
||||||
|
if (declaration) {
|
||||||
|
// `export default class Foo{}` or `export default function foo () {}`
|
||||||
|
if (declaration.type === 'ClassDeclaration' || declaration.type === 'FunctionDeclaration') {
|
||||||
|
const name = nameFromChildIdentifier(filepath, declaration);
|
||||||
|
exportMap[name] = 'default';
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// `export default foo`
|
||||||
|
if (declaration.type === 'Identifier') {
|
||||||
|
exportMap[declaration.name] = 'default';
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// `export default {foo: 'bar'}` or `export default 42`
|
||||||
|
if (declaration.type === 'ObjectExpression' || declaration.type === 'Literal') {
|
||||||
|
exportMap[''] = 'default';
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new Error(`Unexpected default export "${declaration.type}" in ${loc(filepath, declaration)}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
exports.astNodeVisitor = {
|
||||||
|
visitNode: (node, event, parser, filepath) => {
|
||||||
|
if (node.type === 'ExportNamedDeclaration') {
|
||||||
|
return handleExportNamedDeclaration(filepath, node);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (node.type === 'ExportDefaultDeclaration') {
|
||||||
|
return handleDefaultDeclaration(filepath, node);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const moduleLookup = {};
|
||||||
|
|
||||||
|
exports.handlers = {
|
||||||
|
|
||||||
|
// create a lookup of @module doclets
|
||||||
|
newDoclet: event => {
|
||||||
|
const doclet = event.doclet;
|
||||||
|
if (doclet.kind === 'module') {
|
||||||
|
const filepath = path.join(doclet.meta.path, doclet.meta.filename);
|
||||||
|
|
||||||
|
assert.ok(!(filepath in moduleLookup), `duplicate @module doc in ${filepath}`);
|
||||||
|
moduleLookup[filepath] = doclet;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
// assign the `exportMap` property to @module doclets
|
||||||
|
parseComplete: event => {
|
||||||
|
for (const filepath in moduleLookup) {
|
||||||
|
assert.ok(filepath in exportMapLookup, `missing ${filepath} in export map lookup`);
|
||||||
|
moduleLookup[filepath].exportMap = exportMapLookup[filepath];
|
||||||
|
}
|
||||||
|
|
||||||
|
// make sure there was a @module doclet for each export map
|
||||||
|
for (const filepath in exportMapLookup) {
|
||||||
|
assert.ok(filepath in moduleLookup, `missing @module doclet in ${filepath}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
11
gatsby-config.js
Normal file
11
gatsby-config.js
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
module.exports = {
|
||||||
|
plugins: [
|
||||||
|
'gatsby-plugin-emotion',
|
||||||
|
{
|
||||||
|
resolve: 'gatsby-plugin-typography',
|
||||||
|
options: {
|
||||||
|
pathToConfigModule: 'site/util/typography'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
};
|
||||||
23
gatsby-node.js
Normal file
23
gatsby-node.js
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
|
||||||
|
function getDocs() {
|
||||||
|
// TODO: build if not present
|
||||||
|
const info = require('./build/api-info.json');
|
||||||
|
|
||||||
|
return info.docs.filter(doc => !doc.ignore && (doc.api || doc.kind === 'module' || doc.kind === 'typedef'));
|
||||||
|
}
|
||||||
|
|
||||||
|
function createPages({actions: {createPage}}) {
|
||||||
|
createPage({
|
||||||
|
path: '/api',
|
||||||
|
component: require.resolve('./site/pages/API.js'),
|
||||||
|
context: {docs: getDocs()}
|
||||||
|
});
|
||||||
|
|
||||||
|
createPage({
|
||||||
|
path: '/info',
|
||||||
|
component: require.resolve('./site/pages/Info.js'),
|
||||||
|
context: {docs: getDocs()}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
exports.createPages = createPages;
|
||||||
20668
package-lock.json
generated
Normal file
20668
package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load Diff
21
package.json
21
package.json
@@ -24,7 +24,10 @@
|
|||||||
"copy-css": "shx cp src/ol/ol.css build/ol/ol.css",
|
"copy-css": "shx cp src/ol/ol.css build/ol/ol.css",
|
||||||
"transpile": "shx rm -rf build/ol && shx mkdir -p build/ol && shx cp -rf src/ol build/ol/src && node tasks/serialize-workers && tsc --project config/tsconfig-build.json",
|
"transpile": "shx rm -rf build/ol && shx mkdir -p build/ol && shx cp -rf src/ol build/ol/src && node tasks/serialize-workers && tsc --project config/tsconfig-build.json",
|
||||||
"typecheck": "tsc --pretty",
|
"typecheck": "tsc --pretty",
|
||||||
"apidoc": "jsdoc -R config/jsdoc/api/index.md -c config/jsdoc/api/conf.json -P package.json -d build/apidoc"
|
"apidoc": "jsdoc -R config/jsdoc/api/index.md -c config/jsdoc/api/conf.json -P package.json -d build/apidoc",
|
||||||
|
"api-info": "jsdoc --configure config/jsdoc/api-info/conf.json --destination build/api-info.json",
|
||||||
|
"serve-site": "gatsby develop",
|
||||||
|
"build-site": "npm run api-info && gatsby build"
|
||||||
},
|
},
|
||||||
"main": "index.js",
|
"main": "index.js",
|
||||||
"repository": {
|
"repository": {
|
||||||
@@ -43,6 +46,8 @@
|
|||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@babel/core": "^7.4.0",
|
"@babel/core": "^7.4.0",
|
||||||
"@babel/preset-env": "^7.4.4",
|
"@babel/preset-env": "^7.4.4",
|
||||||
|
"@emotion/core": "^10.0.10",
|
||||||
|
"@emotion/styled": "^10.0.11",
|
||||||
"@openlayers/eslint-plugin": "^4.0.0-beta.2",
|
"@openlayers/eslint-plugin": "^4.0.0-beta.2",
|
||||||
"@types/arcgis-rest-api": "^10.4.4",
|
"@types/arcgis-rest-api": "^10.4.4",
|
||||||
"@types/geojson": "^7946.0.7",
|
"@types/geojson": "^7946.0.7",
|
||||||
@@ -57,9 +62,14 @@
|
|||||||
"coveralls": "3.0.3",
|
"coveralls": "3.0.3",
|
||||||
"eslint": "^5.16.0",
|
"eslint": "^5.16.0",
|
||||||
"eslint-config-openlayers": "^11.0.0",
|
"eslint-config-openlayers": "^11.0.0",
|
||||||
|
"eslint-config-tschaub": "^13.1.0",
|
||||||
|
"eslint-plugin-react": "^7.13.0",
|
||||||
"expect.js": "0.3.1",
|
"expect.js": "0.3.1",
|
||||||
"front-matter": "^3.0.2",
|
"front-matter": "^3.0.2",
|
||||||
"fs-extra": "^8.0.0",
|
"fs-extra": "^8.0.0",
|
||||||
|
"gatsby": "^2.4.3",
|
||||||
|
"gatsby-plugin-emotion": "^4.0.6",
|
||||||
|
"gatsby-plugin-typography": "^2.2.13",
|
||||||
"glob": "^7.1.4",
|
"glob": "^7.1.4",
|
||||||
"globby": "^9.2.0",
|
"globby": "^9.2.0",
|
||||||
"handlebars": "4.1.2",
|
"handlebars": "4.1.2",
|
||||||
@@ -68,6 +78,7 @@
|
|||||||
"istanbul-instrumenter-loader": "^3.0.1",
|
"istanbul-instrumenter-loader": "^3.0.1",
|
||||||
"jquery": "3.4.1",
|
"jquery": "3.4.1",
|
||||||
"jsdoc": "3.6.2",
|
"jsdoc": "3.6.2",
|
||||||
|
"jsdoc-json": "^2.0.2",
|
||||||
"jsdoc-plugin-typescript": "^2.0.1",
|
"jsdoc-plugin-typescript": "^2.0.1",
|
||||||
"karma": "^4.1.0",
|
"karma": "^4.1.0",
|
||||||
"karma-chrome-launcher": "2.2.0",
|
"karma-chrome-launcher": "2.2.0",
|
||||||
@@ -84,7 +95,13 @@
|
|||||||
"pixelmatch": "^4.0.2",
|
"pixelmatch": "^4.0.2",
|
||||||
"pngjs": "^3.4.0",
|
"pngjs": "^3.4.0",
|
||||||
"proj4": "2.5.0",
|
"proj4": "2.5.0",
|
||||||
|
"prop-types": "^15.7.2",
|
||||||
"puppeteer": "~1.16.0",
|
"puppeteer": "~1.16.0",
|
||||||
|
"react": "^16.8.6",
|
||||||
|
"react-dom": "^16.8.6",
|
||||||
|
"react-markdown": "^4.0.8",
|
||||||
|
"react-syntax-highlighter": "^10.2.1",
|
||||||
|
"react-typography": "^0.16.19",
|
||||||
"rollup": "^1.12.0",
|
"rollup": "^1.12.0",
|
||||||
"rollup-plugin-babel": "^4.3.2",
|
"rollup-plugin-babel": "^4.3.2",
|
||||||
"rollup-plugin-commonjs": "^10.0.0",
|
"rollup-plugin-commonjs": "^10.0.0",
|
||||||
@@ -95,6 +112,8 @@
|
|||||||
"sinon": "^7.3.2",
|
"sinon": "^7.3.2",
|
||||||
"terser-webpack-plugin": "^1.2.3",
|
"terser-webpack-plugin": "^1.2.3",
|
||||||
"typescript": "^3.4.5",
|
"typescript": "^3.4.5",
|
||||||
|
"typography": "^0.16.19",
|
||||||
|
"typography-theme-alton": "^0.16.19",
|
||||||
"url-polyfill": "^1.1.5",
|
"url-polyfill": "^1.1.5",
|
||||||
"walk": "^2.3.9",
|
"walk": "^2.3.9",
|
||||||
"webpack": "4.31.0",
|
"webpack": "4.31.0",
|
||||||
|
|||||||
3
site/.eslintrc.json
Normal file
3
site/.eslintrc.json
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
{
|
||||||
|
"extends": "tschaub/react"
|
||||||
|
}
|
||||||
35
site/components/Class.jsx
Normal file
35
site/components/Class.jsx
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
import {object} from 'prop-types';
|
||||||
|
import React from 'react';
|
||||||
|
import Markdown from 'react-markdown';
|
||||||
|
import Code from './Code';
|
||||||
|
import Parameter from './Parameter';
|
||||||
|
|
||||||
|
function Class({cls, module, helper}) {
|
||||||
|
const exportedName = module.getExportedName(cls.name);
|
||||||
|
let importCode;
|
||||||
|
if (exportedName === 'default') {
|
||||||
|
importCode = `import ${cls.name} from '${module.id}';`;
|
||||||
|
} else {
|
||||||
|
importCode = `import {${exportedName}} from '${module.id}';`;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<h3>{cls.name}</h3>
|
||||||
|
<Code value={importCode} />
|
||||||
|
<Markdown source={cls.doc.classdesc} renderers={{code: Code}} />
|
||||||
|
<h6>Parameters</h6>
|
||||||
|
<ul>
|
||||||
|
{cls.doc.params && cls.doc.params.map(param => <Parameter param={param} module={module} helper={helper} />)}
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Class.propTypes = {
|
||||||
|
cls: object.isRequired,
|
||||||
|
module: object.isRequired,
|
||||||
|
helper: object.isRequired
|
||||||
|
};
|
||||||
|
|
||||||
|
export default Class;
|
||||||
26
site/components/Code.jsx
Normal file
26
site/components/Code.jsx
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
import React, {PureComponent} from 'react';
|
||||||
|
import {string} from 'prop-types';
|
||||||
|
import {Prism as SyntaxHighlighter} from 'react-syntax-highlighter';
|
||||||
|
import {coy} from 'react-syntax-highlighter/dist/styles/prism';
|
||||||
|
|
||||||
|
class Code extends PureComponent {
|
||||||
|
render() {
|
||||||
|
let language = this.props.language;
|
||||||
|
if (!language) {
|
||||||
|
language = 'js';
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<SyntaxHighlighter language={language} style={coy}>
|
||||||
|
{this.props.value}
|
||||||
|
</SyntaxHighlighter>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Code.propTypes = {
|
||||||
|
value: string.isRequired,
|
||||||
|
language: string
|
||||||
|
};
|
||||||
|
|
||||||
|
export default Code;
|
||||||
35
site/components/Func.jsx
Normal file
35
site/components/Func.jsx
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
import {object} from 'prop-types';
|
||||||
|
import React from 'react';
|
||||||
|
import Markdown from 'react-markdown';
|
||||||
|
import Code from './Code';
|
||||||
|
import Parameter from './Parameter';
|
||||||
|
|
||||||
|
function Func({func, module, helper}) {
|
||||||
|
const exportedName = module.getExportedName(func.name);
|
||||||
|
let importCode;
|
||||||
|
if (exportedName === 'default') {
|
||||||
|
importCode = `import ${func.name} from '${module.id}';`;
|
||||||
|
} else {
|
||||||
|
importCode = `import {${exportedName}} from '${module.id}';`;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<h3>{func.name}</h3>
|
||||||
|
<Code value={importCode} />
|
||||||
|
<Markdown source={func.doc.description} renderers={{code: Code}} />
|
||||||
|
<h6>Parameters</h6>
|
||||||
|
<ul>
|
||||||
|
{func.doc.params && func.doc.params.map(param => <Parameter param={param} module={module} helper={helper} />)}
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Func.propTypes = {
|
||||||
|
func: object.isRequired,
|
||||||
|
module: object.isRequired,
|
||||||
|
helper: object.isRequired
|
||||||
|
};
|
||||||
|
|
||||||
|
export default Func;
|
||||||
26
site/components/Module.jsx
Normal file
26
site/components/Module.jsx
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
import {object} from 'prop-types';
|
||||||
|
import React from 'react';
|
||||||
|
import Class from './Class';
|
||||||
|
import Func from './Func';
|
||||||
|
|
||||||
|
function Module({module, helper}) {
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<hr />
|
||||||
|
<h2>{module.id}</h2>
|
||||||
|
{module.classes.map(cls => (
|
||||||
|
<Class key={cls.name} cls={cls} module={module} helper={helper} />
|
||||||
|
))}
|
||||||
|
{module.functions.map(func => (
|
||||||
|
<Func key={func.name} func={func} module={module} helper={helper} />
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Module.propTypes = {
|
||||||
|
module: object.isRequired,
|
||||||
|
helper: object.isRequired
|
||||||
|
};
|
||||||
|
|
||||||
|
export default Module;
|
||||||
20
site/components/Parameter.jsx
Normal file
20
site/components/Parameter.jsx
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
import {object} from 'prop-types';
|
||||||
|
import React from 'react';
|
||||||
|
import Type from './Type';
|
||||||
|
|
||||||
|
function Parameter({param, module, helper}) {
|
||||||
|
return (
|
||||||
|
<li>
|
||||||
|
<code>{param.name}</code> - {param.description} {param.optional && <span>(optional)</span>}<br/>
|
||||||
|
{param.type.names.map(longName => <Type longName={longName} module={module} helper={helper} />)}
|
||||||
|
</li>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Parameter.propTypes = {
|
||||||
|
param: object.isRequired,
|
||||||
|
module: object.isRequired,
|
||||||
|
helper: object.isRequired
|
||||||
|
};
|
||||||
|
|
||||||
|
export default Parameter;
|
||||||
27
site/components/Type.jsx
Normal file
27
site/components/Type.jsx
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
import {object} from 'prop-types';
|
||||||
|
import React from 'react';
|
||||||
|
import Parameter from './Parameter';
|
||||||
|
|
||||||
|
function Type({longName, module, helper}) {
|
||||||
|
const type = helper.getTypeDef(longName);
|
||||||
|
if (!type) {
|
||||||
|
return <code>{longName}</code>;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<code>{type.doc.type.names}</code>
|
||||||
|
<ul>
|
||||||
|
{type.doc.properties && type.doc.properties.map(prop => <Parameter param={prop} module={module} helper={helper} />)}
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Type.propTypes = {
|
||||||
|
longName: object.isRequired,
|
||||||
|
module: object.isRequired,
|
||||||
|
helper: object.isRequired
|
||||||
|
};
|
||||||
|
|
||||||
|
export default Type;
|
||||||
8
site/components/layout.js
Normal file
8
site/components/layout.js
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
import styled from '@emotion/styled';
|
||||||
|
import {baseSpacingPx} from '../util/typography';
|
||||||
|
|
||||||
|
export const Page = styled.div({
|
||||||
|
display: 'flex',
|
||||||
|
flexDirection: 'column',
|
||||||
|
margin: 2 * baseSpacingPx
|
||||||
|
});
|
||||||
26
site/pages/API.js
Normal file
26
site/pages/API.js
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
import {object} from 'prop-types';
|
||||||
|
import React from 'react';
|
||||||
|
import {Page} from '../components/layout';
|
||||||
|
import Module from '../components/Module';
|
||||||
|
import {getHelper} from '../util/api';
|
||||||
|
|
||||||
|
function API({pageContext: {docs}}) {
|
||||||
|
const helper = getHelper(docs);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Page>
|
||||||
|
<h1>API</h1>
|
||||||
|
{helper.modules
|
||||||
|
.filter(module => module.visible)
|
||||||
|
.map(module => (
|
||||||
|
<Module key={module.id} module={module} helper={helper} />
|
||||||
|
))}
|
||||||
|
</Page>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
API.propTypes = {
|
||||||
|
pageContext: object.isRequired
|
||||||
|
};
|
||||||
|
|
||||||
|
export default API;
|
||||||
33
site/pages/Info.js
Normal file
33
site/pages/Info.js
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
import {object} from 'prop-types';
|
||||||
|
import React from 'react';
|
||||||
|
import {Page} from '../components/layout';
|
||||||
|
|
||||||
|
function Info({pageContext: {docs}}) {
|
||||||
|
return (
|
||||||
|
<Page>
|
||||||
|
<h1>API</h1>
|
||||||
|
<table>
|
||||||
|
<tbody>
|
||||||
|
<tr>
|
||||||
|
<th>kind</th>
|
||||||
|
<th>longname</th>
|
||||||
|
<th>memberof</th>
|
||||||
|
</tr>
|
||||||
|
{docs.map(doc => (
|
||||||
|
<tr key={doc.longname}>
|
||||||
|
<td>{doc.kind}</td>
|
||||||
|
<td>{doc.longname}</td>
|
||||||
|
<td>{doc.memberof}</td>
|
||||||
|
</tr>
|
||||||
|
))}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</Page>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Info.propTypes = {
|
||||||
|
pageContext: object.isRequired
|
||||||
|
};
|
||||||
|
|
||||||
|
export default Info;
|
||||||
205
site/util/api.js
Normal file
205
site/util/api.js
Normal file
@@ -0,0 +1,205 @@
|
|||||||
|
class FunctionDoc {
|
||||||
|
constructor(doc) {
|
||||||
|
this.name = doc.name;
|
||||||
|
this.doc = doc;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class TypedefDoc {
|
||||||
|
constructor(doc) {
|
||||||
|
this.name = doc.name;
|
||||||
|
this.doc = doc;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class ClassDoc {
|
||||||
|
constructor(name) {
|
||||||
|
this.name = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
processDoc(doc) {
|
||||||
|
if (doc.kind === 'class') {
|
||||||
|
this.doc = doc;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class ModuleDoc {
|
||||||
|
constructor(id) {
|
||||||
|
this.id = id;
|
||||||
|
|
||||||
|
this.classLookup = {};
|
||||||
|
this.classes = [];
|
||||||
|
|
||||||
|
this.functionLookup = {};
|
||||||
|
this.functions = [];
|
||||||
|
}
|
||||||
|
|
||||||
|
processDoc(doc) {
|
||||||
|
if (doc.kind === 'module') {
|
||||||
|
this.doc = doc;
|
||||||
|
//console.log('processing module: ' + doc.longname)
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (doc.kind === 'class') {
|
||||||
|
const name = nameFromLongname(doc.longname);
|
||||||
|
if (!(name in this.classLookup)) {
|
||||||
|
const cls = new ClassDoc(name);
|
||||||
|
this.classLookup[name] = cls;
|
||||||
|
this.classes.push(cls);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.classLookup[name].processDoc(doc);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (doc.kind === 'function') {
|
||||||
|
if (nameFromLongname(doc.memberof)) {
|
||||||
|
// belongs to a class or other
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (doc.name in this.functionLookup) {
|
||||||
|
throw new Error(`Duplicate function ${doc.name} in ${this.id}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
const func = new FunctionDoc(doc);
|
||||||
|
this.functionLookup[doc.name] = func;
|
||||||
|
this.functions.push(func);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
finalize() {
|
||||||
|
this.classes.sort(byName);
|
||||||
|
this.functions.sort(byName);
|
||||||
|
this.visible = this.classes.length > 0 || this.functions.length > 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
getExportedName(localName) {
|
||||||
|
if (!this.doc || !this.doc.exportMap) {
|
||||||
|
throw new Error(`Expected to find export map in module doc: ${this.id}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!(localName in this.doc.exportMap)) {
|
||||||
|
throw new Error(
|
||||||
|
`No local name "${localName}" in export map for module: ${this.id}`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return this.doc.exportMap[localName];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const longnameRE = /^module:(?<module>.*?)([~\.](?<name>\w+)(#(?<member>\w+))?(:(?<type>\w+))?)?$/;
|
||||||
|
|
||||||
|
function moduleIDFromLongname(longname) {
|
||||||
|
const match = longname.match(longnameRE);
|
||||||
|
if (!match) {
|
||||||
|
throw new Error(`could not match module id in longname: ${longname}`);
|
||||||
|
}
|
||||||
|
return match.groups.module;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function nameFromLongname(longname) {
|
||||||
|
const match = longname.match(longnameRE);
|
||||||
|
if (!match) {
|
||||||
|
throw new Error(`could not match name in longname: ${longname}`);
|
||||||
|
}
|
||||||
|
return match.groups.name;
|
||||||
|
}
|
||||||
|
|
||||||
|
function memberFromLongname(longname) {
|
||||||
|
const match = longname.match(longnameRE);
|
||||||
|
if (!match) {
|
||||||
|
throw new Error(`could not match member in longname: ${longname}`);
|
||||||
|
}
|
||||||
|
return match.groups.member;
|
||||||
|
}
|
||||||
|
|
||||||
|
function byName(a, b) {
|
||||||
|
if (a.name < b.name) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
if (a.name > b.name) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
function byModuleId(a, b) {
|
||||||
|
const aParts = a.id.split('/');
|
||||||
|
const bParts = b.id.split('/');
|
||||||
|
const len = Math.max(aParts.length, bParts.length);
|
||||||
|
for (let i = 0; i < len; ++i) {
|
||||||
|
if (aParts[i] && bParts[i]) {
|
||||||
|
if (aParts[i] < bParts[i]) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
if (aParts[i] > bParts[i]) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
} else if (!aParts[i]) {
|
||||||
|
return -1;
|
||||||
|
} else {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
class DocHelper {
|
||||||
|
constructor(docs) {
|
||||||
|
this.moduleLookup = {};
|
||||||
|
this.modules = [];
|
||||||
|
|
||||||
|
this.typedefLookup = {};
|
||||||
|
|
||||||
|
docs.forEach(doc => {
|
||||||
|
// typedef are indexed by long name
|
||||||
|
if (doc.kind === 'typedef') {
|
||||||
|
if (doc.name in this.typedefLookup) {
|
||||||
|
throw new Error(`Duplicate type definition ${doc.name} in ${this.id}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
const type = new TypedefDoc(doc);
|
||||||
|
this.typedefLookup[doc.longname] = type;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const moduleID = moduleIDFromLongname(doc.longname);
|
||||||
|
if (!(moduleID in this.moduleLookup)) {
|
||||||
|
const module = new ModuleDoc(moduleID);
|
||||||
|
this.moduleLookup[moduleID] = module;
|
||||||
|
this.modules.push(module);
|
||||||
|
}
|
||||||
|
|
||||||
|
const module = this.moduleLookup[moduleID];
|
||||||
|
module.processDoc(doc);
|
||||||
|
});
|
||||||
|
|
||||||
|
this.modules.sort(byModuleId);
|
||||||
|
this.modules.forEach(module => module.finalize());
|
||||||
|
}
|
||||||
|
|
||||||
|
getTypeDef(longName) {
|
||||||
|
this.typedefLookup[longName] && console.log(this.typedefLookup[longName]);
|
||||||
|
return this.typedefLookup[longName];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let cachedDocs;
|
||||||
|
let cachedHelper;
|
||||||
|
|
||||||
|
export function getHelper(docs) {
|
||||||
|
if (docs !== cachedDocs) {
|
||||||
|
if (cachedDocs) {
|
||||||
|
console.warn('creating new doc helper'); // eslint-disable-line
|
||||||
|
}
|
||||||
|
cachedHelper = new DocHelper(docs);
|
||||||
|
cachedDocs = docs;
|
||||||
|
}
|
||||||
|
|
||||||
|
return cachedHelper;
|
||||||
|
}
|
||||||
9
site/util/typography.js
Normal file
9
site/util/typography.js
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
import Typography from 'typography';
|
||||||
|
import theme from 'typography-theme-alton';
|
||||||
|
|
||||||
|
const typography = new Typography(theme);
|
||||||
|
|
||||||
|
export const baseSpacingPx = parseInt(theme.baseFontSize, 10);
|
||||||
|
|
||||||
|
export {theme};
|
||||||
|
export default typography;
|
||||||
Reference in New Issue
Block a user