feat: docs
This commit is contained in:
parent
6e6cb3f0f4
commit
5e2b825620
28
packages/db/build/dox/hooks.js
Normal file
28
packages/db/build/dox/hooks.js
Normal file
|
@ -0,0 +1,28 @@
|
|||
import {Hooks} from '@flecks/core';
|
||||
|
||||
export default {
|
||||
[Hooks]: {
|
||||
/**
|
||||
* Gather database models.
|
||||
*
|
||||
* In the example below, your fleck would have a `models` subdirectory, and each model would be
|
||||
* defined in its own file.
|
||||
* See: https://github.com/cha0s/flecks/tree/master/packages/user/src/server/models
|
||||
*/
|
||||
'@flecks/db/server/models': Flecks.provide(require.context('./models', false, /\.js$/)),
|
||||
|
||||
/**
|
||||
* Decorate database models.
|
||||
*
|
||||
* In the example below, your fleck would have a `models/decorators` subdirectory, and each
|
||||
* decorator would be defined in its own file.
|
||||
* See: https://github.com/cha0s/flecks/tree/master/packages/user/src/local/server/models/decorators
|
||||
*
|
||||
* @param {constructor} Model The model to decorate.
|
||||
*/
|
||||
'@flecks/db/server/models.decorate': (
|
||||
Flecks.decorate(require.context('./models/decorators', false, /\.js$/))
|
||||
),
|
||||
},
|
||||
};
|
||||
|
27
packages/docker/build/dox/hooks.js
Normal file
27
packages/docker/build/dox/hooks.js
Normal file
|
@ -0,0 +1,27 @@
|
|||
import {Hooks} from '@flecks/core';
|
||||
|
||||
export default {
|
||||
[Hooks]: {
|
||||
/**
|
||||
* Define docker containers.
|
||||
*
|
||||
* Beware: the user running the server must have Docker privileges.
|
||||
* See: https://docs.docker.com/engine/install/linux-postinstall/#manage-docker-as-a-non-root-user
|
||||
*/
|
||||
'@flecks/docker/containers': () => ({
|
||||
someContainer: {
|
||||
// Environment variables.
|
||||
environment: {
|
||||
SOME_CONTAINER_VAR: 'hello',
|
||||
},
|
||||
// The docker image.
|
||||
image: 'some-image:latest',
|
||||
// Some container path you'd like to persist. Flecks handles the host path.
|
||||
mount: '/some/container/path',
|
||||
// Expose ports.
|
||||
ports: {3000: 3000},
|
||||
},
|
||||
}),
|
||||
},
|
||||
};
|
||||
|
116
packages/dox/.gitignore
vendored
Normal file
116
packages/dox/.gitignore
vendored
Normal file
|
@ -0,0 +1,116 @@
|
|||
# Logs
|
||||
logs
|
||||
*.log
|
||||
npm-debug.log*
|
||||
yarn-debug.log*
|
||||
yarn-error.log*
|
||||
lerna-debug.log*
|
||||
|
||||
# Diagnostic reports (https://nodejs.org/api/report.html)
|
||||
report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json
|
||||
|
||||
# Runtime data
|
||||
pids
|
||||
*.pid
|
||||
*.seed
|
||||
*.pid.lock
|
||||
|
||||
# Directory for instrumented libs generated by jscoverage/JSCover
|
||||
lib-cov
|
||||
|
||||
# Coverage directory used by tools like istanbul
|
||||
coverage
|
||||
*.lcov
|
||||
|
||||
# nyc test coverage
|
||||
.nyc_output
|
||||
|
||||
# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files)
|
||||
.grunt
|
||||
|
||||
# Bower dependency directory (https://bower.io/)
|
||||
bower_components
|
||||
|
||||
# node-waf configuration
|
||||
.lock-wscript
|
||||
|
||||
# Compiled binary addons (https://nodejs.org/api/addons.html)
|
||||
build/Release
|
||||
|
||||
# Dependency directories
|
||||
node_modules/
|
||||
jspm_packages/
|
||||
|
||||
# Snowpack dependency directory (https://snowpack.dev/)
|
||||
web_modules/
|
||||
|
||||
# TypeScript cache
|
||||
*.tsbuildinfo
|
||||
|
||||
# Optional npm cache directory
|
||||
.npm
|
||||
|
||||
# Optional eslint cache
|
||||
.eslintcache
|
||||
|
||||
# Microbundle cache
|
||||
.rpt2_cache/
|
||||
.rts2_cache_cjs/
|
||||
.rts2_cache_es/
|
||||
.rts2_cache_umd/
|
||||
|
||||
# Optional REPL history
|
||||
.node_repl_history
|
||||
|
||||
# Output of 'npm pack'
|
||||
*.tgz
|
||||
|
||||
# Yarn Integrity file
|
||||
.yarn-integrity
|
||||
|
||||
# dotenv environment variables file
|
||||
.env
|
||||
.env.test
|
||||
|
||||
# parcel-bundler cache (https://parceljs.org/)
|
||||
.cache
|
||||
.parcel-cache
|
||||
|
||||
# Next.js build output
|
||||
.next
|
||||
out
|
||||
|
||||
# Nuxt.js build / generate output
|
||||
.nuxt
|
||||
dist
|
||||
|
||||
# Gatsby files
|
||||
.cache/
|
||||
# Comment in the public line in if your project uses Gatsby and not Next.js
|
||||
# https://nextjs.org/blog/next-9-1#public-directory-support
|
||||
# public
|
||||
|
||||
# vuepress build output
|
||||
.vuepress/dist
|
||||
|
||||
# Serverless directories
|
||||
.serverless/
|
||||
|
||||
# FuseBox cache
|
||||
.fusebox/
|
||||
|
||||
# DynamoDB Local files
|
||||
.dynamodb/
|
||||
|
||||
# TernJS port file
|
||||
.tern-port
|
||||
|
||||
# Stores VSCode versions used for testing VSCode extensions
|
||||
.vscode-test
|
||||
|
||||
# yarn v2
|
||||
.yarn/cache
|
||||
.yarn/unplugged
|
||||
.yarn/build-state.yml
|
||||
.yarn/install-state.gz
|
||||
.pnp.*
|
2
packages/dox/build/flecks.yml
Normal file
2
packages/dox/build/flecks.yml
Normal file
|
@ -0,0 +1,2 @@
|
|||
'@flecks/core': {}
|
||||
'@flecks/fleck': {}
|
31
packages/dox/package.json
Normal file
31
packages/dox/package.json
Normal file
|
@ -0,0 +1,31 @@
|
|||
{
|
||||
"name": "@flecks/dox",
|
||||
"publishConfig": {
|
||||
"access": "public"
|
||||
},
|
||||
"version": "1.0.0",
|
||||
"main": "index.js",
|
||||
"scripts": {
|
||||
"build": "flecks build",
|
||||
"clean": "flecks clean",
|
||||
"lint": "flecks lint",
|
||||
"test": "flecks test"
|
||||
},
|
||||
"files": [
|
||||
"build",
|
||||
"server.js",
|
||||
"server.js.map",
|
||||
"src"
|
||||
],
|
||||
"dependencies": {
|
||||
"@babel/core": "^7.17.2",
|
||||
"@babel/traverse": "^7.17.0",
|
||||
"@babel/types": "^7.17.0",
|
||||
"@flecks/core": "^1.1.1",
|
||||
"comment-parser": "^1.3.0",
|
||||
"glob": "^7.2.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@flecks/fleck": "^1.0.1"
|
||||
}
|
||||
}
|
46
packages/dox/src/commands.js
Normal file
46
packages/dox/src/commands.js
Normal file
|
@ -0,0 +1,46 @@
|
|||
import {mkdir, writeFile} from 'fs/promises';
|
||||
import {join} from 'path';
|
||||
|
||||
import {D} from '@flecks/core';
|
||||
|
||||
import {generateHookPage, generateTodoPage} from './generate';
|
||||
import {parseFlecks} from './parser';
|
||||
|
||||
const {
|
||||
FLECKS_CORE_ROOT = process.cwd(),
|
||||
} = process.env;
|
||||
|
||||
const debug = D('@flecks/dox/commands');
|
||||
|
||||
export default (program, flecks) => {
|
||||
const commands = {};
|
||||
commands.dox = {
|
||||
description: 'generate documentation for this project',
|
||||
action: async () => {
|
||||
debug('Parsing flecks...');
|
||||
const state = await parseFlecks(flecks);
|
||||
debug('parsed');
|
||||
debug('Generating hooks page...');
|
||||
const hookPage = generateHookPage(state.hooks);
|
||||
debug('generated');
|
||||
debug('Generating TODO page...');
|
||||
const todoPage = generateTodoPage(state.todos);
|
||||
debug('generated');
|
||||
const output = join(FLECKS_CORE_ROOT, 'dox');
|
||||
await mkdir(output, {recursive: true});
|
||||
/* eslint-disable no-console */
|
||||
console.log('');
|
||||
console.group('Output:');
|
||||
debug('Writing hooks page...');
|
||||
await writeFile(join(output, 'hooks.md'), hookPage);
|
||||
console.log('hooks.md');
|
||||
debug('Writing TODO page...');
|
||||
await writeFile(join(output, 'TODO.md'), todoPage);
|
||||
console.log('TODO.md');
|
||||
console.groupEnd();
|
||||
console.log('');
|
||||
/* eslint-enable no-console */
|
||||
},
|
||||
};
|
||||
return commands;
|
||||
};
|
87
packages/dox/src/generate.js
Normal file
87
packages/dox/src/generate.js
Normal file
|
@ -0,0 +1,87 @@
|
|||
export const generateHookPage = (hooks) => {
|
||||
const source = [];
|
||||
source.push('# Hooks');
|
||||
source.push('');
|
||||
source.push('This page documents all the hooks in this project.');
|
||||
source.push('');
|
||||
Object.entries(hooks)
|
||||
.sort(([lhook], [rhook]) => (lhook < rhook ? -1 : 1))
|
||||
.forEach(([hook, {implementations = [], invocations = [], specification}]) => {
|
||||
source.push(`## \`${hook}\``);
|
||||
source.push('');
|
||||
const {description, example, params} = specification || {
|
||||
params: [],
|
||||
};
|
||||
if (description) {
|
||||
description.split('\n').forEach((line) => {
|
||||
source.push(`> ${line}`);
|
||||
});
|
||||
source.push('');
|
||||
}
|
||||
if (params.length > 0) {
|
||||
source.push('<details>');
|
||||
source.push('<summary>Parameters</summary>');
|
||||
source.push('<ul>');
|
||||
params.forEach(({description, name, type}) => {
|
||||
source.push(`<li><strong><code>{${type}}</code></strong> <code>${name}</code>`);
|
||||
source.push(`<blockquote>${description}</blockquote></li>`);
|
||||
});
|
||||
source.push('</ul>');
|
||||
source.push('</details>');
|
||||
source.push('');
|
||||
}
|
||||
if (implementations.length > 0) {
|
||||
source.push('<details>');
|
||||
source.push('<summary>Implementations</summary>');
|
||||
source.push('<ul>');
|
||||
implementations.forEach(({filename, loc: {start: {column, line}}}) => {
|
||||
source.push(`<li>${filename}:${line}:${column}</li>`);
|
||||
});
|
||||
source.push('</ul>');
|
||||
source.push('</details>');
|
||||
source.push('');
|
||||
}
|
||||
if (invocations.length > 0) {
|
||||
source.push('<details>');
|
||||
source.push('<summary>Invocations</summary>');
|
||||
source.push('<ul>');
|
||||
invocations.forEach(({filename, loc: {start: {column, line}}}) => {
|
||||
source.push(`<li>${filename}:${line}:${column}</li>`);
|
||||
});
|
||||
source.push('</ul>');
|
||||
source.push('</details>');
|
||||
source.push('');
|
||||
}
|
||||
if (example) {
|
||||
source.push('### Example usage');
|
||||
source.push('');
|
||||
source.push('```javascript');
|
||||
source.push('export default {');
|
||||
source.push(' [Hooks]: {');
|
||||
source.push(` '${hook}': ${example}`);
|
||||
source.push(' },');
|
||||
source.push('};');
|
||||
source.push('```');
|
||||
source.push('');
|
||||
}
|
||||
});
|
||||
return source.join('\n');
|
||||
};
|
||||
|
||||
export const generateTodoPage = (todos) => {
|
||||
const source = [];
|
||||
source.push('# TODO');
|
||||
source.push('');
|
||||
source.push('This page documents all the TODO items in this project.');
|
||||
source.push('');
|
||||
if (todos.length > 0) {
|
||||
todos.forEach(({filename, loc: {start: {column, line}}, text}) => {
|
||||
source.push(`- ${filename}:${line}:${column}`);
|
||||
text.split('\n').forEach((line) => {
|
||||
source.push(` > ${line}`);
|
||||
});
|
||||
});
|
||||
source.push('');
|
||||
}
|
||||
return source.join('\n');
|
||||
};
|
259
packages/dox/src/parser.js
Normal file
259
packages/dox/src/parser.js
Normal file
|
@ -0,0 +1,259 @@
|
|||
import {readFile} from 'fs/promises';
|
||||
import {dirname, join} from 'path';
|
||||
|
||||
import {transformAsync} from '@babel/core';
|
||||
import traverse from '@babel/traverse';
|
||||
import {
|
||||
isIdentifier,
|
||||
isLiteral,
|
||||
isMemberExpression,
|
||||
isObjectExpression,
|
||||
isStringLiteral,
|
||||
isThisExpression,
|
||||
} from '@babel/types';
|
||||
import {require as R} from '@flecks/core/server';
|
||||
import {parse as parseComment} from 'comment-parser';
|
||||
import glob from 'glob';
|
||||
|
||||
const flecksCorePath = dirname(__non_webpack_require__.resolve('@flecks/core/package.json'));
|
||||
|
||||
class ParserState {
|
||||
|
||||
constructor() {
|
||||
this.hooks = {};
|
||||
this.todos = [];
|
||||
}
|
||||
|
||||
addImplementation(hook, filename, loc) {
|
||||
this.hooks[hook] = this.hooks[hook] || {};
|
||||
this.hooks[hook].implementations = this.hooks[hook].implementations || [];
|
||||
this.hooks[hook].implementations.push({filename, loc});
|
||||
}
|
||||
|
||||
addInvocation(hook, type, filename, loc) {
|
||||
this.hooks[hook] = this.hooks[hook] || {};
|
||||
this.hooks[hook].invocations = this.hooks[hook].invocations || [];
|
||||
this.hooks[hook].invocations.push({filename, loc, type});
|
||||
}
|
||||
|
||||
addSpecification(hook, specification) {
|
||||
this.hooks[hook] = this.hooks[hook] || {};
|
||||
this.hooks[hook].specification = specification;
|
||||
}
|
||||
|
||||
addTodo(comment, filename) {
|
||||
this.todos.push({filename, loc: comment.loc, text: comment.value.trim()});
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
const FlecksInvocations = (state, filename) => ({
|
||||
CallExpression(path) {
|
||||
if (isMemberExpression(path.node.callee)) {
|
||||
if (
|
||||
(isIdentifier(path.node.callee.object) && 'flecks' === path.node.callee.object.name)
|
||||
|| (
|
||||
(
|
||||
isThisExpression(path.node.callee.object)
|
||||
&& (filename === join(flecksCorePath, 'src', 'flecks.js'))
|
||||
)
|
||||
)
|
||||
) {
|
||||
if (isIdentifier(path.node.callee.property)) {
|
||||
if (path.node.callee.property.name.match(/^invoke.*/)) {
|
||||
if (path.node.arguments.length > 0) {
|
||||
if (isStringLiteral(path.node.arguments[0])) {
|
||||
state.addInvocation(
|
||||
path.node.arguments[0].value,
|
||||
path.node.callee.property.name,
|
||||
filename,
|
||||
path.node.loc,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
if ('up' === path.node.callee.property.name) {
|
||||
if (path.node.arguments.length > 0) {
|
||||
if (isStringLiteral(path.node.arguments[0])) {
|
||||
state.addInvocation(
|
||||
path.node.arguments[0].value,
|
||||
'invokeSequentialAsync',
|
||||
filename,
|
||||
path.node.loc,
|
||||
);
|
||||
state.addInvocation(
|
||||
'@flecks/core/starting',
|
||||
'invokeFlat',
|
||||
filename,
|
||||
path.node.loc,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
if ('gather' === path.node.callee.property.name) {
|
||||
if (path.node.arguments.length > 0) {
|
||||
if (isStringLiteral(path.node.arguments[0])) {
|
||||
state.addInvocation(
|
||||
path.node.arguments[0].value,
|
||||
'invokeReduce',
|
||||
filename,
|
||||
path.node.loc,
|
||||
);
|
||||
state.addInvocation(
|
||||
`${path.node.arguments[0].value}.decorate`,
|
||||
'invokeComposed',
|
||||
filename,
|
||||
path.node.loc,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
const implementationVisitor = (fn) => {
|
||||
let hooksSymbol;
|
||||
return {
|
||||
ExportDefaultDeclaration(path) {
|
||||
const {declaration} = path.node;
|
||||
if (isObjectExpression(declaration)) {
|
||||
const {properties} = declaration;
|
||||
properties.forEach((property) => {
|
||||
const {key, value} = property;
|
||||
if (isIdentifier(key) && key.name === hooksSymbol) {
|
||||
if (isObjectExpression(value)) {
|
||||
const {properties} = value;
|
||||
properties.forEach((property) => {
|
||||
const {key} = property;
|
||||
if (isLiteral(key)) {
|
||||
fn(path, property);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
},
|
||||
ImportDeclaration(path) {
|
||||
const {source, specifiers} = path.node;
|
||||
if ('@flecks/core' === source.value) {
|
||||
specifiers.forEach((specifier) => {
|
||||
const {imported, local} = specifier;
|
||||
if ('Hooks' === imported.name) {
|
||||
hooksSymbol = local.name;
|
||||
}
|
||||
});
|
||||
}
|
||||
},
|
||||
};
|
||||
};
|
||||
|
||||
const FlecksImplementations = (state, filename) => (
|
||||
implementationVisitor((path, {key}) => {
|
||||
state.addImplementation(
|
||||
key.value,
|
||||
filename,
|
||||
path.node.loc,
|
||||
);
|
||||
})
|
||||
);
|
||||
|
||||
const FlecksSpecifications = (state, source) => (
|
||||
implementationVisitor((path, property) => {
|
||||
if (property.leadingComments) {
|
||||
const {key, value: example} = property;
|
||||
const [{value}] = property.leadingComments;
|
||||
const [{description, tags}] = parseComment(`/**\n${value}\n*/`, {spacing: 'preserve'});
|
||||
const params = tags
|
||||
.filter(({tag}) => 'param' === tag)
|
||||
.map(({description, name, type}) => ({description, name, type}));
|
||||
state.addSpecification(
|
||||
key.value,
|
||||
{
|
||||
description,
|
||||
example: source.slice(example.start, example.end),
|
||||
params,
|
||||
},
|
||||
);
|
||||
}
|
||||
})
|
||||
);
|
||||
|
||||
const FlecksTodos = (state, filename) => ({
|
||||
enter(path) {
|
||||
if (path.node.leadingComments) {
|
||||
path.node.leadingComments.forEach((comment) => {
|
||||
if (comment.value.toLowerCase().match('@todo')) {
|
||||
state.addTodo(comment, filename);
|
||||
}
|
||||
});
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
export const parseCode = async (code) => {
|
||||
const config = {
|
||||
ast: true,
|
||||
code: false,
|
||||
};
|
||||
const {ast} = await transformAsync(code, config);
|
||||
return ast;
|
||||
};
|
||||
|
||||
export const parseFile = async (filename, resolved, state) => {
|
||||
const buffer = await readFile(filename);
|
||||
const ast = await parseCode(buffer.toString('utf8'));
|
||||
traverse(ast, FlecksInvocations(state, resolved));
|
||||
traverse(ast, FlecksImplementations(state, resolved));
|
||||
traverse(ast, FlecksTodos(state, resolved));
|
||||
};
|
||||
|
||||
const fleckSources = async (path) => (
|
||||
new Promise((r, e) => (
|
||||
glob(
|
||||
join(path, 'src', '**', '*.js'),
|
||||
(error, result) => (error ? e(error) : r(result)),
|
||||
)
|
||||
))
|
||||
);
|
||||
|
||||
export const parseFleckRoot = async (root, state) => {
|
||||
const resolved = dirname(R.resolve(join(root, 'package.json')));
|
||||
const sources = await fleckSources(resolved);
|
||||
await Promise.all(
|
||||
sources.map(async (source) => {
|
||||
await parseFile(source, join(root, source.slice(resolved.length)), state);
|
||||
}),
|
||||
);
|
||||
try {
|
||||
const buffer = await readFile(join(resolved, 'build', 'dox', 'hooks.js'));
|
||||
const source = buffer.toString('utf8');
|
||||
const ast = await parseCode(source);
|
||||
traverse(ast, FlecksSpecifications(state, source));
|
||||
}
|
||||
catch (error) {
|
||||
if ('ENOENT' !== error.code) {
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
export const parseFlecks = async (flecks) => {
|
||||
const state = new ParserState();
|
||||
const paths = Object.keys(flecks.resolver);
|
||||
const roots = Array.from(new Set(
|
||||
paths
|
||||
.map((path) => flecks.root(path))
|
||||
.filter((e) => !!e),
|
||||
));
|
||||
await Promise.all(
|
||||
roots
|
||||
.map(async (root) => {
|
||||
await parseFleckRoot(root, state);
|
||||
}),
|
||||
);
|
||||
return state;
|
||||
};
|
9
packages/dox/src/server.js
Normal file
9
packages/dox/src/server.js
Normal file
|
@ -0,0 +1,9 @@
|
|||
import {Hooks} from '@flecks/core';
|
||||
|
||||
import commands from './commands';
|
||||
|
||||
export default {
|
||||
[Hooks]: {
|
||||
'@flecks/core/commands': commands,
|
||||
},
|
||||
};
|
69
packages/http/build/dox/hooks.js
Normal file
69
packages/http/build/dox/hooks.js
Normal file
|
@ -0,0 +1,69 @@
|
|||
import {Hooks} from '@flecks/core';
|
||||
|
||||
export default {
|
||||
[Hooks]: {
|
||||
/**
|
||||
* Define sequential actions to run when the client comes up.
|
||||
*/
|
||||
'@flecks/http/client/up': async () => {
|
||||
await youCanDoAsyncThingsHere();
|
||||
},
|
||||
/**
|
||||
* Override flecks configuration sent to client flecks.
|
||||
* @param {http.ClientRequest} req The HTTP request object.
|
||||
*/
|
||||
'@flecks/http/config': (req) => ({
|
||||
someClientFleck: {
|
||||
someConfig: req.someConfig,
|
||||
},
|
||||
}),
|
||||
/**
|
||||
* Define HTTP routes.
|
||||
*/
|
||||
'@flecks/http/routes': () => [
|
||||
{
|
||||
method: 'get',
|
||||
path: '/some-path',
|
||||
middleware: (req, res, next) => {
|
||||
// Express-style route middleware...
|
||||
next();
|
||||
},
|
||||
},
|
||||
],
|
||||
/**
|
||||
* Define neutrino compilation middleware (e.g. @neutrinojs/react).
|
||||
*/
|
||||
'@flecks/http/server/compiler': () => {
|
||||
return require('@neutrinojs/node');
|
||||
},
|
||||
/**
|
||||
* Define middleware to run when a route is matched.
|
||||
*/
|
||||
'@flecks/http/server/request.route': () => (req, res, next) => {
|
||||
// Express-style route middleware...
|
||||
next();
|
||||
},
|
||||
/**
|
||||
* Define middleware to run when an HTTP socket connection is established.
|
||||
*/
|
||||
'@flecks/http/server/request.socket': () => (req, res, next) => {
|
||||
// Express-style route middleware...
|
||||
next();
|
||||
},
|
||||
/**
|
||||
* Define composition functions to run over the HTML stream prepared for the client.
|
||||
* @param {stream.Readable} stream The HTML stream.
|
||||
* @param {http.ClientRequest} req The HTTP request object.
|
||||
*/
|
||||
'@flecks/http/server/stream.html': (stream, req) => {
|
||||
return stream.pipe(myTransformStream);
|
||||
},
|
||||
/**
|
||||
* Define sequential actions to run when the HTTP server comes up.
|
||||
*/
|
||||
'@flecks/http/server/up': async () => {
|
||||
await youCanDoAsyncThingsHere();
|
||||
},
|
||||
},
|
||||
};
|
||||
|
27
packages/react/build/dox/hooks.js
Normal file
27
packages/react/build/dox/hooks.js
Normal file
|
@ -0,0 +1,27 @@
|
|||
import {Hooks} from '@flecks/core';
|
||||
|
||||
export default {
|
||||
[Hooks]: {
|
||||
/**
|
||||
* Define React Providers.
|
||||
*
|
||||
* Note: `req` will be only be defined when server-side rendering.
|
||||
* @param {http.ClientRequest} req The HTTP request object.
|
||||
*/
|
||||
'@flecks/react/providers': (req) => {
|
||||
// Generally it makes more sense to separate client and server concerns using platform
|
||||
// naming conventions, but this is just a small contrived example.
|
||||
return req ? serverSideProvider(req) : clientSideProvider();
|
||||
},
|
||||
/**
|
||||
* Define root-level React components that are mounted as siblings on `#main`.
|
||||
* Note: `req` will be only be defined when server-side rendering.
|
||||
* @param {http.ClientRequest} req The HTTP request object.
|
||||
*/
|
||||
'@flecks/react/roots': (req) => {
|
||||
// Note that we're not returning `<Component />`, but `Component`.
|
||||
return Component;
|
||||
},
|
||||
},
|
||||
};
|
||||
|
45
packages/redux/build/dox/hooks.js
Normal file
45
packages/redux/build/dox/hooks.js
Normal file
|
@ -0,0 +1,45 @@
|
|||
import {Hooks} from '@flecks/core';
|
||||
|
||||
export default {
|
||||
[Hooks]: {
|
||||
/**
|
||||
* Define side-effects to run against Redux actions.
|
||||
*/
|
||||
'@flecks/redux/effects': () => ({
|
||||
someActionName: (store, action, flecks) => {
|
||||
// Runs when `someActionName` actions are dispatched.
|
||||
},
|
||||
}),
|
||||
/**
|
||||
* Define root-level reducers for the Redux store.
|
||||
*/
|
||||
'@flecks/redux/reducers': () => {
|
||||
return (state, action) => {
|
||||
// Whatever you'd like.
|
||||
return state;
|
||||
};
|
||||
},
|
||||
/**
|
||||
* Define Redux slices.
|
||||
*
|
||||
* See: https://redux-toolkit.js.org/api/createSlice
|
||||
*/
|
||||
'@flecks/redux/slices': () => {
|
||||
const something = createSlice(
|
||||
// ...
|
||||
);
|
||||
return {
|
||||
something: something.reducer,
|
||||
};
|
||||
},
|
||||
/**
|
||||
* Modify Redux store configuration.
|
||||
* @param {Object} options A mutable object with keys for enhancers and middleware.
|
||||
*/
|
||||
'@flecks/redux/store': (options) => {
|
||||
options.enhancers.splice(someIndex, 1);
|
||||
options.middleware.push(mySpecialMiddleware);
|
||||
},
|
||||
},
|
||||
};
|
||||
|
30
packages/repl/build/dox/hooks.js
Normal file
30
packages/repl/build/dox/hooks.js
Normal file
|
@ -0,0 +1,30 @@
|
|||
import {Hooks} from '@flecks/core';
|
||||
|
||||
export default {
|
||||
[Hooks]: {
|
||||
/**
|
||||
* Define REPL commands.
|
||||
*
|
||||
* Note: commands will be prefixed with a period in the Node REPL.
|
||||
*/
|
||||
'@flecks/repl/commands': () => ({
|
||||
someCommand: (...args) => {
|
||||
// args are passed from the Node REPL. So, you could invoke it like:
|
||||
// .someCommand foo bar
|
||||
// and `args` would be `['foo', 'bar']`.
|
||||
},
|
||||
}),
|
||||
/**
|
||||
* Provide global context to the REPL.
|
||||
*/
|
||||
'@flecks/repl/context': () => {
|
||||
// Now you'd be able to do like:
|
||||
// `node> someValue;`
|
||||
// and the REPL would evaluate it to `'foobar'`.
|
||||
return {
|
||||
someValue: 'foobar',
|
||||
};
|
||||
},
|
||||
},
|
||||
};
|
||||
|
19
packages/server/build/dox/hooks.js
Normal file
19
packages/server/build/dox/hooks.js
Normal file
|
@ -0,0 +1,19 @@
|
|||
import {Hooks} from '@flecks/core';
|
||||
|
||||
export default {
|
||||
[Hooks]: {
|
||||
/**
|
||||
* Define neutrino compilation middleware (e.g. @neutrinojs/react).
|
||||
*/
|
||||
'@flecks/server/compiler': () => {
|
||||
return require('@neutrinojs/node');
|
||||
},
|
||||
/**
|
||||
* Define sequential actions to run when the server comes up.
|
||||
*/
|
||||
'@flecks/server/up': async () => {
|
||||
await youCanDoAsyncThingsHere();
|
||||
},
|
||||
},
|
||||
};
|
||||
|
65
packages/socket/build/dox/hooks.js
Normal file
65
packages/socket/build/dox/hooks.js
Normal file
|
@ -0,0 +1,65 @@
|
|||
import {Hooks} from '@flecks/core';
|
||||
|
||||
export default {
|
||||
[Hooks]: {
|
||||
/**
|
||||
* Modify Socket.io client configuration.
|
||||
*
|
||||
* See: https://socket.io/docs/v4/client-options/
|
||||
*/
|
||||
'@flecks/socket/client': () => ({
|
||||
timeout: Infinity,
|
||||
}),
|
||||
/**
|
||||
* Define server-side intercom channels.
|
||||
*/
|
||||
'@flecks/socket/intercom': (req) => ({
|
||||
// This would have been called like:
|
||||
// `const result = await req.intercom('someChannel', payload)`.
|
||||
// `result` will be an `n`-length array, where `n` is the number of server instances. Each
|
||||
// element in the array will be the result of `someServiceSpecificInformation()` running
|
||||
// against that server instance.
|
||||
someChannel: async (payload, server) => {
|
||||
return someServiceSpecificInformation();
|
||||
},
|
||||
}),
|
||||
/**
|
||||
* Define socket packets.
|
||||
*
|
||||
* In the example below, your fleck would have a `packets` subdirectory, and each
|
||||
* decorator would be defined in its own file.
|
||||
* See: https://github.com/cha0s/flecks/tree/master/packages/redux/src/packets
|
||||
*
|
||||
* See: https://github.com/cha0s/flecks/tree/master/packages/socket/src/packet/packet.js
|
||||
* See: https://github.com/cha0s/flecks/tree/master/packages/socket/src/packet/redirect.js
|
||||
*/
|
||||
'@flecks/socket/packets': Flecks.provide(require.context('./packets', false, /\.js$/)),
|
||||
/**
|
||||
* Decorate database models.
|
||||
*
|
||||
* In the example below, your fleck would have a `packets/decorators` subdirectory, and each
|
||||
* decorator would be defined in its own file.
|
||||
* @param {constructor} Packet The packet to decorate.
|
||||
*/
|
||||
'@flecks/socket/packets.decorate': (
|
||||
Flecks.decorate(require.context('./packets/decorators', false, /\.js$/))
|
||||
),
|
||||
|
||||
/**
|
||||
* Modify Socket.io server configuration.
|
||||
*
|
||||
* See: https://socket.io/docs/v4/server-options/
|
||||
*/
|
||||
'@flecks/socket/server': () => ({
|
||||
pingTimeout: Infinity,
|
||||
}),
|
||||
/**
|
||||
* Define middleware to run when a socket connection is established.
|
||||
*/
|
||||
'@flecks/socket/server/request.socket': () => (socket, next) => {
|
||||
// Express-style route middleware...
|
||||
next();
|
||||
},
|
||||
},
|
||||
};
|
||||
|
15
packages/user/build/dox/hooks.js
Normal file
15
packages/user/build/dox/hooks.js
Normal file
|
@ -0,0 +1,15 @@
|
|||
import {Hooks} from '@flecks/core';
|
||||
|
||||
export default {
|
||||
[Hooks]: {
|
||||
/**
|
||||
* Modify express-session configuration.
|
||||
*
|
||||
* See: https://www.npmjs.com/package/express-session
|
||||
*/
|
||||
'@flecks/user/session': () => ({
|
||||
saveUninitialized: true,
|
||||
}),
|
||||
},
|
||||
};
|
||||
|
Loading…
Reference in New Issue
Block a user