diff --git a/.gitignore b/.gitignore index 50d7c7b9161..ad98096af78 100644 --- a/.gitignore +++ b/.gitignore @@ -57,7 +57,3 @@ testem.log .DS_Store .vscode/settings.json .vscode/launch.json -libs/remix-node/ -libs/remix-niks/ - -apps/remix-react \ No newline at end of file diff --git a/apps/doc-gen/.eslintrc.json b/apps/doc-gen/.eslintrc.json new file mode 100644 index 00000000000..a92d0f887ac --- /dev/null +++ b/apps/doc-gen/.eslintrc.json @@ -0,0 +1,34 @@ +{ + "extends": [ + "plugin:@nrwl/nx/react", + "../../.eslintrc.json" + ], + "ignorePatterns": [ + "!**/*" + ], + "overrides": [ + { + "files": [ + "*.ts", + "*.tsx", + "*.js", + "*.jsx" + ], + "rules": {} + }, + { + "files": [ + "*.ts", + "*.tsx" + ], + "rules": {} + }, + { + "files": [ + "*.js", + "*.jsx" + ], + "rules": {} + } + ] +} \ No newline at end of file diff --git a/apps/doc-gen/.prettierrc b/apps/doc-gen/.prettierrc new file mode 100644 index 00000000000..6e6d086922c --- /dev/null +++ b/apps/doc-gen/.prettierrc @@ -0,0 +1,13 @@ +{ + "semi": false, + "singleQuote": true, + "trailingComma": "all", + "printWidth": 120, + "tabWidth": 2, + "useTabs": false, + "arrowParens": "avoid", + "bracketSpacing": true, + "jsxBracketSameLine": false, + "jsxSingleQuote": false, + "endOfLine": "lf" +} \ No newline at end of file diff --git a/apps/doc-gen/project.json b/apps/doc-gen/project.json new file mode 100644 index 00000000000..51d9d63212c --- /dev/null +++ b/apps/doc-gen/project.json @@ -0,0 +1,59 @@ +{ + "name": "doc-gen", + "$schema": "../../node_modules/nx/schemas/project-schema.json", + "sourceRoot": "apps/doc-gen/src", + "projectType": "application", + "implicitDependencies": [ + ], + "targets": { + "build": { + "executor": "@nrwl/webpack:webpack", + "outputs": ["{options.outputPath}"], + "defaultConfiguration": "development", + "options": { + "compiler": "babel", + "outputPath": "dist/apps/doc-gen", + "index": "apps/doc-gen/src/index.html", + "baseHref": "/", + "main": "apps/doc-gen/src/main.tsx", + "tsConfig": "apps/doc-gen/tsconfig.app.json", + "assets": [ + "apps/doc-gen/src/favicon.ico" + ], + "styles": [], + "scripts": [], + "webpackConfig": "apps/doc-gen/webpack.config.js" + }, + "configurations": { + "development": { + }, + "production": { + "fileReplacements": [ + { + "replace": "apps/doc-gen/src/environments/environment.ts", + "with": "apps/doc-gen/src/environments/environment.prod.ts" + } + ] + } + } + }, + "serve": { + "executor": "@nrwl/webpack:dev-server", + "defaultConfiguration": "development", + "options": { + "buildTarget": "doc-gen:build", + "hmr": true + }, + "configurations": { + "development": { + "buildTarget": "doc-gen:build:development", + "port": 6003 + }, + "production": { + "buildTarget": "doc-gen:build:production" + } + } + } + }, + "tags": [] +} diff --git a/apps/doc-gen/src/app/App.css b/apps/doc-gen/src/app/App.css new file mode 100644 index 00000000000..609253955e2 --- /dev/null +++ b/apps/doc-gen/src/app/App.css @@ -0,0 +1,3 @@ +body { + margin: 0; +} \ No newline at end of file diff --git a/apps/doc-gen/src/app/App.tsx b/apps/doc-gen/src/app/App.tsx new file mode 100644 index 00000000000..358d6776b63 --- /dev/null +++ b/apps/doc-gen/src/app/App.tsx @@ -0,0 +1,42 @@ +import React, { useState, useEffect } from 'react' +import { + CompilationResult, +} from '@remixproject/plugin-api/' + +import './App.css' +import { DocGenClient } from './docgen-client' +import { Build } from './docgen/site' + +export const client = new DocGenClient() + +const App = () => { + const [themeType, setThemeType] = useState('dark'); + const [hasBuild, setHasBuild] = useState(false); + const [fileName, setFileName] = useState(''); + + useEffect(() => { + const watchThemeSwitch = async () => { + client.eventEmitter.on('themeChanged', (theme: string) => { + setThemeType(theme) + }) + client.eventEmitter.on('compilationFinished', (build: Build, fileName: string) => { + setHasBuild(true) + setFileName(fileName) + }) + client.eventEmitter.on('docsGenerated', (docs: string[]) => { + console.log('docsGenerated', docs) + }) + } + watchThemeSwitch() + }, []) + + return ( +
+

Remix Docgen

+ {fileName &&

File: {fileName.split('/')[1].split('.')[0].concat('.sol')}

} + {hasBuild && } +
+ ) +} + +export default App diff --git a/apps/doc-gen/src/app/docgen-client.ts b/apps/doc-gen/src/app/docgen-client.ts new file mode 100644 index 00000000000..76d702c6b49 --- /dev/null +++ b/apps/doc-gen/src/app/docgen-client.ts @@ -0,0 +1,80 @@ +import { PluginClient } from '@remixproject/plugin' +import { CompilationResult, SourceWithTarget } from '@remixproject/plugin-api' +import { createClient } from '@remixproject/plugin-webview' +import EventEmitter from 'events' +import { Config, defaults } from './docgen/config' +import { Build, buildSite } from './docgen/site' +import { loadTemplates } from './docgen/templates' +import { SolcInput, SolcOutput } from 'solidity-ast/solc' +import { render } from './docgen/render' + +export class DocGenClient extends PluginClient { + private currentTheme + public eventEmitter: EventEmitter + private build: Build + public docs: string[] = [] + private fileName: string = '' + + constructor() { + super() + this.eventEmitter = new EventEmitter() + this.methods = ['generateDocs', 'opendDocs'] + createClient(this) + this.onload().then(async () => { + await this.setListeners() + }) + } + + async setListeners() { + this.currentTheme = await this.call('theme', 'currentTheme') + + this.on('theme', 'themeChanged', (theme: any) => { + this.currentTheme = theme + this.eventEmitter.emit('themeChanged', this.currentTheme) + }); + this.eventEmitter.emit('themeChanged', this.currentTheme) + + this.on('solidity', 'compilationFinished', (fileName: string, source: SourceWithTarget, languageVersion: string, data: CompilationResult) => { + const input: SolcInput = { + sources: source.sources + } + const output: SolcOutput = { + sources: data.sources as any + } + this.build = { + input: input, + output: output + } + this.fileName = fileName + this.eventEmitter.emit('compilationFinished', this.build, fileName) + }) + } + + async docgen(builds: Build[], userConfig?: Config): Promise { + const config = { ...defaults, ...userConfig } + const templates = await loadTemplates(config.theme, config.root, config.templates) + const site = buildSite(builds, config, templates.properties ?? {}) + const renderedSite = render(site, templates, config.collapseNewlines) + const docs: string[] = [] + for (const { id, contents } of renderedSite) { + const temp = `${this.fileName.split('/')[1].split('.')[0]}.${id.split('.')[1]}` + const newFileName = `docs/${temp}` + await this.call('fileManager', 'setFile', newFileName , contents) + docs.push(newFileName) + } + this.eventEmitter.emit('docsGenerated', docs) + this.emit('docgen' as any, 'docsGenerated', docs) + this.docs = docs + await this.opendDocs(docs) + } + + async opendDocs(docs: string[]) { + await this.call('manager', 'activatePlugin', 'doc-viewer') + await this.call('tabs' as any, 'focus', 'doc-viewer') + await this.call('doc-viewer' as any, 'viewDocs', docs) + } + + async generateDocs() { + this.docgen([this.build]) + } +} diff --git a/apps/doc-gen/src/app/docgen/common/helpers.ts b/apps/doc-gen/src/app/docgen/common/helpers.ts new file mode 100644 index 00000000000..926e6df9da8 --- /dev/null +++ b/apps/doc-gen/src/app/docgen/common/helpers.ts @@ -0,0 +1,22 @@ +import { VariableDeclaration } from "solidity-ast"; + +export function trim(text: string) { + if (typeof text === 'string') { + return text.trim(); + } +} + +export function joinLines(text?: string) { + if (typeof text === 'string') { + return text.replace(/\n+/g, ' '); + } +} + +/** + * Format a variable as its type followed by its name, if available. + */ +export function formatVariable(v: VariableDeclaration): string { + return [v.typeName?.typeDescriptions.typeString].concat(v.name || []).join(' '); +} + +export const eq = (a: unknown, b: unknown) => a === b; diff --git a/apps/doc-gen/src/app/docgen/common/properties.ts b/apps/doc-gen/src/app/docgen/common/properties.ts new file mode 100644 index 00000000000..460090a0364 --- /dev/null +++ b/apps/doc-gen/src/app/docgen/common/properties.ts @@ -0,0 +1,138 @@ +import { EnumDefinition, ErrorDefinition, EventDefinition, FunctionDefinition, ModifierDefinition, ParameterList, StructDefinition, UserDefinedValueTypeDefinition, VariableDeclaration } from 'solidity-ast'; +import { findAll, isNodeType } from 'solidity-ast/utils'; +import { NatSpec, parseNatspec } from '../utils/natspec'; +import { DocItemContext, DOC_ITEM_CONTEXT } from '../site'; +import { mapValues } from '../utils/map-values'; +import { DocItem, docItemTypes } from '../doc-item'; +import { formatVariable } from './helpers'; +import { PropertyGetter } from '../templates'; +import { itemType } from '../utils/item-type'; + +type TypeDefinition = StructDefinition | EnumDefinition | UserDefinedValueTypeDefinition; + +export function type ({ item }: DocItemContext): string { + return itemType(item); +} + +export function natspec ({ item }: DocItemContext): NatSpec { + return parseNatspec(item); +} + +export function name({ item }: DocItemContext, original?: unknown): string { + if (item.nodeType === 'FunctionDefinition') { + return item.kind === 'function' ? original as string : item.kind; + } else { + return original as string; + } +} + +export function fullName ({ item, contract }: DocItemContext): string { + if (contract) { + return `${contract.name}.${item.name}`; + } else { + return `${item.name}`; + } +} + +export function signature ({ item }: DocItemContext): string | undefined { + switch (item.nodeType) { + case 'ContractDefinition': + return undefined; + + case 'FunctionDefinition': { + const { kind, name } = item; + const params = item.parameters.parameters; + const returns = item.returnParameters.parameters; + const head = (kind === 'function' || kind === 'freeFunction') ? [kind, name].join(' ') : kind; + const res = [ + `${head}(${params.map(formatVariable).join(', ')})`, + item.visibility, + ]; + if (item.stateMutability !== 'nonpayable') { + res.push(item.stateMutability); + } + if (item.virtual) { + res.push('virtual'); + } + if (returns.length > 0) { + res.push(`returns (${returns.map(formatVariable).join(', ')})`); + } + return res.join(' '); + } + + case 'EventDefinition': { + const params = item.parameters.parameters; + return `event ${item.name}(${params.map(formatVariable).join(', ')})`; + } + + case 'ErrorDefinition': { + const params = item.parameters.parameters; + return `error ${item.name}(${params.map(formatVariable).join(', ')})`; + } + + case 'ModifierDefinition': { + const params = item.parameters.parameters; + return `modifier ${item.name}(${params.map(formatVariable).join(', ')})`; + } + + case 'VariableDeclaration': + return formatVariable(item); + } +} + +interface Param extends VariableDeclaration { + type: string; + natspec?: string; +}; + +function getParams (params: ParameterList, natspec: NatSpec['params'] | NatSpec['returns']): Param[] { + return params.parameters.map((p, i) => ({ + ...p, + type: p.typeDescriptions.typeString!, + natspec: natspec?.find((q, j) => q.name === undefined ? i === j : p.name === q.name)?.description, + })); +} + +export function params ({ item }: DocItemContext): Param[] | undefined { + if ('parameters' in item) { + return getParams(item.parameters, natspec(item[DOC_ITEM_CONTEXT]).params); + } +} + +export function returns ({ item }: DocItemContext): Param[] | undefined { + if ('returnParameters' in item) { + return getParams(item.returnParameters, natspec(item[DOC_ITEM_CONTEXT]).returns); + } +} + +export function items ({ item }: DocItemContext): DocItem[] | undefined { + return (item.nodeType === 'ContractDefinition') + ? item.nodes.filter(isNodeType(docItemTypes)).filter(n => !('visibility' in n) || n.visibility !== 'private') + : undefined; +} + +export function functions ({ item }: DocItemContext): FunctionDefinition[] | undefined { + return [...findAll('FunctionDefinition', item)].filter(f => f.visibility !== 'private'); +} + +export function events ({ item }: DocItemContext): EventDefinition[] | undefined { + return [...findAll('EventDefinition', item)]; +} + +export function modifiers ({ item }: DocItemContext): ModifierDefinition[] | undefined { + return [...findAll('ModifierDefinition', item)]; +} + +export function errors ({ item }: DocItemContext): ErrorDefinition[] | undefined { + return [...findAll('ErrorDefinition', item)]; +} + +export function variables ({ item }: DocItemContext): VariableDeclaration[] | undefined { + return (item.nodeType === 'ContractDefinition') + ? item.nodes.filter(isNodeType('VariableDeclaration')).filter(v => v.stateVariable && v.visibility !== 'private') + : undefined; +} + +export function types ({ item }: DocItemContext): TypeDefinition[] | undefined { + return [...findAll(['StructDefinition', 'EnumDefinition', 'UserDefinedValueTypeDefinition'], item)]; +} diff --git a/apps/doc-gen/src/app/docgen/config.ts b/apps/doc-gen/src/app/docgen/config.ts new file mode 100644 index 00000000000..2a3f9fcc6e9 --- /dev/null +++ b/apps/doc-gen/src/app/docgen/config.ts @@ -0,0 +1,84 @@ +import type { SourceUnit } from 'solidity-ast'; +import type { DocItem } from './doc-item'; +import type { PageAssigner, PageStructure } from './site'; + +export interface UserConfig { + /** + * The directory where rendered pages will be written. + * Defaults to 'docs'. + */ + outputDir?: string; + + /** + * A directory of custom templates that should take precedence over the + * theme's templates. + */ + templates?: string; + + /** + * The name of the built-in templates that will be used by default. + * Defaults to 'markdown'. + */ + theme?: string; + + /** + * The way documentable items (contracts, functions, custom errors, etc.) + * will be organized in pages. Built in options are: + * - 'single': all items in one page + * - 'items': one page per item + * - 'files': one page per input Solidity file + * More customization is possible by defining a function that returns a page + * path given the AST node for the item and the source unit where it is + * defined. + * Defaults to 'single'. + */ + pages?: 'single' | 'items' | 'files' | PageAssigner; + + /** + * An array of sources subdirectories that should be excluded from + * documentation, relative to the contract sources directory. + */ + exclude?: string[]; + + /** + * Clean up the output by collapsing 3 or more contiguous newlines into only 2. + * Enabled by default. + */ + collapseNewlines?: boolean; + + /** + * The extension for generated pages. + * Defaults to '.md'. + */ + pageExtension?: string; +} + +//////////////////////////////////////////////////////////////////////////////////////////////////// + +// Other config parameters that will be provided by the environment (e.g. Hardhat) +// rather than by the user manually, unless using the library directly. +export interface Config extends UserConfig { + /** + * The root directory relative to which 'outputDir', 'sourcesDir', and + * 'templates' are specified. Defaults to the working directory. + */ + root?: string; + + /** + * The Solidity sources directory. + */ + sourcesDir?: string; +} + +export type FullConfig = Required; + +export const defaults: Omit = { + root: process.cwd(), + sourcesDir: 'contracts', + outputDir: 'docs', + pages: 'single', + exclude: [], + theme: 'markdown', + collapseNewlines: true, + pageExtension: '.md', +}; diff --git a/apps/doc-gen/src/app/docgen/doc-item.ts b/apps/doc-gen/src/app/docgen/doc-item.ts new file mode 100644 index 00000000000..eb032230271 --- /dev/null +++ b/apps/doc-gen/src/app/docgen/doc-item.ts @@ -0,0 +1,27 @@ +import { ContractDefinition, ImportDirective, PragmaDirective, SourceUnit, UsingForDirective } from "solidity-ast"; +import { Node, NodeType, NodeTypeMap } from "solidity-ast/node"; +import { AssertEqual } from "./utils/assert-equal-types"; + +export type DocItem = Exclude< + SourceUnit['nodes'][number] | ContractDefinition['nodes'][number], + ImportDirective | PragmaDirective | UsingForDirective +>; + +export const docItemTypes = [ + 'ContractDefinition', + 'EnumDefinition', + 'ErrorDefinition', + 'EventDefinition', + 'FunctionDefinition', + 'ModifierDefinition', + 'StructDefinition', + 'UserDefinedValueTypeDefinition', + 'VariableDeclaration', +] as const; + +// Make sure at compile time that docItemTypes contains exactly the node types of DocItem. +const _: AssertEqual = true; + +export function isDocItem(node: Node): node is DocItem { + return (docItemTypes as readonly string[]).includes(node.nodeType); +} diff --git a/apps/doc-gen/src/app/docgen/render.ts b/apps/doc-gen/src/app/docgen/render.ts new file mode 100644 index 00000000000..5c206f92b6e --- /dev/null +++ b/apps/doc-gen/src/app/docgen/render.ts @@ -0,0 +1,87 @@ +import Handlebars, { RuntimeOptions } from 'handlebars'; +import { Site, Page, DocItemWithContext, DOC_ITEM_CONTEXT } from './site'; +import { Templates } from './templates'; +import { itemType } from './utils/item-type'; +import fs from 'fs'; + +export interface RenderedPage { + id: string; + contents: string; +} + +interface TemplateOptions { + data: { + site: Site; + }; +} + +export function render(site: Site, templates: Templates, collapseNewlines?: boolean): RenderedPage[] { + const renderPage = buildRenderer(templates); + const renderedPages: RenderedPage[] = []; + for (const page of site.pages) { + let contents = renderPage(page, { data: { site } }); + if (collapseNewlines) { + contents = contents.replace(/\n{3,}/g, '\n\n'); + } + renderedPages.push({ + id: page.id, + contents, + }); + } + return renderedPages; +} + +export const itemPartialName = (item: DocItemWithContext) => itemType(item).replace(/ /g, '-').toLowerCase(); + +function itemPartial(item: DocItemWithContext, options?: RuntimeOptions) { + if (!item.__item_context) { + throw new Error(`Partial 'item' used in unsupported context (not a doc item)`); + } + const partial = options?.partials?.[itemPartialName(item)]; + if (!partial) { + throw new Error(`Missing partial '${itemPartialName(item)}'`); + } + return partial(item, options); +} + +function readmeHelper(H: typeof Handlebars, path: string, opts: RuntimeOptions) { + const items: DocItemWithContext[] = opts.data.root.items; + const renderedItems = Object.fromEntries( + items.map(item => [ + item.name, + new H.SafeString( + H.compile('{{>item}}')(item, opts), + ), + ]), + ); + return new H.SafeString( + H.compile(fs.readFileSync(path, 'utf8'))(renderedItems, opts), + ); +} + +function buildRenderer(templates: Templates): (page: Page, options: TemplateOptions) => string { + const pageTemplate = templates.partials?.page; + if (pageTemplate === undefined) { + throw new Error(`Missing 'page' template`); + } + + const H = Handlebars.create(); + + for (const [name, getBody] of Object.entries(templates.partials ?? {})) { + let partial: HandlebarsTemplateDelegate | undefined; + H.registerPartial(name, (...args) => { + partial ??= H.compile(getBody()); + return partial(...args); + }); + } + + H.registerHelper('readme', (path: string, opts: RuntimeOptions) => readmeHelper(H, path, opts)); + + for (const [name, fn] of Object.entries(templates.helpers ?? {})) { + H.registerHelper(name, fn); + } + + H.registerPartial('item', itemPartial); + + return H.compile('{{>page}}'); +} diff --git a/apps/doc-gen/src/app/docgen/site.ts b/apps/doc-gen/src/app/docgen/site.ts new file mode 100644 index 00000000000..53ffd5bc929 --- /dev/null +++ b/apps/doc-gen/src/app/docgen/site.ts @@ -0,0 +1,138 @@ +import path from 'path'; +import { ContractDefinition, SourceUnit } from 'solidity-ast'; +import { SolcOutput, SolcInput } from 'solidity-ast/solc'; +import { astDereferencer, ASTDereferencer, findAll, isNodeType, srcDecoder, SrcDecoder } from 'solidity-ast/utils'; +import { FullConfig } from './config'; +import { DocItem, docItemTypes, isDocItem } from './doc-item'; +import { Properties } from './templates'; +import { clone } from './utils/clone'; +import { isChild } from './utils/is-child'; +import { mapValues } from './utils/map-values'; +import { defineGetterMemoized } from './utils/memoized-getter'; + +export interface Build { + input: SolcInput; + output: SolcOutput; +} + +export interface BuildContext extends Build { + deref: ASTDereferencer; + decodeSrc: SrcDecoder; +} + +export type SiteConfig = Pick; +export type PageStructure = SiteConfig['pages']; +export type PageAssigner = ((item: DocItem, file: SourceUnit, config: SiteConfig) => string | undefined); + +export const pageAssigner: Record = { + single: (_1, _2, { pageExtension: ext }) => 'index' + ext, + items: (item, _, { pageExtension: ext }) => item.name + ext, + files: (_, file, { pageExtension: ext, sourcesDir }) => + path.relative(sourcesDir, file.absolutePath).replace('.sol', ext), +}; + +export interface Site { + items: DocItemWithContext[]; + pages: Page[]; +} + +export interface Page { + id: string; + items: DocItemWithContext[]; +} + +export const DOC_ITEM_CONTEXT = '__item_context' as const; +export type DocItemWithContext = DocItem & { [DOC_ITEM_CONTEXT]: DocItemContext }; + +export interface DocItemContext { + page?: string; + item: DocItemWithContext; + contract?: ContractDefinition; + file: SourceUnit; + build: BuildContext; +} + +export function buildSite (builds: Build[], siteConfig: SiteConfig, properties: Properties = {}): Site { + const assign = typeof siteConfig.pages === 'string' ? pageAssigner[siteConfig.pages] : siteConfig.pages; + + const seen = new Set(); + const items: DocItemWithContext[] = []; + const pages: Record = {}; + + // eslint-disable-next-line prefer-const + for (let { input, output } of builds) { + // Clone because we will mutate in order to add item context. + output = { ...output, sources: clone(output.sources) }; + + const deref = astDereferencer(output); + const decodeSrc = srcDecoder(input, output); + const build = { input, output, deref, decodeSrc }; + + for (const { ast: file } of Object.values(output.sources)) { + const isNewFile = !seen.has(file.absolutePath); + seen.add(file.absolutePath); + + for (const topLevelItem of file.nodes) { + if (!isDocItem(topLevelItem)) continue; + + const page = assignIfIncludedSource(assign, topLevelItem, file, siteConfig); + + const withContext = defineContext(topLevelItem, build, file, page); + defineProperties(withContext, properties); + + if (isNewFile && page !== undefined) { + (pages[page] ??= []).push(withContext); + items.push(withContext); + } + + if (!isNodeType('ContractDefinition', topLevelItem)) { + continue; + } + + for (const item of topLevelItem.nodes) { + if (!isDocItem(item)) continue; + if (isNewFile && page !== undefined) items.push(item as DocItemWithContext); + const contract = topLevelItem.nodeType === 'ContractDefinition' ? topLevelItem : undefined; + const withContext = defineContext(item, build, file, page, contract); + defineProperties(withContext, properties); + } + } + } + } + + return { + items, + pages: Object.entries(pages).map(([id, pageItems]) => ({ id, items: pageItems })), + }; +} + +function defineContext (item: DocItem, build: BuildContext, file: SourceUnit, page?: string, contract?: ContractDefinition): DocItemWithContext { + return Object.assign(item, { + [DOC_ITEM_CONTEXT]: { build, file, contract, page, item: item as DocItemWithContext }, + }); +} + +function defineProperties (item: DocItemWithContext, properties: Properties) { + for (const [prop, fn] of Object.entries(properties)) { + const original: unknown = (item as any)[prop]; + defineGetterMemoized(item as any, prop, () => fn(item.__item_context, original)); + } +} + +function assignIfIncludedSource ( + assign: PageAssigner, + item: DocItem, + file: SourceUnit, + config: SiteConfig, +) { + return isFileIncluded(file.absolutePath, config) + ? assign(item, file, config) + : undefined; +} + +function isFileIncluded (file: string, config: SiteConfig) { + return ( + isChild(file, config.sourcesDir) && + config.exclude.every(e => !isChild(file, path.join(config.sourcesDir, e))) + ); +} diff --git a/apps/doc-gen/src/app/docgen/templates.ts b/apps/doc-gen/src/app/docgen/templates.ts new file mode 100644 index 00000000000..cee8f12c751 --- /dev/null +++ b/apps/doc-gen/src/app/docgen/templates.ts @@ -0,0 +1,90 @@ +import { mapKeys } from './utils/map-keys'; +import { DocItemContext } from './site'; + +import * as defaultProperties from './common/properties'; + +export type PropertyGetter = (ctx: DocItemContext, original?: unknown) => unknown; +export type Properties = Record; + +export interface Templates { + partials?: Record string>; + helpers?: Record string>; + properties?: Record; +} + +/** + * Loads the templates that will be used for rendering a site based on a + * default theme and user templates. + * + * The result contains all partials, helpers, and property getters defined in + * the user templates and the default theme, where the user's take precedence + * if there is a clash. Additionally, all theme partials and helpers are + * included with the theme prefix, e.g. `markdown/contract` will be a partial. + */ +export async function loadTemplates(defaultTheme: string, root: string, userTemplatesPath?: string): Promise { + const themes = await readThemes(); + + // Initialize templates with the default theme. + const templates: Required = { + partials: { ...themes[defaultTheme]?.partials }, + helpers: { ...themes[defaultTheme]?.helpers }, + properties: { ...defaultProperties }, + }; + + + // Add partials and helpers from all themes, prefixed with the theme name. + for (const [themeName, theme] of Object.entries(themes)) { + const addPrefix = (k: string) => `${themeName}/${k}`; + Object.assign(templates.partials, mapKeys(theme.partials, addPrefix)); + Object.assign(templates.helpers, mapKeys(theme.helpers, addPrefix)); + } + + return templates; +} + +/** + * Read templates and helpers from a directory. + */ +export async function readTemplates(): Promise> { + return { + partials: await readPartials(), + helpers: await readHelpers('helpers'), + properties: await readHelpers('properties'), + }; +} + +async function readPartials() { + const partials: NonNullable = {}; + const partialNames = ["common", "contract", "enum", "error", "event", "function", "modifier", "page", "struct", "variable", "user-defined-value-type"] + for (const name of partialNames) { + const p = await import('raw-loader!./themes/markdown/' + name + '.hbs') + partials[name] = () => p.default + } + return partials; +} + +async function readHelpers(name: string) { + let helpersPath; + + const h = await import('./themes/markdown/helpers'); + const helpers: Record any> = {}; + + for (const name in h) { + if (typeof h[name] === 'function') { + helpers[name] = h[name]; + } + } + + return helpers; +} + +/** + * Reads all built-in themes into an object. Partials will always be found in + * src/themes, whereas helpers may instead be found in dist/themes if TypeScript + * can't be imported directly. + */ +async function readThemes(): Promise>> { + const themes: Record> = {} + themes['markdown'] = await readTemplates() + return themes +} diff --git a/apps/doc-gen/src/app/docgen/themes/markdown/common.hbs b/apps/doc-gen/src/app/docgen/themes/markdown/common.hbs new file mode 100644 index 00000000000..b2a3b2a5a2a --- /dev/null +++ b/apps/doc-gen/src/app/docgen/themes/markdown/common.hbs @@ -0,0 +1,34 @@ +{{h}} {{name}} + +{{#if signature}} +```solidity +{{{signature}}} +``` +{{/if}} + +{{{natspec.notice}}} + +{{#if natspec.dev}} +_{{{natspec.dev}}}_ +{{/if}} + +{{#if natspec.params}} +{{h 2}} Parameters + +| Name | Type | Description | +| ---- | ---- | ----------- | +{{#each params}} +| {{name}} | {{type}} | {{{joinLines natspec}}} | +{{/each}} +{{/if}} + +{{#if natspec.returns}} +{{h 2}} Return Values + +| Name | Type | Description | +| ---- | ---- | ----------- | +{{#each returns}} +| {{#if name}}{{name}}{{else}}[{{@index}}]{{/if}} | {{type}} | {{{joinLines natspec}}} | +{{/each}} +{{/if}} + diff --git a/apps/doc-gen/src/app/docgen/themes/markdown/contract.hbs b/apps/doc-gen/src/app/docgen/themes/markdown/contract.hbs new file mode 100644 index 00000000000..e4ed15831c2 --- /dev/null +++ b/apps/doc-gen/src/app/docgen/themes/markdown/contract.hbs @@ -0,0 +1,8 @@ +{{>common}} + +{{#each items}} +{{#hsection}} +{{>item}} +{{/hsection}} + +{{/each}} diff --git a/apps/doc-gen/src/app/docgen/themes/markdown/enum.hbs b/apps/doc-gen/src/app/docgen/themes/markdown/enum.hbs new file mode 100644 index 00000000000..677406db9c7 --- /dev/null +++ b/apps/doc-gen/src/app/docgen/themes/markdown/enum.hbs @@ -0,0 +1,9 @@ +{{>common}} + +```solidity +enum {{name}} { +{{#each members}} + {{name}}{{#unless @last}},{{/unless}} +{{/each}} +} +``` diff --git a/apps/doc-gen/src/app/docgen/themes/markdown/error.hbs b/apps/doc-gen/src/app/docgen/themes/markdown/error.hbs new file mode 100644 index 00000000000..5373296cbc5 --- /dev/null +++ b/apps/doc-gen/src/app/docgen/themes/markdown/error.hbs @@ -0,0 +1 @@ +{{>common}} diff --git a/apps/doc-gen/src/app/docgen/themes/markdown/event.hbs b/apps/doc-gen/src/app/docgen/themes/markdown/event.hbs new file mode 100644 index 00000000000..5373296cbc5 --- /dev/null +++ b/apps/doc-gen/src/app/docgen/themes/markdown/event.hbs @@ -0,0 +1 @@ +{{>common}} diff --git a/apps/doc-gen/src/app/docgen/themes/markdown/function.hbs b/apps/doc-gen/src/app/docgen/themes/markdown/function.hbs new file mode 100644 index 00000000000..5373296cbc5 --- /dev/null +++ b/apps/doc-gen/src/app/docgen/themes/markdown/function.hbs @@ -0,0 +1 @@ +{{>common}} diff --git a/apps/doc-gen/src/app/docgen/themes/markdown/helpers.ts b/apps/doc-gen/src/app/docgen/themes/markdown/helpers.ts new file mode 100644 index 00000000000..bfd5cfbdd77 --- /dev/null +++ b/apps/doc-gen/src/app/docgen/themes/markdown/helpers.ts @@ -0,0 +1,49 @@ +import { HelperOptions, Utils } from 'handlebars'; + +export * from '../../common/helpers'; + +/** + * Returns a Markdown heading marker. An optional number increases the heading level. + * + * Input Output + * {{h}} {{name}} # Name + * {{h 2}} {{name}} ## Name + */ +export function h(opts: HelperOptions): string; +export function h(hsublevel: number, opts: HelperOptions): string; +export function h(hsublevel: number | HelperOptions, opts?: HelperOptions) { + const { hlevel } = getHLevel(hsublevel, opts); + return new Array(hlevel).fill('#').join(''); +}; + +/** + * Delineates a section where headings should be increased by 1 or a custom number. + * + * {{#hsection}} + * {{>partial-with-headings}} + * {{/hsection}} + */ +export function hsection(opts: HelperOptions): string; +export function hsection(hsublevel: number, opts: HelperOptions): string; +export function hsection(this: unknown, hsublevel: number | HelperOptions, opts?: HelperOptions) { + let hlevel; + ({ hlevel, opts } = getHLevel(hsublevel, opts)); + opts.data = Utils.createFrame(opts.data); + opts.data.hlevel = hlevel; + return opts.fn(this as unknown, opts); +} + +/** + * Helper for dealing with the optional hsublevel argument. + */ +function getHLevel(hsublevel: number | HelperOptions, opts?: HelperOptions) { + if (typeof hsublevel === 'number') { + opts = opts!; + hsublevel = Math.max(1, hsublevel); + } else { + opts = hsublevel; + hsublevel = 1; + } + const contextHLevel: number = opts.data?.hlevel ?? 0; + return { opts, hlevel: contextHLevel + hsublevel }; +} diff --git a/apps/doc-gen/src/app/docgen/themes/markdown/modifier.hbs b/apps/doc-gen/src/app/docgen/themes/markdown/modifier.hbs new file mode 100644 index 00000000000..5373296cbc5 --- /dev/null +++ b/apps/doc-gen/src/app/docgen/themes/markdown/modifier.hbs @@ -0,0 +1 @@ +{{>common}} diff --git a/apps/doc-gen/src/app/docgen/themes/markdown/page.hbs b/apps/doc-gen/src/app/docgen/themes/markdown/page.hbs new file mode 100644 index 00000000000..6597f0b5c77 --- /dev/null +++ b/apps/doc-gen/src/app/docgen/themes/markdown/page.hbs @@ -0,0 +1,8 @@ +# Solidity API + +{{#each items}} +{{#hsection}} +{{>item}} +{{/hsection}} + +{{/each}} diff --git a/apps/doc-gen/src/app/docgen/themes/markdown/struct.hbs b/apps/doc-gen/src/app/docgen/themes/markdown/struct.hbs new file mode 100644 index 00000000000..867069e2bca --- /dev/null +++ b/apps/doc-gen/src/app/docgen/themes/markdown/struct.hbs @@ -0,0 +1,9 @@ +{{>common}} + +```solidity +struct {{name}} { +{{#each members}} + {{{typeName.typeDescriptions.typeString}}} {{name}}; +{{/each}} +} +``` diff --git a/apps/doc-gen/src/app/docgen/themes/markdown/user-defined-value-type.hbs b/apps/doc-gen/src/app/docgen/themes/markdown/user-defined-value-type.hbs new file mode 100644 index 00000000000..5373296cbc5 --- /dev/null +++ b/apps/doc-gen/src/app/docgen/themes/markdown/user-defined-value-type.hbs @@ -0,0 +1 @@ +{{>common}} diff --git a/apps/doc-gen/src/app/docgen/themes/markdown/variable.hbs b/apps/doc-gen/src/app/docgen/themes/markdown/variable.hbs new file mode 100644 index 00000000000..5373296cbc5 --- /dev/null +++ b/apps/doc-gen/src/app/docgen/themes/markdown/variable.hbs @@ -0,0 +1 @@ +{{>common}} diff --git a/apps/doc-gen/src/app/docgen/utils/ItemError.ts b/apps/doc-gen/src/app/docgen/utils/ItemError.ts new file mode 100644 index 00000000000..3791f71443a --- /dev/null +++ b/apps/doc-gen/src/app/docgen/utils/ItemError.ts @@ -0,0 +1,13 @@ +import { DocItemWithContext, DOC_ITEM_CONTEXT } from '../site'; + +export class ItemError extends Error { + constructor(msg: string, item: DocItemWithContext) { + const ctx = item[DOC_ITEM_CONTEXT]; + const src = ctx && ctx.build.decodeSrc(item); + if (src) { + super(msg + ` (${src})`); + } else { + super(msg); + } + } +} diff --git a/apps/doc-gen/src/app/docgen/utils/arrays-equal.ts b/apps/doc-gen/src/app/docgen/utils/arrays-equal.ts new file mode 100644 index 00000000000..fe08726e95f --- /dev/null +++ b/apps/doc-gen/src/app/docgen/utils/arrays-equal.ts @@ -0,0 +1,5 @@ +export function arraysEqual(a: T[], b: T[]): boolean; +export function arraysEqual(a: T[], b: T[], mapFn: (x: T) => U): boolean; +export function arraysEqual(a: T[], b: T[], mapFn = (x: T) => x): boolean { + return a.length === b.length && a.every((x, i) => mapFn(x) === mapFn(b[i]!)); +} diff --git a/apps/doc-gen/src/app/docgen/utils/assert-equal-types.ts b/apps/doc-gen/src/app/docgen/utils/assert-equal-types.ts new file mode 100644 index 00000000000..0171d13a366 --- /dev/null +++ b/apps/doc-gen/src/app/docgen/utils/assert-equal-types.ts @@ -0,0 +1 @@ +export type AssertEqual = [T, U] extends [U, T] ? true : never; diff --git a/apps/doc-gen/src/app/docgen/utils/clone.ts b/apps/doc-gen/src/app/docgen/utils/clone.ts new file mode 100644 index 00000000000..f92fa701899 --- /dev/null +++ b/apps/doc-gen/src/app/docgen/utils/clone.ts @@ -0,0 +1,6 @@ +/** + * Deep cloning good enough for simple objects like solc output. Types are not + * sound because the function may lose information: non-enumerable properties, + * symbols, undefined values, prototypes, etc. + */ +export const clone = (obj: T): T => JSON.parse(JSON.stringify(obj)); diff --git a/apps/doc-gen/src/app/docgen/utils/ensure-array.ts b/apps/doc-gen/src/app/docgen/utils/ensure-array.ts new file mode 100644 index 00000000000..cd0f8ea570b --- /dev/null +++ b/apps/doc-gen/src/app/docgen/utils/ensure-array.ts @@ -0,0 +1,12 @@ +// The function below would not be correctly typed if the return type was T[] +// because T may itself be an array type and Array.isArray would not know the +// difference. Adding IfArray makes sure the return type is always correct. +type IfArray = T extends any[] ? T : never; + +export function ensureArray(x: T | T[]): T[] | IfArray { + if (Array.isArray(x)) { + return x; + } else { + return [x]; + } +} diff --git a/apps/doc-gen/src/app/docgen/utils/execall.ts b/apps/doc-gen/src/app/docgen/utils/execall.ts new file mode 100644 index 00000000000..2aca0ad77cc --- /dev/null +++ b/apps/doc-gen/src/app/docgen/utils/execall.ts @@ -0,0 +1,18 @@ +/** + * Iterates over all contiguous matches of the regular expression over the + * text. Stops as soon as the regular expression no longer matches at the + * current position. + */ +export function* execAll(re: RegExp, text: string) { + re = new RegExp(re, re.flags + (re.sticky ? '' : 'y')); + + while (true) { + const match = re.exec(text); + + // We break out of the loop if there is no match or if the empty string is + // matched because no progress will be made and it will loop indefinitely. + if (!match?.[0]) break; + + yield match; + } +} diff --git a/apps/doc-gen/src/app/docgen/utils/is-child.ts b/apps/doc-gen/src/app/docgen/utils/is-child.ts new file mode 100644 index 00000000000..cb07cc71367 --- /dev/null +++ b/apps/doc-gen/src/app/docgen/utils/is-child.ts @@ -0,0 +1,5 @@ +import path from 'path'; + +export function isChild(file: string, parent: string) { + return path.normalize(file + path.sep).startsWith(path.normalize(parent + path.sep)); +} diff --git a/apps/doc-gen/src/app/docgen/utils/item-type.ts b/apps/doc-gen/src/app/docgen/utils/item-type.ts new file mode 100644 index 00000000000..8873ece1fcd --- /dev/null +++ b/apps/doc-gen/src/app/docgen/utils/item-type.ts @@ -0,0 +1,7 @@ +import { DocItem } from '../doc-item'; + +export function itemType(item: DocItem): string { + return item.nodeType + .replace(/(Definition|Declaration)$/, '') + .replace(/(\w)([A-Z])/g, '$1 $2'); +} diff --git a/apps/doc-gen/src/app/docgen/utils/map-keys.ts b/apps/doc-gen/src/app/docgen/utils/map-keys.ts new file mode 100644 index 00000000000..7852cd85dc1 --- /dev/null +++ b/apps/doc-gen/src/app/docgen/utils/map-keys.ts @@ -0,0 +1,4 @@ +export function mapKeys(obj: Record, fn: (key: string) => string): Record { + return Object.fromEntries(Object.entries(obj).map(([k, v]) => [fn(k), v])); +} + diff --git a/apps/doc-gen/src/app/docgen/utils/map-values.ts b/apps/doc-gen/src/app/docgen/utils/map-values.ts new file mode 100644 index 00000000000..c151d7d5529 --- /dev/null +++ b/apps/doc-gen/src/app/docgen/utils/map-values.ts @@ -0,0 +1,19 @@ +export function mapValues(obj: Record, fn: (value: T) => U): Record { + const res: Record = {}; + for (const [k, v] of Object.entries(obj)) { + res[k] = fn(v); + } + return res; +} + +export function filterValues(obj: Record, fn: (value: T) => value is U): Record; +export function filterValues(obj: Record, fn: (value: T) => boolean): Record; +export function filterValues(obj: Record, fn: (value: T) => boolean): Record { + const res: Record = {}; + for (const [k, v] of Object.entries(obj)) { + if (fn(v)) { + res[k] = v; + } + } + return res; +} diff --git a/apps/doc-gen/src/app/docgen/utils/memoized-getter.ts b/apps/doc-gen/src/app/docgen/utils/memoized-getter.ts new file mode 100644 index 00000000000..1a2fef4ae5f --- /dev/null +++ b/apps/doc-gen/src/app/docgen/utils/memoized-getter.ts @@ -0,0 +1,23 @@ +export function defineGetterMemoized(obj: O, key: K, getter: () => T) { + let state: 'todo' | 'doing' | 'done' = 'todo'; + let value: T; + + Object.defineProperty(obj, key, { + enumerable: true, + get() { + switch (state) { + case 'done': + return value; + + case 'doing': + throw new Error("Detected recursion"); + + case 'todo': + state = 'doing'; + value = getter(); + state = 'done'; + return value; + } + } + }); +} diff --git a/apps/doc-gen/src/app/docgen/utils/natspec.ts b/apps/doc-gen/src/app/docgen/utils/natspec.ts new file mode 100644 index 00000000000..40f752aaa85 --- /dev/null +++ b/apps/doc-gen/src/app/docgen/utils/natspec.ts @@ -0,0 +1,145 @@ +import { FunctionDefinition } from 'solidity-ast'; +import { findAll } from 'solidity-ast/utils'; +import { DocItemWithContext, DOC_ITEM_CONTEXT } from '../site'; +import { arraysEqual } from './arrays-equal'; +import { execAll } from './execall'; +import { itemType } from './item-type'; +import { ItemError } from './ItemError'; +import { readItemDocs } from './read-item-docs'; +import { getContractsInScope } from './scope'; + +export interface NatSpec { + title?: string; + notice?: string; + dev?: string; + params?: { + name: string; + description: string; + }[]; + returns?: { + name?: string; + description: string; + }[]; + custom?: { + [tag: string]: string; + }; +} + +export function parseNatspec(item: DocItemWithContext): NatSpec { + if (!item[DOC_ITEM_CONTEXT]) throw new Error(`Not an item or item is missing context`); + + let res: NatSpec = {}; + + const docSource = readItemDocs(item); + const docString = docSource !== undefined + ? cleanUpDocstringFromSource(docSource) + : 'documentation' in item && item.documentation + ? typeof item.documentation === 'string' + ? item.documentation + : cleanUpDocstringFromSolc(item.documentation.text) + : ''; + + const tagMatches = execAll( + /^(?:@(\w+|custom:[a-z][a-z-]*) )?((?:(?!^@(?:\w+|custom:[a-z][a-z-]*) )[^])*)/m, + docString, + ); + + let inheritFrom: FunctionDefinition | undefined; + + for (const [, tag = 'notice', content] of tagMatches) { + if (content === undefined) throw new ItemError('Unexpected error', item); + + if (tag === 'dev' || tag === 'notice') { + res[tag] ??= ''; + res[tag] += content; + } + + if (tag === 'title') { + res.title = content.trim(); + } + + if (tag === 'param') { + const paramMatches = content.match(/(\w+) ([^]*)/); + if (paramMatches) { + const [, name, description] = paramMatches as [string, string, string]; + res.params ??= []; + res.params.push({ name, description: description.trim() }); + } + } + + if (tag === 'return') { + if (!('returnParameters' in item)) { + throw new ItemError(`Item does not contain return parameters`, item); + } + res.returns ??= []; + const i = res.returns.length; + const p = item.returnParameters.parameters[i]; + if (p === undefined) { + throw new ItemError('Got more @return tags than expected', item); + } + if (!p.name) { + res.returns.push({ description: content.trim() }); + } else { + const paramMatches = content.match(/(\w+)( ([^]*))?/); + if (!paramMatches || paramMatches[1] !== p.name) { + throw new ItemError(`Expected @return tag to start with name '${p.name}'`, item); + } + const [, name, description] = paramMatches as [string, string, string?]; + res.returns.push({ name, description: description?.trim() ?? '' }); + } + } + + if (tag?.startsWith('custom:')) { + const key = tag.replace(/^custom:/, ''); + res.custom ??= {}; + res.custom[key] ??= ''; + res.custom[key] += content; + } + + if (tag === 'inheritdoc') { + if (!(item.nodeType === 'FunctionDefinition' || item.nodeType === 'VariableDeclaration')) { + throw new ItemError(`Expected function or variable but saw ${itemType(item)}`, item); + } + const parentContractName = content.trim(); + const parentContract = getContractsInScope(item)[parentContractName]; + if (!parentContract) { + throw new ItemError(`Parent contract '${parentContractName}' not found`, item); + } + inheritFrom = [...findAll('FunctionDefinition', parentContract)].find(f => item.baseFunctions?.includes(f.id)); + } + } + + if (docString.length === 0) { + if ('baseFunctions' in item && item.baseFunctions?.length === 1) { + const baseFn = item[DOC_ITEM_CONTEXT].build.deref('FunctionDefinition', item.baseFunctions[0]!); + const shouldInherit = item.nodeType === 'VariableDeclaration' || arraysEqual(item.parameters.parameters, baseFn.parameters.parameters, p => p.name); + if (shouldInherit) { + inheritFrom = baseFn; + } + } + } + + if (res.dev) res.dev = res.dev.trim(); + if (res.notice) res.notice = res.notice.trim(); + + if (inheritFrom) { + res = { ...parseNatspec(inheritFrom as DocItemWithContext), ...res }; + } + + return res; +} + +// Fix solc buggy parsing of doc comments. +// Reverse engineered from solc behavior. +function cleanUpDocstringFromSolc(text: string) { + return text + .replace(/\n\n?^[ \t]*(?:\*|\/\/\/)/mg, '\n\n') + .replace(/^[ \t]?/mg, ''); +} + +function cleanUpDocstringFromSource(text: string) { + return text + .replace(/^\/\*\*(.*)\*\/$/s, '$1') + .trim() + .replace(/^[ \t]*(\*|\/\/\/)[ \t]?/mg, ''); +} diff --git a/apps/doc-gen/src/app/docgen/utils/read-item-docs.ts b/apps/doc-gen/src/app/docgen/utils/read-item-docs.ts new file mode 100644 index 00000000000..36ee13aa7fc --- /dev/null +++ b/apps/doc-gen/src/app/docgen/utils/read-item-docs.ts @@ -0,0 +1,26 @@ +import { DocItemWithContext, DOC_ITEM_CONTEXT, Build } from '../site'; + +export function readItemDocs(item: DocItemWithContext): string | undefined { + const { build } = item[DOC_ITEM_CONTEXT]; + // Note that Solidity 0.5 has item.documentation: string even though the + // types do not reflect that. This is why we check typeof === object. + if ('documentation' in item && item.documentation && typeof item.documentation === 'object') { + const { source, start, length } = decodeSrc(item.documentation.src, build); + const content = build.input.sources[source]?.content; + if (content !== undefined) { + return Buffer.from(content, 'utf8').slice(start, start + length).toString('utf8'); + } + } +} + +function decodeSrc(src: string, build: Build): { source: string; start: number; length: number } { + const [start, length, sourceId] = src.split(':').map(s => parseInt(s)); + if (start === undefined || length === undefined || sourceId === undefined) { + throw new Error(`Bad source string ${src}`); + } + const source = Object.keys(build.output.sources).find(s => build.output.sources[s]?.id === sourceId); + if (source === undefined) { + throw new Error(`No source with id ${sourceId}`); + } + return { source, start, length }; +} diff --git a/apps/doc-gen/src/app/docgen/utils/scope.ts b/apps/doc-gen/src/app/docgen/utils/scope.ts new file mode 100644 index 00000000000..dabe9901378 --- /dev/null +++ b/apps/doc-gen/src/app/docgen/utils/scope.ts @@ -0,0 +1,63 @@ +import { ContractDefinition, SourceUnit } from "solidity-ast"; +import { findAll, isNodeType } from "solidity-ast/utils"; +import { DocItemWithContext } from "../site"; +import { filterValues, mapValues } from './map-values'; +import { mapKeys } from './map-keys'; + +type Definition = SourceUnit['nodes'][number] & { name: string }; +type Scope = { [name in string]: () => { namespace: Scope } | { definition: Definition } }; + +export function getContractsInScope(item: DocItemWithContext) { + const cache = new WeakMap(); + + return filterValues( + flattenScope(run(item.__item_context.file)), + isNodeType('ContractDefinition'), + ); + + function run(file: SourceUnit): Scope { + if (cache.has(file)) { + return cache.get(file)!; + } + + const scope: Scope = {}; + + cache.set(file, scope); + + for (const c of file.nodes) { + if ('name' in c) { + scope[c.name] = () => ({ definition: c }); + } + } + + for (const i of findAll('ImportDirective', file)) { + const importedFile = item.__item_context.build.deref('SourceUnit', i.sourceUnit); + const importedScope = run(importedFile); + if (i.unitAlias) { + scope[i.unitAlias] = () => ({ namespace: importedScope }); + } else if (i.symbolAliases.length === 0) { + Object.assign(scope, importedScope); + } else { + for (const a of i.symbolAliases) { + // Delayed function call supports circular dependencies + scope[a.local ?? a.foreign.name] = importedScope[a.foreign.name] ?? (() => importedScope[a.foreign.name]!()); + } + } + }; + + return scope; + } +} + +function flattenScope(scope: Scope): Record { + return Object.fromEntries( + Object.entries(scope).flatMap(([k, fn]) => { + const v = fn(); + if ('definition' in v) { + return [[k, v.definition] as const]; + } else { + return Object.entries(mapKeys(flattenScope(v.namespace), k2 => k + '.' + k2)); + } + }), + ); +} diff --git a/apps/doc-gen/src/app/hooks/useLocalStorage.tsx b/apps/doc-gen/src/app/hooks/useLocalStorage.tsx new file mode 100644 index 00000000000..d677de7813b --- /dev/null +++ b/apps/doc-gen/src/app/hooks/useLocalStorage.tsx @@ -0,0 +1,37 @@ +import { useState } from "react"; + +export function useLocalStorage(key: string, initialValue: any) { + // State to store our value + // Pass initial state function to useState so logic is only executed once + const [storedValue, setStoredValue] = useState(() => { + try { + // Get from local storage by key + const item = window.localStorage.getItem(key); + // Parse stored json or if none return initialValue + return item ? JSON.parse(item) : initialValue; + } catch (error) { + // If error also return initialValue + console.log(error); + return initialValue; + } + }); + + // Return a wrapped version of useState's setter function that ... + // ... persists the new value to localStorage. + const setValue = (value: any) => { + try { + // Allow value to be a function so we have same API as useState + const valueToStore = + value instanceof Function ? value(storedValue) : value; + // Save state + setStoredValue(valueToStore); + // Save to local storage + window.localStorage.setItem(key, JSON.stringify(valueToStore)); + } catch (error) { + // A more advanced implementation would handle the error case + console.log(error); + } + }; + + return [storedValue, setValue]; +} diff --git a/apps/doc-gen/src/app/views/ErrorView.tsx b/apps/doc-gen/src/app/views/ErrorView.tsx new file mode 100644 index 00000000000..f1c4fdaf919 --- /dev/null +++ b/apps/doc-gen/src/app/views/ErrorView.tsx @@ -0,0 +1,31 @@ +import React from "react"; + +export const ErrorView: React.FC = () => { + return ( +
+ Error page +
Sorry, something unexpected happened.
+
+ Please raise an issue:{" "} + + Here + +
+
+ ); +}; diff --git a/apps/doc-gen/src/app/views/index.ts b/apps/doc-gen/src/app/views/index.ts new file mode 100644 index 00000000000..8b137891791 --- /dev/null +++ b/apps/doc-gen/src/app/views/index.ts @@ -0,0 +1 @@ + diff --git a/apps/doc-gen/src/favicon.ico b/apps/doc-gen/src/favicon.ico new file mode 100644 index 00000000000..bcd5dfd67cd Binary files /dev/null and b/apps/doc-gen/src/favicon.ico differ diff --git a/apps/doc-gen/src/index.html b/apps/doc-gen/src/index.html new file mode 100644 index 00000000000..6e26b4393e1 --- /dev/null +++ b/apps/doc-gen/src/index.html @@ -0,0 +1,13 @@ + + + + + Remix Docgen + + + + + +
+ + diff --git a/apps/doc-gen/src/main.tsx b/apps/doc-gen/src/main.tsx new file mode 100644 index 00000000000..a6dc3b3a473 --- /dev/null +++ b/apps/doc-gen/src/main.tsx @@ -0,0 +1,11 @@ +import React from "react"; +import ReactDOM from "react-dom"; +import App from "./app/App"; +// import { Routes } from "./routes"; + +ReactDOM.render( + + + , + document.getElementById("root") +); diff --git a/apps/doc-gen/src/types.ts b/apps/doc-gen/src/types.ts new file mode 100644 index 00000000000..187fb6e7b31 --- /dev/null +++ b/apps/doc-gen/src/types.ts @@ -0,0 +1,11 @@ +export type Documentation = string + +export interface EthDocumentation { + [contractName: string]: Documentation +} + +export type ContractName = string + +export type FileName = string + +export type PublishedSite = string \ No newline at end of file diff --git a/apps/doc-gen/tsconfig.app.json b/apps/doc-gen/tsconfig.app.json new file mode 100644 index 00000000000..af84f21cfc8 --- /dev/null +++ b/apps/doc-gen/tsconfig.app.json @@ -0,0 +1,23 @@ +{ + "extends": "./tsconfig.json", + "compilerOptions": { + "outDir": "../../dist/out-tsc", + "types": ["node"] + }, + "files": [ + "../../node_modules/@nrwl/react/typings/cssmodule.d.ts", + "../../node_modules/@nrwl/react/typings/image.d.ts" + ], + "exclude": [ + "jest.config.ts", + "**/*.spec.ts", + "**/*.test.ts", + "**/*.spec.tsx", + "**/*.test.tsx", + "**/*.spec.js", + "**/*.test.js", + "**/*.spec.jsx", + "**/*.test.jsx" + ], + "include": ["**/*.js", "**/*.jsx", "**/*.ts", "**/*.tsx"] +} diff --git a/apps/doc-gen/tsconfig.json b/apps/doc-gen/tsconfig.json new file mode 100644 index 00000000000..5aab5e79111 --- /dev/null +++ b/apps/doc-gen/tsconfig.json @@ -0,0 +1,16 @@ +{ + "extends": "../../tsconfig.base.json", + "compilerOptions": { + "jsx": "react-jsx", + "allowJs": true, + "esModuleInterop": true, + "allowSyntheticDefaultImports": true + }, + "files": [], + "include": [], + "references": [ + { + "path": "./tsconfig.app.json" + } + ] +} diff --git a/apps/doc-gen/webpack.config.js b/apps/doc-gen/webpack.config.js new file mode 100644 index 00000000000..7b3d088f057 --- /dev/null +++ b/apps/doc-gen/webpack.config.js @@ -0,0 +1,82 @@ +const { composePlugins, withNx } = require('@nrwl/webpack') +const { withReact } = require('@nrwl/react') +const webpack = require('webpack') +const TerserPlugin = require("terser-webpack-plugin") +const CssMinimizerPlugin = require("css-minimizer-webpack-plugin") + +// Nx plugins for webpack. +module.exports = composePlugins(withNx(), withReact(), (config) => { + // Update the webpack config as needed here. + // e.g. `config.plugins.push(new MyPlugin())` + + // add fallback for node modules + config.resolve.fallback = { + ...config.resolve.fallback, + "crypto": require.resolve("crypto-browserify"), + "stream": require.resolve("stream-browserify"), + "path": require.resolve("path-browserify"), + "http": require.resolve("stream-http"), + "https": require.resolve("https-browserify"), + "constants": require.resolve("constants-browserify"), + "os": false, //require.resolve("os-browserify/browser"), + "timers": false, // require.resolve("timers-browserify"), + "zlib": require.resolve("browserify-zlib"), + "fs": false, + "module": false, + "tls": false, + "net": false, + "readline": false, + "child_process": false, + "buffer": require.resolve("buffer/"), + "vm": require.resolve('vm-browserify'), + } + + // add externals + config.externals = { + ...config.externals, + solc: 'solc', + } + + // add public path + config.output.publicPath = '/' + + // add copy & provide plugin + config.plugins.push( + new webpack.ProvidePlugin({ + Buffer: ['buffer', 'Buffer'], + url: ['url', 'URL'], + process: 'process/browser', + }), + new webpack.DefinePlugin({ + + }), + ) + + // souce-map loader + config.module.rules.push({ + test: /\.js$/, + use: ["source-map-loader"], + enforce: "pre" + }) + + config.ignoreWarnings = [/Failed to parse source map/] // ignore source-map-loader warnings + + // set minimizer + config.optimization.minimizer = [ + new TerserPlugin({ + parallel: true, + terserOptions: { + ecma: 2015, + compress: false, + mangle: false, + format: { + comments: false, + }, + }, + extractComments: false, + }), + new CssMinimizerPlugin(), + ]; + + return config; +}) diff --git a/apps/doc-viewer/project.json b/apps/doc-viewer/project.json new file mode 100644 index 00000000000..5ea04be27ea --- /dev/null +++ b/apps/doc-viewer/project.json @@ -0,0 +1,59 @@ +{ + "name": "doc-viewer", + "$schema": "../../node_modules/nx/schemas/project-schema.json", + "sourceRoot": "apps/doc-viewer/src", + "projectType": "application", + "implicitDependencies": [ + ], + "targets": { + "build": { + "executor": "@nrwl/webpack:webpack", + "outputs": ["{options.outputPath}"], + "defaultConfiguration": "development", + "options": { + "compiler": "babel", + "outputPath": "dist/apps/doc-viewer", + "index": "apps/doc-viewer/src/index.html", + "baseHref": "/", + "main": "apps/doc-viewer/src/main.tsx", + "tsConfig": "apps/doc-viewer/tsconfig.app.json", + "assets": [ + "apps/doc-viewer/src/favicon.ico" + ], + "styles": [], + "scripts": [], + "webpackConfig": "apps/doc-viewer/webpack.config.js" + }, + "configurations": { + "development": { + }, + "production": { + "fileReplacements": [ + { + "replace": "apps/doc-viewer/src/environments/environment.ts", + "with": "apps/doc-viewer/src/environments/environment.prod.ts" + } + ] + } + } + }, + "serve": { + "executor": "@nrwl/webpack:dev-server", + "defaultConfiguration": "development", + "options": { + "buildTarget": "doc-viewer:build", + "hmr": true + }, + "configurations": { + "development": { + "buildTarget": "doc-viewer:build:development", + "port": 7003 + }, + "production": { + "buildTarget": "doc-viewer:build:production" + } + } + } + }, + "tags": [] +} diff --git a/apps/doc-viewer/src/app/App.tsx b/apps/doc-viewer/src/app/App.tsx new file mode 100644 index 00000000000..cbb57460d09 --- /dev/null +++ b/apps/doc-viewer/src/app/App.tsx @@ -0,0 +1,23 @@ +import React, { useEffect, useState } from "react" +import { DocViewer } from "./docviewer" +import ReactMarkdown from 'react-markdown' +import remarkGfm from 'remark-gfm' + +const client = new DocViewer() + +export default function App() { + const [contents, setContents] = useState('') + useEffect(() => { + client.eventEmitter.on('contentsReady', (fileContents: string) => { + setContents(fileContents) + }) + + }, []) + return ( + <> +
+ +
+ + ) +} \ No newline at end of file diff --git a/apps/doc-viewer/src/app/docviewer.ts b/apps/doc-viewer/src/app/docviewer.ts new file mode 100644 index 00000000000..d6fed6e490f --- /dev/null +++ b/apps/doc-viewer/src/app/docviewer.ts @@ -0,0 +1,22 @@ +import { PluginClient } from '@remixproject/plugin' +import { createClient } from '@remixproject/plugin-webview' +import EventEmitter from 'events' + +export class DocViewer extends PluginClient { + mdFile: string + eventEmitter: EventEmitter + constructor() { + super() + this.eventEmitter = new EventEmitter() + this.methods = ['viewDocs'] + createClient(this) + this.mdFile = '' + this.onload() + } + + async viewDocs(docs: string[]) { + this.mdFile = docs[0] + const contents = await this.call('fileManager', 'readFile', this.mdFile) + this.eventEmitter.emit('contentsReady', contents) + } +} \ No newline at end of file diff --git a/apps/doc-viewer/src/favicon.ico b/apps/doc-viewer/src/favicon.ico new file mode 100644 index 00000000000..bcd5dfd67cd Binary files /dev/null and b/apps/doc-viewer/src/favicon.ico differ diff --git a/apps/doc-viewer/src/index.html b/apps/doc-viewer/src/index.html new file mode 100644 index 00000000000..ab3b67eef14 --- /dev/null +++ b/apps/doc-viewer/src/index.html @@ -0,0 +1,13 @@ + + + + + Doc Viewer + + + + + +
+ + diff --git a/apps/doc-viewer/src/main.tsx b/apps/doc-viewer/src/main.tsx new file mode 100644 index 00000000000..7b8dd49ee65 --- /dev/null +++ b/apps/doc-viewer/src/main.tsx @@ -0,0 +1,10 @@ +import React from 'react' +import ReactDOM from 'react-dom' +import App from './app/App' + +ReactDOM.render( + + + , + document.getElementById("root") +); diff --git a/apps/doc-viewer/tsconfig.app.json b/apps/doc-viewer/tsconfig.app.json new file mode 100644 index 00000000000..af84f21cfc8 --- /dev/null +++ b/apps/doc-viewer/tsconfig.app.json @@ -0,0 +1,23 @@ +{ + "extends": "./tsconfig.json", + "compilerOptions": { + "outDir": "../../dist/out-tsc", + "types": ["node"] + }, + "files": [ + "../../node_modules/@nrwl/react/typings/cssmodule.d.ts", + "../../node_modules/@nrwl/react/typings/image.d.ts" + ], + "exclude": [ + "jest.config.ts", + "**/*.spec.ts", + "**/*.test.ts", + "**/*.spec.tsx", + "**/*.test.tsx", + "**/*.spec.js", + "**/*.test.js", + "**/*.spec.jsx", + "**/*.test.jsx" + ], + "include": ["**/*.js", "**/*.jsx", "**/*.ts", "**/*.tsx"] +} diff --git a/apps/doc-viewer/tsconfig.json b/apps/doc-viewer/tsconfig.json new file mode 100644 index 00000000000..5aab5e79111 --- /dev/null +++ b/apps/doc-viewer/tsconfig.json @@ -0,0 +1,16 @@ +{ + "extends": "../../tsconfig.base.json", + "compilerOptions": { + "jsx": "react-jsx", + "allowJs": true, + "esModuleInterop": true, + "allowSyntheticDefaultImports": true + }, + "files": [], + "include": [], + "references": [ + { + "path": "./tsconfig.app.json" + } + ] +} diff --git a/apps/doc-viewer/webpack.config.js b/apps/doc-viewer/webpack.config.js new file mode 100644 index 00000000000..7b3d088f057 --- /dev/null +++ b/apps/doc-viewer/webpack.config.js @@ -0,0 +1,82 @@ +const { composePlugins, withNx } = require('@nrwl/webpack') +const { withReact } = require('@nrwl/react') +const webpack = require('webpack') +const TerserPlugin = require("terser-webpack-plugin") +const CssMinimizerPlugin = require("css-minimizer-webpack-plugin") + +// Nx plugins for webpack. +module.exports = composePlugins(withNx(), withReact(), (config) => { + // Update the webpack config as needed here. + // e.g. `config.plugins.push(new MyPlugin())` + + // add fallback for node modules + config.resolve.fallback = { + ...config.resolve.fallback, + "crypto": require.resolve("crypto-browserify"), + "stream": require.resolve("stream-browserify"), + "path": require.resolve("path-browserify"), + "http": require.resolve("stream-http"), + "https": require.resolve("https-browserify"), + "constants": require.resolve("constants-browserify"), + "os": false, //require.resolve("os-browserify/browser"), + "timers": false, // require.resolve("timers-browserify"), + "zlib": require.resolve("browserify-zlib"), + "fs": false, + "module": false, + "tls": false, + "net": false, + "readline": false, + "child_process": false, + "buffer": require.resolve("buffer/"), + "vm": require.resolve('vm-browserify'), + } + + // add externals + config.externals = { + ...config.externals, + solc: 'solc', + } + + // add public path + config.output.publicPath = '/' + + // add copy & provide plugin + config.plugins.push( + new webpack.ProvidePlugin({ + Buffer: ['buffer', 'Buffer'], + url: ['url', 'URL'], + process: 'process/browser', + }), + new webpack.DefinePlugin({ + + }), + ) + + // souce-map loader + config.module.rules.push({ + test: /\.js$/, + use: ["source-map-loader"], + enforce: "pre" + }) + + config.ignoreWarnings = [/Failed to parse source map/] // ignore source-map-loader warnings + + // set minimizer + config.optimization.minimizer = [ + new TerserPlugin({ + parallel: true, + terserOptions: { + ecma: 2015, + compress: false, + mangle: false, + format: { + comments: false, + }, + }, + extractComments: false, + }), + new CssMinimizerPlugin(), + ]; + + return config; +}) diff --git a/apps/remix-ide/src/remixAppManager.js b/apps/remix-ide/src/remixAppManager.js index 2a4d7f4671e..2665ec8e3d5 100644 --- a/apps/remix-ide/src/remixAppManager.js +++ b/apps/remix-ide/src/remixAppManager.js @@ -11,7 +11,7 @@ const requiredModules = [ // services + layout views + system views 'filePanel', 'terminal', 'settings', 'pluginManager', 'tabs', 'udapp', 'dGitProvider', 'solidity', 'solidity-logic', 'gistHandler', 'layout', 'notification', 'permissionhandler', 'walkthrough', 'storage', 'restorebackupzip', 'link-libraries', 'deploy-libraries', 'openzeppelin-proxy', 'hardhat-provider', 'ganache-provider', 'foundry-provider', 'basic-http-provider', 'injected', 'injected-trustwallet', 'injected-optimism-provider', 'injected-arbitrum-one-provider', 'vm-custom-fork', 'vm-goerli-fork', 'vm-mainnet-fork', 'vm-sepolia-fork', 'vm-merge', 'vm-london', 'vm-berlin', - 'compileAndRun', 'search', 'recorder', 'fileDecorator', 'codeParser', 'codeFormatter', 'solidityumlgen', 'contractflattener'] + 'compileAndRun', 'search', 'recorder', 'fileDecorator', 'codeParser', 'codeFormatter', 'solidityumlgen', 'contractflattener', 'doc-gen', 'doc-viewer'] // dependentModules shouldn't be manually activated (e.g hardhat is activated by remixd) const dependentModules = ['foundry', 'hardhat', 'truffle', 'slither'] diff --git a/libs/remix-ui/solidity-compiler/src/lib/logic/pdfSaveLogic.ts b/libs/remix-ui/solidity-compiler/src/lib/logic/pdfSaveLogic.ts deleted file mode 100644 index c93c9909902..00000000000 --- a/libs/remix-ui/solidity-compiler/src/lib/logic/pdfSaveLogic.ts +++ /dev/null @@ -1,294 +0,0 @@ -/* eslint-disable prefer-const */ -import domToImage from 'dom-to-image'; -import { jsPDF } from 'jspdf'; - -const _cloneNode = (node, javascriptEnabled) => { - let child = node.firstChild - const clone = node.nodeType === 3 ? document.createTextNode(node.nodeValue) : node.cloneNode(false) - while (child) { - if (javascriptEnabled === true || child.nodeType !== 1 || child.nodeName !== 'SCRIPT') { - clone.appendChild(_cloneNode(child, javascriptEnabled)) - } - child = child.nextSibling - } - if (node.nodeType === 1) { - if (node.nodeName === 'CANVAS') { - clone.width = node.width - clone.height = node.height - clone.getContext('2d').drawImage(node, 0, 0) - } else if (node.nodeName === 'TEXTAREA' || node.nodeName === 'SELECT') { - clone.value = node.value - } - clone.addEventListener('load', (() => { - clone.scrollTop = node.scrollTop - clone.scrollLeft = node.scrollLeft - }), true) - } - return clone -} - -const _createElement = (tagName, {className, innerHTML, style}) => { - let i - let scripts - const el = document.createElement(tagName) - if (className) { - el.className = className - } - if (innerHTML) { - el.innerHTML = innerHTML - scripts = el.getElementsByTagName('script') - i = scripts.length - while (i-- > 0) { - scripts[i].parentNode.removeChild(scripts[i]) - } - } - for (const key in style) { - el.style[key] = style[key]; - } - return el; -}; - -const _isCanvasBlank = canvas => { - const blank = document.createElement('canvas'); - blank.width = canvas.width; - blank.height = canvas.height; - const ctx = blank.getContext('2d'); - ctx.fillStyle = '#FFFFFF'; - ctx.fillRect(0, 0, blank.width, blank.height); - return canvas.toDataURL() === blank.toDataURL(); -}; - -const downloadPdf = (dom, options, cb) => { - const a4Height = 841.89; - const a4Width = 595.28; - let overrideWidth; - let container; - let containerCSS; - let containerWidth; - let elements; - let excludeClassNames; - let excludeTagNames; - let filename; - let filterFn; - let innerRatio; - let overlay; - let overlayCSS; - let pageHeightPx; - let proxyUrl; - let compression = 'NONE'; - let scale; - let opts; - let offsetHeight; - let offsetWidth; - let scaleObj; - let style; - const transformOrigin = 'top left'; - const pdfOptions: any = { - orientation: 'l', - unit: 'pt', - format: 'a4' - }; - - ({filename, excludeClassNames = [], excludeTagNames = ['button', 'input', 'select'], overrideWidth, proxyUrl, compression, scale} = options); - - overlayCSS = { - position: 'fixed', - zIndex: 1000, - opacity: 0, - left: 0, - right: 0, - bottom: 0, - top: 0, - backgroundColor: 'rgba(0,0,0,0.8)' - }; - if (overrideWidth) { - overlayCSS.width = `${overrideWidth}px`; - } - containerCSS = { - position: 'absolute', - left: 0, - right: 0, - top: 0, - height: 'auto', - margin: 'auto', - overflow: 'auto', - backgroundColor: 'white' - }; - overlay = _createElement('div', { - style: overlayCSS, - className: '', - innerHTML: '' - }); - container = _createElement('div', { - style: containerCSS, - className: '', - innerHTML: '' - }); - //@ts-ignore - container.appendChild(_cloneNode(dom)); - overlay.appendChild(container); - document.body.appendChild(overlay); - innerRatio = a4Height / a4Width; - containerWidth = overrideWidth || container.getBoundingClientRect().width; - pageHeightPx = Math.floor(containerWidth * innerRatio); - elements = container.querySelectorAll('*'); - - for (let i = 0, len = excludeClassNames.length; i < len; i++) { - const clName = excludeClassNames[i]; - container.querySelectorAll(`.${clName}`).forEach(function(a) { - return a.remove(); - }); - } - - for (let j = 0, len1 = excludeTagNames.length; j < len1; j++) { - const tName = excludeTagNames[j]; - let els = container.getElementsByTagName(tName); - - for (let k = els.length - 1; k >= 0; k--) { - if (!els[k]) { - continue; - } - els[k].parentNode.removeChild(els[k]); - } - } - - Array.prototype.forEach.call(elements, el => { - let clientRect; - let endPage; - let nPages; - let pad; - let rules; - let startPage; - rules = { - before: false, - after: false, - avoid: true - }; - clientRect = el.getBoundingClientRect(); - if (rules.avoid && !rules.before) { - startPage = Math.floor(clientRect.top / pageHeightPx); - endPage = Math.floor(clientRect.bottom / pageHeightPx); - nPages = Math.abs(clientRect.bottom - clientRect.top) / pageHeightPx; - // Turn on rules.before if the el is broken and is at most one page long. - if (endPage !== startPage && nPages <= 1) { - rules.before = true; - } - // Before: Create a padding div to push the element to the next page. - if (rules.before) { - pad = _createElement('div', { - className: '', - innerHTML: '', - style: { - display: 'block', - height: `${pageHeightPx - clientRect.top % pageHeightPx}px` - } - }); - return el.parentNode.insertBefore(pad, el); - } - } - }); - - // Remove unnecessary elements from result pdf - filterFn = ({classList, tagName}) => { - let cName; - let j; - let len; - let ref; - if (classList) { - for (j = 0, len = excludeClassNames.length; j < len; j++) { - cName = excludeClassNames[j]; - if (Array.prototype.indexOf.call(classList, cName) >= 0) { - return false; - } - } - } - ref = tagName != null ? tagName.toLowerCase() : undefined; - return excludeTagNames.indexOf(ref) < 0; - }; - - opts = { - filter: filterFn, - proxy: proxyUrl - }; - - if (scale) { - offsetWidth = container.offsetWidth; - offsetHeight = container.offsetHeight; - style = { - transform: 'scale(' + scale + ')', - transformOrigin: transformOrigin, - width: offsetWidth + 'px', - height: offsetHeight + 'px' - }; - scaleObj = { - width: offsetWidth * scale, - height: offsetHeight * scale, - quality: 1, - style: style - }; - opts = Object.assign(opts, scaleObj); - } - - return domToImage.toCanvas(container, opts).then(canvas => { - let h; - let imgData; - let nPages; - let page; - let pageCanvas; - let pageCtx; - let pageHeight; - let pdf; - let pxFullHeight; - let w; - // Remove overlay - document.body.removeChild(overlay); - // Initialize the PDF. - pdf = new jsPDF(pdfOptions); - // Calculate the number of pages. - pxFullHeight = canvas.height; - nPages = Math.ceil(pxFullHeight / pageHeightPx); - // Define pageHeight separately so it can be trimmed on the final page. - pageHeight = a4Height; - pageCanvas = document.createElement('canvas'); - pageCtx = pageCanvas.getContext('2d'); - pageCanvas.width = canvas.width; - pageCanvas.height = pageHeightPx; - page = 0; - while (page < nPages) { - if (page === nPages - 1 && pxFullHeight % pageHeightPx !== 0) { - pageCanvas.height = pxFullHeight % pageHeightPx; - pageHeight = pageCanvas.height * a4Width / pageCanvas.width; - } - w = pageCanvas.width; - h = pageCanvas.height; - pageCtx.fillStyle = 'white'; - pageCtx.fillRect(0, 0, w, h); - pageCtx.drawImage(canvas, 0, page * pageHeightPx, w, h, 0, 0, w, h); - // Don't create blank pages - if (_isCanvasBlank(pageCanvas)) { - ++page; - continue; - } - // Add the page to the PDF. - if (page) { - pdf.addPage(); - } - imgData = pageCanvas.toDataURL('image/PNG'); - pdf.addImage(imgData, 'PNG', 0, 0, a4Width, pageHeight, undefined, compression); - ++page; - } - if (typeof cb === "function") { - cb(pdf); - } - return pdf.save(filename); - }).catch(error => { - // Remove overlay - document.body.removeChild(overlay); - if (typeof cb === "function") { - cb(null); - } - return console.error(error); - }); -}; - -module.exports = downloadPdf; \ No newline at end of file diff --git a/package.json b/package.json index 3a8bee75f04..027fb33faf0 100644 --- a/package.json +++ b/package.json @@ -186,11 +186,13 @@ "react-draggable": "^4.4.4", "react-intl": "^6.0.4", "react-json-view": "^1.21.3", + "react-markdown": "^8.0.5", "react-multi-carousel": "^2.8.2", "react-router-dom": "^6.3.0", "react-tabs": "^3.2.2", "react-zoom-pan-pinch": "^3.0.2", "regenerator-runtime": "0.13.7", + "remark-gfm": "^3.0.1", "rss-parser": "^3.12.0", "signale": "^1.4.0", "sol2uml": "^2.4.3", diff --git a/tsconfig.json b/tsconfig.json index 904022e081a..5f976c49efd 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -32,4 +32,4 @@ "module": "NodeNext", } } -} \ No newline at end of file +} diff --git a/tsconfig.paths.json b/tsconfig.paths.json index e45b0114000..dec19c068b1 100644 --- a/tsconfig.paths.json +++ b/tsconfig.paths.json @@ -150,7 +150,7 @@ ], "@remix-project/ghaction-helper": [ "libs/ghaction-helper/src/index.ts" - ] + ], } } } \ No newline at end of file diff --git a/yarn.lock b/yarn.lock index f2b64adf7c2..3f50f178ae8 100644 --- a/yarn.lock +++ b/yarn.lock @@ -174,7 +174,7 @@ source-map "^0.5.0" trim-right "^1.0.1" -"@babel/generator@^7.0.0-beta.44", "@babel/generator@^7.4.0": +"@babel/generator@^7.0.0-beta.44": version "7.15.8" resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.15.8.tgz#fa56be6b596952ceb231048cf84ee499a19c0cd1" integrity sha512-ECmAKstXbp1cvpTTZciZCgfOt6iN64lR0d+euv3UZisU5awfRawOvg07Utn/qBGuH4bRIEZKrA/4LzZyXhZr8g== @@ -183,7 +183,7 @@ jsesc "^2.5.1" source-map "^0.5.0" -"@babel/generator@^7.15.8", "@babel/generator@^7.21.0", "@babel/generator@^7.21.1", "@babel/generator@^7.7.2": +"@babel/generator@^7.15.8", "@babel/generator@^7.21.0", "@babel/generator@^7.21.1", "@babel/generator@^7.4.0", "@babel/generator@^7.7.2": version "7.21.1" resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.21.1.tgz#951cc626057bc0af2c35cd23e9c64d384dea83dd" integrity sha512-1lT45bAYlQhFn/BHivJs43AiW2rg3/UbLyShGfF3C0KmHvO5fSghWd5kBJy30kpRRucGzXStvnnCFniCR2kXAA== @@ -819,7 +819,7 @@ resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.21.1.tgz#a8f81ee2fe872af23faea4b17a08fcc869de7bcc" integrity sha512-JzhBFpkuhBNYUY7qs+wTzNmyCWUHEaAFpQQD2YfU1rPL38/L43Wvid0fFkiOCnHvsGncRZgEPyGnltABLcVDTg== -"@babel/parser@^7.15.8", "@babel/parser@^7.21.2": +"@babel/parser@^7.15.8", "@babel/parser@^7.21.2", "@babel/parser@^7.4.3": version "7.21.2" resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.21.2.tgz#dacafadfc6d7654c3051a66d6fe55b6cb2f2a0b3" integrity sha512-URpaIJQwEkEC2T9Kn+Ai6Xe/02iNaVCuT/PtoRz3GPVJVDpPd7mLo+VddTbhCRU9TXqW5mSrQfXZyi8kDKOVpQ== @@ -844,11 +844,6 @@ resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.19.6.tgz#b923430cb94f58a7eae8facbffa9efd19130e7f8" integrity sha512-h1IUp81s2JYJ3mRkdxJgs4UvmSsRvDrx5ICSJbPvtWYv5i1nTBGcBpnog+89rAFMwvvru6E5NUHdBe01UeSzYA== -"@babel/parser@^7.4.3": - version "7.15.8" - resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.15.8.tgz#7bacdcbe71bdc3ff936d510c15dcea7cf0b99016" - integrity sha512-BRYa3wcQnjS/nqI8Ac94pYYpJfojHVvVXJ97+IDCImX4Jc8W8Xv1+47enbruk+q1etOpsQNwnfFcNGw+gtPGxA== - "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression@^7.18.6": version "7.18.6" resolved "https://registry.yarnpkg.com/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression/-/plugin-bugfix-safari-id-destructuring-collision-in-function-expression-7.18.6.tgz#da5b8f9a580acdfbe53494dba45ea389fb09a4d2" @@ -2039,7 +2034,7 @@ "@babel/types" "7.0.0-beta.53" lodash "^4.17.5" -"@babel/template@^7.15.4", "@babel/template@^7.20.7", "@babel/template@^7.3.3": +"@babel/template@^7.15.4", "@babel/template@^7.20.7", "@babel/template@^7.3.3", "@babel/template@^7.4.0": version "7.20.7" resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.20.7.tgz#a15090c2839a83b02aa996c0b4994005841fd5a8" integrity sha512-8SegXApWe6VoNw0r9JHpSteLKTpTiLZ4rMlGIm9JQ18KiCtyQiAMEazujAHrUS5flrcqYZa75ukev3P6QmUwUw== @@ -2048,7 +2043,7 @@ "@babel/parser" "^7.20.7" "@babel/types" "^7.20.7" -"@babel/template@^7.16.0", "@babel/template@^7.4.0": +"@babel/template@^7.16.0": version "7.16.0" resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.16.0.tgz#d16a35ebf4cd74e202083356fab21dd89363ddd6" integrity sha512-MnZdpFD/ZdYhXwiunMqqgyZyucaYsbL0IrjoGjaVhGilz+x8YB++kRfygSOIj1yOtWKPlx7NBp+9I1RQSgsd5A== @@ -2082,7 +2077,7 @@ invariant "^2.2.0" lodash "^4.17.5" -"@babel/traverse@^7.15.4", "@babel/traverse@^7.21.2": +"@babel/traverse@^7.15.4", "@babel/traverse@^7.21.2", "@babel/traverse@^7.4.3": version "7.21.2" resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.21.2.tgz#ac7e1f27658750892e815e60ae90f382a46d8e75" integrity sha512-ts5FFU/dSUPS13tv8XiEObDu9K+iagEKME9kAbaP7r0Y9KtZJZ+NGndDvWoRAYNpeWafbpFeki3q9QoMD6gxyw== @@ -2098,7 +2093,7 @@ debug "^4.1.0" globals "^11.1.0" -"@babel/traverse@^7.16.0", "@babel/traverse@^7.4.3": +"@babel/traverse@^7.16.0": version "7.16.3" resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.16.3.tgz#f63e8a938cc1b780f66d9ed3c54f532ca2d14787" integrity sha512-eolumr1vVMjqevCpwVO99yN/LoGL0EyHiLO5I043aYQvwOJ9eR5UsZSClHVCzfhBduMAsSzgA/6AyqPjNayJag== @@ -2195,7 +2190,7 @@ "@babel/helper-validator-identifier" "^7.19.1" to-fast-properties "^2.0.0" -"@babel/types@^7.15.6", "@babel/types@^7.16.0", "@babel/types@^7.4.0", "@babel/types@^7.4.4": +"@babel/types@^7.15.6", "@babel/types@^7.16.0", "@babel/types@^7.4.4": version "7.16.0" resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.16.0.tgz#db3b313804f96aadd0b776c4823e127ad67289ba" integrity sha512-PJgg/k3SdLsGb3hhisFvtLOw5ts113klrpLuIPtCJIU+BB24fqq6lf8RWqKJEjzqXR9AEH1rIb5XTqwBHB+kQg== @@ -2239,7 +2234,7 @@ "@babel/helper-validator-identifier" "^7.19.1" to-fast-properties "^2.0.0" -"@babel/types@^7.21.2": +"@babel/types@^7.21.2", "@babel/types@^7.4.0": version "7.21.2" resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.21.2.tgz#92246f6e00f91755893c2876ad653db70c8310d1" integrity sha512-3wRZSs7jiFaB8AjxiiD+VqN5DTG2iRvJGQ+qYFrs/654lg6kGTQWIOFjlBo5RaXuAZjBmP3+OQH4dmhqiiyYxw== @@ -6003,6 +5998,13 @@ dependencies: "@types/node" "*" +"@types/hast@^2.0.0": + version "2.3.4" + resolved "https://registry.yarnpkg.com/@types/hast/-/hast-2.3.4.tgz#8aa5ef92c117d20d974a82bdfb6a648b08c0bafc" + integrity sha512-wLEm0QvaoawEDoTRwzTXp4b4jpwiJDvR5KMnFnVodm3scufTlBOWRD6N1OBf9TZMhjlNsSfcO5V+7AF4+Vy+9g== + dependencies: + "@types/unist" "*" + "@types/history@*": version "4.7.9" resolved "https://registry.yarnpkg.com/@types/history/-/history-4.7.9.tgz#1cfb6d60ef3822c589f18e70f8b12f9a28ce8724" @@ -6101,6 +6103,13 @@ resolved "https://registry.yarnpkg.com/@types/lru-cache/-/lru-cache-5.1.1.tgz#c48c2e27b65d2a153b19bfc1a317e30872e01eef" integrity sha512-ssE3Vlrys7sdIzs5LOxCzTVMsU7i9oa/IaW92wF32JFb3CVczqOkru2xspuKczHEbG3nvmPY7IFqVmGGHdNbYw== +"@types/mdast@^3.0.0": + version "3.0.10" + resolved "https://registry.yarnpkg.com/@types/mdast/-/mdast-3.0.10.tgz#4724244a82a4598884cbbe9bcfd73dff927ee8af" + integrity sha512-W864tg/Osz1+9f4lrGTZpCSO5/z4608eUp19tbozkq2HJK6i3z1kT0H9tlADXuYIb1YYOBByU4Jsqkk75q48qA== + dependencies: + "@types/unist" "*" + "@types/mime@*": version "3.0.1" resolved "https://registry.yarnpkg.com/@types/mime/-/mime-3.0.1.tgz#5f8f2bca0a5863cb69bc0b0acd88c96cb1d4ae10" @@ -6177,6 +6186,11 @@ resolved "https://registry.yarnpkg.com/@types/prop-types/-/prop-types-15.7.4.tgz#fcf7205c25dff795ee79af1e30da2c9790808f11" integrity sha512-rZ5drC/jWjrArrS8BR6SIr4cWpW09RNTYt9AMZo3Jwwif+iacXAqgVjm0B0Bv/S1jhDXKHqRVNCbACkJ89RAnQ== +"@types/prop-types@^15.0.0": + version "15.7.5" + resolved "https://registry.yarnpkg.com/@types/prop-types/-/prop-types-15.7.5.tgz#5f19d2b85a98e9558036f6a3cacc8819420f05cf" + integrity sha512-JCB8C6SnDoQf0cNycqd/35A7MjcnK+ZTqE7judS6o7utxUCg6imJg3QK2qzHKszlTjcj2cn+NwMB2i96ubpj7w== + "@types/qs@*": version "6.9.7" resolved "https://registry.yarnpkg.com/@types/qs/-/qs-6.9.7.tgz#63bb7d067db107cc1e457c303bc25d511febf6cb" @@ -6369,6 +6383,11 @@ resolved "https://registry.yarnpkg.com/@types/tough-cookie/-/tough-cookie-4.0.1.tgz#8f80dd965ad81f3e1bc26d6f5c727e132721ff40" integrity sha512-Y0K95ThC3esLEYD6ZuqNek29lNX2EM1qxV8y2FTLUB0ff5wWrk7az+mLrnNFUnaXcgKye22+sFBRXOgpPILZNg== +"@types/unist@*", "@types/unist@^2.0.0": + version "2.0.6" + resolved "https://registry.yarnpkg.com/@types/unist/-/unist-2.0.6.tgz#250a7b16c3b91f672a24552ec64678eeb1d3a08d" + integrity sha512-PBjIUxZHOuj0R15/xuwJYjFi+KZdNFrehocChv4g5hu6aFroHue8m0lBP0POdK2nKzbw0cgV1mws8+V/JAcEkQ== + "@types/warning@^3.0.0": version "3.0.0" resolved "https://registry.yarnpkg.com/@types/warning/-/warning-3.0.0.tgz#0d2501268ad8f9962b740d387c4654f5f8e23e52" @@ -8250,6 +8269,11 @@ bach@^1.0.0: async-settle "^1.0.0" now-and-later "^2.0.0" +bail@^2.0.0: + version "2.0.2" + resolved "https://registry.yarnpkg.com/bail/-/bail-2.0.2.tgz#d26f5cd8fe5d6f832a31517b9f7c356040ba6d5d" + integrity sha512-0xO6mYd7JB2YesxDKplafRpsiOzPt9V02ddPCLbY1xYGPOX24NTyN50qnUxgCPcSoYMhKpAuBTjQoRZCAkUDRw== + balanced-match@^0.4.1: version "0.4.2" resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-0.4.2.tgz#cb3f3e3c732dc0f01ee70b403f302e61d7709838" @@ -9135,9 +9159,9 @@ call-limit@~1.1.0: integrity sha512-2waS4t+GBOSXb5hZyPRjo1m2ndtQUwMj1rIYa3XnLnFlfd5uNnxo3nyPQF+i7yDpgz95ed9Ga6hpgVXi+0oMeA== call-me-maybe@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/call-me-maybe/-/call-me-maybe-1.0.1.tgz#26d208ea89e37b5cbde60250a15f031c16a4d66b" - integrity sha512-wCyFsDQkKPwwF8BDwOiWNx/9K45L/hvggQiDbve+viMNMQnWhrlYIuBk09offfwCRtCO9P6XwUttufzU11WCVw== + version "1.0.2" + resolved "https://registry.yarnpkg.com/call-me-maybe/-/call-me-maybe-1.0.2.tgz#03f964f19522ba643b1b0693acb9152fe2074baa" + integrity sha512-HpX65o1Hnr9HH25ojC1YGs7HCQLq0GCOibSaWER0eNpgJ/Z1MZv2mTc7+xh6WOPxbRVcmgbv4hGU+uSQ/2xFZQ== caller-callsite@^2.0.0: version "2.0.0" @@ -9318,6 +9342,11 @@ cbor@^8.0.0: dependencies: nofilter "^3.1.0" +ccount@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/ccount/-/ccount-2.0.1.tgz#17a3bf82302e0870d6da43a01311a8bc02a3ecf5" + integrity sha512-eyrF0jiFpY+3drT6383f1qhkbGsLSifNAjA61IUjZjmLCWjItY6LB9ft9YhoDgwfmclB2zhu51Lc7+95b8NRAg== + center-align@^0.1.1: version "0.1.3" resolved "https://registry.yarnpkg.com/center-align/-/center-align-0.1.3.tgz#aa0d32629b6ee972200411cbd4461c907bc2b7ad" @@ -9397,6 +9426,11 @@ char-regex@^1.0.2: resolved "https://registry.yarnpkg.com/char-regex/-/char-regex-1.0.2.tgz#d744358226217f981ed58f479b1d6bcc29545dcf" integrity sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw== +character-entities@^2.0.0: + version "2.0.2" + resolved "https://registry.yarnpkg.com/character-entities/-/character-entities-2.0.2.tgz#2d09c2e72cd9523076ccb21157dff66ad43fcc22" + integrity sha512-shx7oQ0Awen/BRIdkjkvz54PnEEI/EjwXDSIZp86/KKdbafHh1Df/RYGBhn4hbe2+uKC9FnT5UCEdyPz3ai9hQ== + chardet@^0.7.0: version "0.7.0" resolved "https://registry.yarnpkg.com/chardet/-/chardet-0.7.0.tgz#90094849f0937f2eedc2425d0d28a9e5f0cbad9e" @@ -9953,6 +9987,11 @@ combined-stream@^1.0.6, combined-stream@^1.0.8, combined-stream@~1.0.6: dependencies: delayed-stream "~1.0.0" +comma-separated-tokens@^2.0.0: + version "2.0.3" + resolved "https://registry.yarnpkg.com/comma-separated-tokens/-/comma-separated-tokens-2.0.3.tgz#4e89c9458acb61bc8fef19f4529973b2392839ee" + integrity sha512-Fu4hJdvzeylCfQPp9SGWidpzrMs7tTrlu6Vb8XGaRGck8QSNZJJp538Wrb60Lax4fPwR64ViY468OIUTbRlGZg== + command-exists@^1.2.8: version "1.2.9" resolved "https://registry.yarnpkg.com/command-exists/-/command-exists-1.2.9.tgz#c50725af3808c8ab0260fd60b01fbfa25b954f69" @@ -11013,6 +11052,13 @@ decamelize@^4.0.0: resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-4.0.0.tgz#aa472d7bf660eb15f3494efd531cab7f2a709837" integrity sha512-9iE1PgSik9HeIIw2JO94IidnE3eBoQrFJ3w7sFuzSX4DpmZ3v5sZpUiV5Swcf6mQEF+Y0ru8Neo+p+nyh2J+hQ== +decode-named-character-reference@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/decode-named-character-reference/-/decode-named-character-reference-1.0.2.tgz#daabac9690874c394c81e4162a0304b35d824f0e" + integrity sha512-O8x12RzrUF8xyVcY0KJowWsmaJxQbmy0/EtnNtHRpsOcT7dFk5W598coHqBVpmWo1oQQfsCqfCmkZN5DJrZVdg== + dependencies: + character-entities "^2.0.0" + decode-uri-component@^0.2.0: version "0.2.2" resolved "https://registry.yarnpkg.com/decode-uri-component/-/decode-uri-component-0.2.2.tgz#e69dbe25d37941171dd540e024c444cd5188e1e9" @@ -11251,6 +11297,11 @@ deps-sort@^2.0.0, deps-sort@^2.0.1: subarg "^1.0.0" through2 "^2.0.0" +dequal@^2.0.0: + version "2.0.3" + resolved "https://registry.yarnpkg.com/dequal/-/dequal-2.0.3.tgz#2644214f1997d39ed0ee0ece72335490a7ac67be" + integrity sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA== + dequal@^2.0.2: version "2.0.2" resolved "https://registry.yarnpkg.com/dequal/-/dequal-2.0.2.tgz#85ca22025e3a87e65ef75a7a437b35284a7e319d" @@ -11351,6 +11402,11 @@ diff@^4.0.1: resolved "https://registry.yarnpkg.com/diff/-/diff-4.0.2.tgz#60f3aecb89d5fae520c11aa19efc2bb982aade7d" integrity sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A== +diff@^5.0.0: + version "5.1.0" + resolved "https://registry.yarnpkg.com/diff/-/diff-5.1.0.tgz#bc52d298c5ea8df9194800224445ed43ffc87e40" + integrity sha512-D+mk+qE8VC/PAUrlAU34N+VfXev0ghe5ywmpqrawphmVZc1bEfn56uo9qpyGp1p4xpzOHkSW4ztBd6L7Xx4ACw== + diffie-hellman@^5.0.0: version "5.0.3" resolved "https://registry.yarnpkg.com/diffie-hellman/-/diffie-hellman-5.0.3.tgz#40e8ee98f55a2149607146921c63e1ae5f3d2875" @@ -11572,12 +11628,7 @@ duplexer3@^0.1.4: resolved "https://registry.yarnpkg.com/duplexer3/-/duplexer3-0.1.4.tgz#ee01dd1cac0ed3cbc7fdbea37dc0a8f1ce002ce2" integrity sha1-7gHdHKwO08vH/b6jfcCo8c4ALOI= -duplexer@^0.1.1: - version "0.1.1" - resolved "https://registry.yarnpkg.com/duplexer/-/duplexer-0.1.1.tgz#ace6ff808c1ce66b57d1ebf97977acb02334cfc1" - integrity sha1-rOb/gIwc5mtX0ev5eXessCM0z8E= - -duplexer@^0.1.2: +duplexer@^0.1.1, duplexer@^0.1.2: version "0.1.2" resolved "https://registry.yarnpkg.com/duplexer/-/duplexer-0.1.2.tgz#3abe43aef3835f8ae077d136ddce0f276b0400e6" integrity sha512-jtD6YG370ZCIi/9GTaJKQxWTZD045+4R4hTk/x1UyoqadyJ9x9CgSi1RlVDQF8U2sxLLSnFkCaMihqljHIWgMg== @@ -11983,6 +12034,11 @@ escape-string-regexp@^2.0.0: resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz#a30304e99daa32e23b2fd20f51babd07cffca344" integrity sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w== +escape-string-regexp@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-5.0.0.tgz#4683126b500b61762f2dbebace1806e8be31b1c8" + integrity sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw== + eslint-config-prettier@^8.5.0: version "8.5.0" resolved "https://registry.yarnpkg.com/eslint-config-prettier/-/eslint-config-prettier-8.5.0.tgz#5a81680ec934beca02c7b1a61cf8ca34b66feab1" @@ -13186,7 +13242,7 @@ find-up@5.0.0, find-up@^5.0.0: find-up@^1.0.0: version "1.1.2" resolved "https://registry.yarnpkg.com/find-up/-/find-up-1.1.2.tgz#6b2e9822b1a2ce0a60ab64d610eccad53cb24d0f" - integrity sha1-ay6YIrGizgpgq2TWEOzK1TyyTQ8= + integrity sha512-jvElSjyuo4EMQGoTwo1uJU5pQMwTW5lS1x05zzfJuTIyLR3zwO27LYrxNg+dlvKpGOuGy/MzBdXh80g0ve5+HA== dependencies: path-exists "^2.0.0" pinkie-promise "^2.0.0" @@ -13993,7 +14049,7 @@ glob-stream@^6.1.0: glob-to-regexp@^0.3.0: version "0.3.0" resolved "https://registry.yarnpkg.com/glob-to-regexp/-/glob-to-regexp-0.3.0.tgz#8c5a1494d2066c570cc3bfe4496175acc4d502ab" - integrity sha1-jFoUlNIGbFcMw7/kSWF1rMTVAqs= + integrity sha512-Iozmtbqv0noj0uDDqoL0zNq0VBEfK2YFoMAZoxJe4cwphvLR+JskfF30QhXHOR4m3KrE6NLRYw+U9MRXvifyig== glob-to-regexp@^0.4.1: version "0.4.1" @@ -14498,7 +14554,7 @@ harmony-reflect@^1.4.6: has-ansi@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/has-ansi/-/has-ansi-2.0.0.tgz#34f5049ce1ecdf2b0649af3ef24e45ed35416d91" - integrity sha1-NPUEnOHs3ysGSa8+8k5F7TVBbZE= + integrity sha512-C8vBJ8DwUCx19vhm7urhTuUsr4/IyP6l4VzNQDv+ryHQObW3TTTp9yB68WpYgRe2bbaGuZ/se74IqFeVnMnLZg== dependencies: ansi-regex "^2.0.0" @@ -14630,6 +14686,11 @@ hasha@^3.0.0: dependencies: is-stream "^1.0.1" +hast-util-whitespace@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/hast-util-whitespace/-/hast-util-whitespace-2.0.1.tgz#0ec64e257e6fc216c7d14c8a1b74d27d650b4557" + integrity sha512-nAxA0v8+vXSBDt3AnRUNjyRIQ0rD+ntpbAp4LnPkumc5M9yUbSMa4XDU9Q6etY4f1Wp4bNgvc1yjiZtsTTrSng== + hawk@~3.1.3: version "3.1.3" resolved "https://registry.yarnpkg.com/hawk/-/hawk-3.1.3.tgz#078444bd7c1640b0fe540d2c9b73d59678e8e1c4" @@ -15562,7 +15623,14 @@ is-circular@^1.0.2: resolved "https://registry.yarnpkg.com/is-circular/-/is-circular-1.0.2.tgz#2e0ab4e9835f4c6b0ea2b9855a84acd501b8366c" integrity sha512-YttjnrswnUYRVJvxCvu8z+PGMUSzC2JttP0OEXezlAEdp3EXzhf7IZ3j0gRAybJBQupedIZFhY61Tga6E0qASA== -is-core-module@^2.2.0, is-core-module@^2.5.0: +is-core-module@^2.2.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/is-core-module/-/is-core-module-2.2.0.tgz#97037ef3d52224d85163f5597b2b63d9afed981a" + integrity sha512-XRAfAdyyY5F5cOXn7hYQDqh2Xmii+DEfIcQGxK/uNwMHhIkPWO0g8msXcbzLe+MpGoR951MlqM/2iIlU4vKDdQ== + dependencies: + has "^1.0.3" + +is-core-module@^2.5.0: version "2.8.0" resolved "https://registry.yarnpkg.com/is-core-module/-/is-core-module-2.8.0.tgz#0321336c3d0925e497fd97f5d95cb114a5ccd548" integrity sha512-vd15qHsaqrRL7dtH6QNuy0ndJmRDrS9HAM1CAiSifNUFv4x1a0CCVsj18hJ1mShxIG6T2i1sO78MkP56r0nYRw== @@ -15837,6 +15905,11 @@ is-plain-obj@^3.0.0: resolved "https://registry.yarnpkg.com/is-plain-obj/-/is-plain-obj-3.0.0.tgz#af6f2ea14ac5a646183a5bbdb5baabbc156ad9d7" integrity sha512-gwsOE28k+23GP1B6vFl1oVh/WOzmawBrKwo5Ev6wMKzPkaXaCDIQKzLnvsA42DRlbVTWorkgTKIviAKCWkfUwA== +is-plain-obj@^4.0.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/is-plain-obj/-/is-plain-obj-4.1.0.tgz#d65025edec3657ce032fd7db63c97883eaed71f0" + integrity sha512-+Pgi+vMuUNkJyExiMBt5IlFoMyKnr5zhJ4Uspz58WOhBF5QoIZkFyNHIbBAtHwzVAgk5RtndVNsDRN61/mmDqg== + is-plain-object@^2.0.1, is-plain-object@^2.0.3, is-plain-object@^2.0.4: version "2.0.4" resolved "https://registry.yarnpkg.com/is-plain-object/-/is-plain-object-2.0.4.tgz#2c163b3fafb1b606d9d17928f05c2a1c38e07677" @@ -17083,6 +17156,11 @@ klaw@^4.0.1: resolved "https://registry.yarnpkg.com/klaw/-/klaw-4.0.1.tgz#8dc6f5723f05894e8e931b516a8ff15c2976d368" integrity sha512-pgsE40/SvC7st04AHiISNewaIMUbY5V/K8b21ekiPiFoYs/EYSdsGa+FJArB1d441uq4Q8zZyIxvAzkGNlBdRw== +kleur@^4.0.3: + version "4.1.5" + resolved "https://registry.yarnpkg.com/kleur/-/kleur-4.1.5.tgz#95106101795f7050c6c650f350c683febddb1780" + integrity sha512-o+NO+8WrRiQEE4/7nwRJhN1HWpVmJm511pBHUxPLtp0BUISzlBplORYSmTclCnJvQq2tKu/sgl3xVpkc7ZWuQQ== + klona@^2.0.4, klona@^2.0.5: version "2.0.5" resolved "https://registry.yarnpkg.com/klona/-/klona-2.0.5.tgz#d166574d90076395d9963aa7a928fabb8d76afbc" @@ -17680,6 +17758,11 @@ logform@^2.2.0: safe-stable-stringify "^1.1.0" triple-beam "^1.3.0" +longest-streak@^3.0.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/longest-streak/-/longest-streak-3.1.0.tgz#62fa67cd958742a1574af9f39866364102d90cd4" + integrity sha512-9Ri+o0JYgehTaVBBDoMqIl8GXtbWg711O3srftcHhZ0dqnETqLaoIK0x17fUw9rFSlK/0NlsKe0Ahhyl5pXE2g== + longest@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/longest/-/longest-1.0.1.tgz#30a0b2da38f73770e8294a0d22e6625ed77d0097" @@ -17906,6 +17989,11 @@ map-visit@^1.0.0: dependencies: object-visit "^1.0.0" +markdown-table@^3.0.0: + version "3.0.3" + resolved "https://registry.yarnpkg.com/markdown-table/-/markdown-table-3.0.3.tgz#e6331d30e493127e031dd385488b5bd326e4a6bd" + integrity sha512-Z1NL3Tb1M9wH4XESsCDEksWoKTdlUafKc4pt0GRwjUyXaCFZ+dc3g2erqB6zm3szA2IUSi7VnPI+o/9jnxh9hw== + marked-terminal@^3.3.0: version "3.3.0" resolved "https://registry.yarnpkg.com/marked-terminal/-/marked-terminal-3.3.0.tgz#25ce0c0299285998c7636beaefc87055341ba1bd" @@ -17952,6 +18040,144 @@ md5.js@^1.3.4: inherits "^2.0.1" safe-buffer "^5.1.2" +mdast-util-definitions@^5.0.0: + version "5.1.2" + resolved "https://registry.yarnpkg.com/mdast-util-definitions/-/mdast-util-definitions-5.1.2.tgz#9910abb60ac5d7115d6819b57ae0bcef07a3f7a7" + integrity sha512-8SVPMuHqlPME/z3gqVwWY4zVXn8lqKv/pAhC57FuJ40ImXyBpmO5ukh98zB2v7Blql2FiHjHv9LVztSIqjY+MA== + dependencies: + "@types/mdast" "^3.0.0" + "@types/unist" "^2.0.0" + unist-util-visit "^4.0.0" + +mdast-util-find-and-replace@^2.0.0: + version "2.2.2" + resolved "https://registry.yarnpkg.com/mdast-util-find-and-replace/-/mdast-util-find-and-replace-2.2.2.tgz#cc2b774f7f3630da4bd592f61966fecade8b99b1" + integrity sha512-MTtdFRz/eMDHXzeK6W3dO7mXUlF82Gom4y0oOgvHhh/HXZAGvIQDUvQ0SuUx+j2tv44b8xTHOm8K/9OoRFnXKw== + dependencies: + "@types/mdast" "^3.0.0" + escape-string-regexp "^5.0.0" + unist-util-is "^5.0.0" + unist-util-visit-parents "^5.0.0" + +mdast-util-from-markdown@^1.0.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/mdast-util-from-markdown/-/mdast-util-from-markdown-1.3.0.tgz#0214124154f26154a2b3f9d401155509be45e894" + integrity sha512-HN3W1gRIuN/ZW295c7zi7g9lVBllMgZE40RxCX37wrTPWXCWtpvOZdfnuK+1WNpvZje6XuJeI3Wnb4TJEUem+g== + dependencies: + "@types/mdast" "^3.0.0" + "@types/unist" "^2.0.0" + decode-named-character-reference "^1.0.0" + mdast-util-to-string "^3.1.0" + micromark "^3.0.0" + micromark-util-decode-numeric-character-reference "^1.0.0" + micromark-util-decode-string "^1.0.0" + micromark-util-normalize-identifier "^1.0.0" + micromark-util-symbol "^1.0.0" + micromark-util-types "^1.0.0" + unist-util-stringify-position "^3.0.0" + uvu "^0.5.0" + +mdast-util-gfm-autolink-literal@^1.0.0: + version "1.0.3" + resolved "https://registry.yarnpkg.com/mdast-util-gfm-autolink-literal/-/mdast-util-gfm-autolink-literal-1.0.3.tgz#67a13abe813d7eba350453a5333ae1bc0ec05c06" + integrity sha512-My8KJ57FYEy2W2LyNom4n3E7hKTuQk/0SES0u16tjA9Z3oFkF4RrC/hPAPgjlSpezsOvI8ObcXcElo92wn5IGA== + dependencies: + "@types/mdast" "^3.0.0" + ccount "^2.0.0" + mdast-util-find-and-replace "^2.0.0" + micromark-util-character "^1.0.0" + +mdast-util-gfm-footnote@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/mdast-util-gfm-footnote/-/mdast-util-gfm-footnote-1.0.2.tgz#ce5e49b639c44de68d5bf5399877a14d5020424e" + integrity sha512-56D19KOGbE00uKVj3sgIykpwKL179QsVFwx/DCW0u/0+URsryacI4MAdNJl0dh+u2PSsD9FtxPFbHCzJ78qJFQ== + dependencies: + "@types/mdast" "^3.0.0" + mdast-util-to-markdown "^1.3.0" + micromark-util-normalize-identifier "^1.0.0" + +mdast-util-gfm-strikethrough@^1.0.0: + version "1.0.3" + resolved "https://registry.yarnpkg.com/mdast-util-gfm-strikethrough/-/mdast-util-gfm-strikethrough-1.0.3.tgz#5470eb105b483f7746b8805b9b989342085795b7" + integrity sha512-DAPhYzTYrRcXdMjUtUjKvW9z/FNAMTdU0ORyMcbmkwYNbKocDpdk+PX1L1dQgOID/+vVs1uBQ7ElrBQfZ0cuiQ== + dependencies: + "@types/mdast" "^3.0.0" + mdast-util-to-markdown "^1.3.0" + +mdast-util-gfm-table@^1.0.0: + version "1.0.7" + resolved "https://registry.yarnpkg.com/mdast-util-gfm-table/-/mdast-util-gfm-table-1.0.7.tgz#3552153a146379f0f9c4c1101b071d70bbed1a46" + integrity sha512-jjcpmNnQvrmN5Vx7y7lEc2iIOEytYv7rTvu+MeyAsSHTASGCCRA79Igg2uKssgOs1i1po8s3plW0sTu1wkkLGg== + dependencies: + "@types/mdast" "^3.0.0" + markdown-table "^3.0.0" + mdast-util-from-markdown "^1.0.0" + mdast-util-to-markdown "^1.3.0" + +mdast-util-gfm-task-list-item@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/mdast-util-gfm-task-list-item/-/mdast-util-gfm-task-list-item-1.0.2.tgz#b280fcf3b7be6fd0cc012bbe67a59831eb34097b" + integrity sha512-PFTA1gzfp1B1UaiJVyhJZA1rm0+Tzn690frc/L8vNX1Jop4STZgOE6bxUhnzdVSB+vm2GU1tIsuQcA9bxTQpMQ== + dependencies: + "@types/mdast" "^3.0.0" + mdast-util-to-markdown "^1.3.0" + +mdast-util-gfm@^2.0.0: + version "2.0.2" + resolved "https://registry.yarnpkg.com/mdast-util-gfm/-/mdast-util-gfm-2.0.2.tgz#e92f4d8717d74bdba6de57ed21cc8b9552e2d0b6" + integrity sha512-qvZ608nBppZ4icQlhQQIAdc6S3Ffj9RGmzwUKUWuEICFnd1LVkN3EktF7ZHAgfcEdvZB5owU9tQgt99e2TlLjg== + dependencies: + mdast-util-from-markdown "^1.0.0" + mdast-util-gfm-autolink-literal "^1.0.0" + mdast-util-gfm-footnote "^1.0.0" + mdast-util-gfm-strikethrough "^1.0.0" + mdast-util-gfm-table "^1.0.0" + mdast-util-gfm-task-list-item "^1.0.0" + mdast-util-to-markdown "^1.0.0" + +mdast-util-phrasing@^3.0.0: + version "3.0.1" + resolved "https://registry.yarnpkg.com/mdast-util-phrasing/-/mdast-util-phrasing-3.0.1.tgz#c7c21d0d435d7fb90956038f02e8702781f95463" + integrity sha512-WmI1gTXUBJo4/ZmSk79Wcb2HcjPJBzM1nlI/OUWA8yk2X9ik3ffNbBGsU+09BFmXaL1IBb9fiuvq6/KMiNycSg== + dependencies: + "@types/mdast" "^3.0.0" + unist-util-is "^5.0.0" + +mdast-util-to-hast@^12.1.0: + version "12.3.0" + resolved "https://registry.yarnpkg.com/mdast-util-to-hast/-/mdast-util-to-hast-12.3.0.tgz#045d2825fb04374e59970f5b3f279b5700f6fb49" + integrity sha512-pits93r8PhnIoU4Vy9bjW39M2jJ6/tdHyja9rrot9uujkN7UTU9SDnE6WNJz/IGyQk3XHX6yNNtrBH6cQzm8Hw== + dependencies: + "@types/hast" "^2.0.0" + "@types/mdast" "^3.0.0" + mdast-util-definitions "^5.0.0" + micromark-util-sanitize-uri "^1.1.0" + trim-lines "^3.0.0" + unist-util-generated "^2.0.0" + unist-util-position "^4.0.0" + unist-util-visit "^4.0.0" + +mdast-util-to-markdown@^1.0.0, mdast-util-to-markdown@^1.3.0: + version "1.5.0" + resolved "https://registry.yarnpkg.com/mdast-util-to-markdown/-/mdast-util-to-markdown-1.5.0.tgz#c13343cb3fc98621911d33b5cd42e7d0731171c6" + integrity sha512-bbv7TPv/WC49thZPg3jXuqzuvI45IL2EVAr/KxF0BSdHsU0ceFHOmwQn6evxAh1GaoK/6GQ1wp4R4oW2+LFL/A== + dependencies: + "@types/mdast" "^3.0.0" + "@types/unist" "^2.0.0" + longest-streak "^3.0.0" + mdast-util-phrasing "^3.0.0" + mdast-util-to-string "^3.0.0" + micromark-util-decode-string "^1.0.0" + unist-util-visit "^4.0.0" + zwitch "^2.0.0" + +mdast-util-to-string@^3.0.0, mdast-util-to-string@^3.1.0: + version "3.1.1" + resolved "https://registry.yarnpkg.com/mdast-util-to-string/-/mdast-util-to-string-3.1.1.tgz#db859050d79d48cf9896d294de06f3ede7474d16" + integrity sha512-tGvhT94e+cVnQt8JWE9/b3cUQZWS732TJxXHktvP+BYo62PpYD53Ls/6cC60rW21dW+txxiM4zMdc6abASvZKA== + dependencies: + "@types/mdast" "^3.0.0" + mdn-data@2.0.14: version "2.0.14" resolved "https://registry.yarnpkg.com/mdn-data/-/mdn-data-2.0.14.tgz#7113fc4281917d63ce29b43446f701e68c25ba50" @@ -18112,6 +18338,281 @@ methods@~1.1.2: resolved "https://registry.yarnpkg.com/methods/-/methods-1.1.2.tgz#5529a4d67654134edcc5266656835b0f851afcee" integrity sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4= +micromark-core-commonmark@^1.0.0, micromark-core-commonmark@^1.0.1: + version "1.0.6" + resolved "https://registry.yarnpkg.com/micromark-core-commonmark/-/micromark-core-commonmark-1.0.6.tgz#edff4c72e5993d93724a3c206970f5a15b0585ad" + integrity sha512-K+PkJTxqjFfSNkfAhp4GB+cZPfQd6dxtTXnf+RjZOV7T4EEXnvgzOcnp+eSTmpGk9d1S9sL6/lqrgSNn/s0HZA== + dependencies: + decode-named-character-reference "^1.0.0" + micromark-factory-destination "^1.0.0" + micromark-factory-label "^1.0.0" + micromark-factory-space "^1.0.0" + micromark-factory-title "^1.0.0" + micromark-factory-whitespace "^1.0.0" + micromark-util-character "^1.0.0" + micromark-util-chunked "^1.0.0" + micromark-util-classify-character "^1.0.0" + micromark-util-html-tag-name "^1.0.0" + micromark-util-normalize-identifier "^1.0.0" + micromark-util-resolve-all "^1.0.0" + micromark-util-subtokenize "^1.0.0" + micromark-util-symbol "^1.0.0" + micromark-util-types "^1.0.1" + uvu "^0.5.0" + +micromark-extension-gfm-autolink-literal@^1.0.0: + version "1.0.3" + resolved "https://registry.yarnpkg.com/micromark-extension-gfm-autolink-literal/-/micromark-extension-gfm-autolink-literal-1.0.3.tgz#dc589f9c37eaff31a175bab49f12290edcf96058" + integrity sha512-i3dmvU0htawfWED8aHMMAzAVp/F0Z+0bPh3YrbTPPL1v4YAlCZpy5rBO5p0LPYiZo0zFVkoYh7vDU7yQSiCMjg== + dependencies: + micromark-util-character "^1.0.0" + micromark-util-sanitize-uri "^1.0.0" + micromark-util-symbol "^1.0.0" + micromark-util-types "^1.0.0" + uvu "^0.5.0" + +micromark-extension-gfm-footnote@^1.0.0: + version "1.0.4" + resolved "https://registry.yarnpkg.com/micromark-extension-gfm-footnote/-/micromark-extension-gfm-footnote-1.0.4.tgz#cbfd8873b983e820c494498c6dac0105920818d5" + integrity sha512-E/fmPmDqLiMUP8mLJ8NbJWJ4bTw6tS+FEQS8CcuDtZpILuOb2kjLqPEeAePF1djXROHXChM/wPJw0iS4kHCcIg== + dependencies: + micromark-core-commonmark "^1.0.0" + micromark-factory-space "^1.0.0" + micromark-util-character "^1.0.0" + micromark-util-normalize-identifier "^1.0.0" + micromark-util-sanitize-uri "^1.0.0" + micromark-util-symbol "^1.0.0" + micromark-util-types "^1.0.0" + uvu "^0.5.0" + +micromark-extension-gfm-strikethrough@^1.0.0: + version "1.0.4" + resolved "https://registry.yarnpkg.com/micromark-extension-gfm-strikethrough/-/micromark-extension-gfm-strikethrough-1.0.4.tgz#162232c284ffbedd8c74e59c1525bda217295e18" + integrity sha512-/vjHU/lalmjZCT5xt7CcHVJGq8sYRm80z24qAKXzaHzem/xsDYb2yLL+NNVbYvmpLx3O7SYPuGL5pzusL9CLIQ== + dependencies: + micromark-util-chunked "^1.0.0" + micromark-util-classify-character "^1.0.0" + micromark-util-resolve-all "^1.0.0" + micromark-util-symbol "^1.0.0" + micromark-util-types "^1.0.0" + uvu "^0.5.0" + +micromark-extension-gfm-table@^1.0.0: + version "1.0.5" + resolved "https://registry.yarnpkg.com/micromark-extension-gfm-table/-/micromark-extension-gfm-table-1.0.5.tgz#7b708b728f8dc4d95d486b9e7a2262f9cddbcbb4" + integrity sha512-xAZ8J1X9W9K3JTJTUL7G6wSKhp2ZYHrFk5qJgY/4B33scJzE2kpfRL6oiw/veJTbt7jiM/1rngLlOKPWr1G+vg== + dependencies: + micromark-factory-space "^1.0.0" + micromark-util-character "^1.0.0" + micromark-util-symbol "^1.0.0" + micromark-util-types "^1.0.0" + uvu "^0.5.0" + +micromark-extension-gfm-tagfilter@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/micromark-extension-gfm-tagfilter/-/micromark-extension-gfm-tagfilter-1.0.1.tgz#fb2e303f7daf616db428bb6a26e18fda14a90a4d" + integrity sha512-Ty6psLAcAjboRa/UKUbbUcwjVAv5plxmpUTy2XC/3nJFL37eHej8jrHrRzkqcpipJliuBH30DTs7+3wqNcQUVA== + dependencies: + micromark-util-types "^1.0.0" + +micromark-extension-gfm-task-list-item@^1.0.0: + version "1.0.3" + resolved "https://registry.yarnpkg.com/micromark-extension-gfm-task-list-item/-/micromark-extension-gfm-task-list-item-1.0.3.tgz#7683641df5d4a09795f353574d7f7f66e47b7fc4" + integrity sha512-PpysK2S1Q/5VXi72IIapbi/jliaiOFzv7THH4amwXeYXLq3l1uo8/2Be0Ac1rEwK20MQEsGH2ltAZLNY2KI/0Q== + dependencies: + micromark-factory-space "^1.0.0" + micromark-util-character "^1.0.0" + micromark-util-symbol "^1.0.0" + micromark-util-types "^1.0.0" + uvu "^0.5.0" + +micromark-extension-gfm@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/micromark-extension-gfm/-/micromark-extension-gfm-2.0.1.tgz#40f3209216127a96297c54c67f5edc7ef2d1a2a2" + integrity sha512-p2sGjajLa0iYiGQdT0oelahRYtMWvLjy8J9LOCxzIQsllMCGLbsLW+Nc+N4vi02jcRJvedVJ68cjelKIO6bpDA== + dependencies: + micromark-extension-gfm-autolink-literal "^1.0.0" + micromark-extension-gfm-footnote "^1.0.0" + micromark-extension-gfm-strikethrough "^1.0.0" + micromark-extension-gfm-table "^1.0.0" + micromark-extension-gfm-tagfilter "^1.0.0" + micromark-extension-gfm-task-list-item "^1.0.0" + micromark-util-combine-extensions "^1.0.0" + micromark-util-types "^1.0.0" + +micromark-factory-destination@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/micromark-factory-destination/-/micromark-factory-destination-1.0.0.tgz#fef1cb59ad4997c496f887b6977aa3034a5a277e" + integrity sha512-eUBA7Rs1/xtTVun9TmV3gjfPz2wEwgK5R5xcbIM5ZYAtvGF6JkyaDsj0agx8urXnO31tEO6Ug83iVH3tdedLnw== + dependencies: + micromark-util-character "^1.0.0" + micromark-util-symbol "^1.0.0" + micromark-util-types "^1.0.0" + +micromark-factory-label@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/micromark-factory-label/-/micromark-factory-label-1.0.2.tgz#6be2551fa8d13542fcbbac478258fb7a20047137" + integrity sha512-CTIwxlOnU7dEshXDQ+dsr2n+yxpP0+fn271pu0bwDIS8uqfFcumXpj5mLn3hSC8iw2MUr6Gx8EcKng1dD7i6hg== + dependencies: + micromark-util-character "^1.0.0" + micromark-util-symbol "^1.0.0" + micromark-util-types "^1.0.0" + uvu "^0.5.0" + +micromark-factory-space@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/micromark-factory-space/-/micromark-factory-space-1.0.0.tgz#cebff49968f2b9616c0fcb239e96685cb9497633" + integrity sha512-qUmqs4kj9a5yBnk3JMLyjtWYN6Mzfcx8uJfi5XAveBniDevmZasdGBba5b4QsvRcAkmvGo5ACmSUmyGiKTLZew== + dependencies: + micromark-util-character "^1.0.0" + micromark-util-types "^1.0.0" + +micromark-factory-title@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/micromark-factory-title/-/micromark-factory-title-1.0.2.tgz#7e09287c3748ff1693930f176e1c4a328382494f" + integrity sha512-zily+Nr4yFqgMGRKLpTVsNl5L4PMu485fGFDOQJQBl2NFpjGte1e86zC0da93wf97jrc4+2G2GQudFMHn3IX+A== + dependencies: + micromark-factory-space "^1.0.0" + micromark-util-character "^1.0.0" + micromark-util-symbol "^1.0.0" + micromark-util-types "^1.0.0" + uvu "^0.5.0" + +micromark-factory-whitespace@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/micromark-factory-whitespace/-/micromark-factory-whitespace-1.0.0.tgz#e991e043ad376c1ba52f4e49858ce0794678621c" + integrity sha512-Qx7uEyahU1lt1RnsECBiuEbfr9INjQTGa6Err+gF3g0Tx4YEviPbqqGKNv/NrBaE7dVHdn1bVZKM/n5I/Bak7A== + dependencies: + micromark-factory-space "^1.0.0" + micromark-util-character "^1.0.0" + micromark-util-symbol "^1.0.0" + micromark-util-types "^1.0.0" + +micromark-util-character@^1.0.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/micromark-util-character/-/micromark-util-character-1.1.0.tgz#d97c54d5742a0d9611a68ca0cd4124331f264d86" + integrity sha512-agJ5B3unGNJ9rJvADMJ5ZiYjBRyDpzKAOk01Kpi1TKhlT1APx3XZk6eN7RtSz1erbWHC2L8T3xLZ81wdtGRZzg== + dependencies: + micromark-util-symbol "^1.0.0" + micromark-util-types "^1.0.0" + +micromark-util-chunked@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/micromark-util-chunked/-/micromark-util-chunked-1.0.0.tgz#5b40d83f3d53b84c4c6bce30ed4257e9a4c79d06" + integrity sha512-5e8xTis5tEZKgesfbQMKRCyzvffRRUX+lK/y+DvsMFdabAicPkkZV6gO+FEWi9RfuKKoxxPwNL+dFF0SMImc1g== + dependencies: + micromark-util-symbol "^1.0.0" + +micromark-util-classify-character@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/micromark-util-classify-character/-/micromark-util-classify-character-1.0.0.tgz#cbd7b447cb79ee6997dd274a46fc4eb806460a20" + integrity sha512-F8oW2KKrQRb3vS5ud5HIqBVkCqQi224Nm55o5wYLzY/9PwHGXC01tr3d7+TqHHz6zrKQ72Okwtvm/xQm6OVNZA== + dependencies: + micromark-util-character "^1.0.0" + micromark-util-symbol "^1.0.0" + micromark-util-types "^1.0.0" + +micromark-util-combine-extensions@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/micromark-util-combine-extensions/-/micromark-util-combine-extensions-1.0.0.tgz#91418e1e74fb893e3628b8d496085639124ff3d5" + integrity sha512-J8H058vFBdo/6+AsjHp2NF7AJ02SZtWaVUjsayNFeAiydTxUwViQPxN0Hf8dp4FmCQi0UUFovFsEyRSUmFH3MA== + dependencies: + micromark-util-chunked "^1.0.0" + micromark-util-types "^1.0.0" + +micromark-util-decode-numeric-character-reference@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/micromark-util-decode-numeric-character-reference/-/micromark-util-decode-numeric-character-reference-1.0.0.tgz#dcc85f13b5bd93ff8d2868c3dba28039d490b946" + integrity sha512-OzO9AI5VUtrTD7KSdagf4MWgHMtET17Ua1fIpXTpuhclCqD8egFWo85GxSGvxgkGS74bEahvtM0WP0HjvV0e4w== + dependencies: + micromark-util-symbol "^1.0.0" + +micromark-util-decode-string@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/micromark-util-decode-string/-/micromark-util-decode-string-1.0.2.tgz#942252ab7a76dec2dbf089cc32505ee2bc3acf02" + integrity sha512-DLT5Ho02qr6QWVNYbRZ3RYOSSWWFuH3tJexd3dgN1odEuPNxCngTCXJum7+ViRAd9BbdxCvMToPOD/IvVhzG6Q== + dependencies: + decode-named-character-reference "^1.0.0" + micromark-util-character "^1.0.0" + micromark-util-decode-numeric-character-reference "^1.0.0" + micromark-util-symbol "^1.0.0" + +micromark-util-encode@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/micromark-util-encode/-/micromark-util-encode-1.0.1.tgz#2c1c22d3800870ad770ece5686ebca5920353383" + integrity sha512-U2s5YdnAYexjKDel31SVMPbfi+eF8y1U4pfiRW/Y8EFVCy/vgxk/2wWTxzcqE71LHtCuCzlBDRU2a5CQ5j+mQA== + +micromark-util-html-tag-name@^1.0.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/micromark-util-html-tag-name/-/micromark-util-html-tag-name-1.1.0.tgz#eb227118befd51f48858e879b7a419fc0df20497" + integrity sha512-BKlClMmYROy9UiV03SwNmckkjn8QHVaWkqoAqzivabvdGcwNGMMMH/5szAnywmsTBUzDsU57/mFi0sp4BQO6dA== + +micromark-util-normalize-identifier@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/micromark-util-normalize-identifier/-/micromark-util-normalize-identifier-1.0.0.tgz#4a3539cb8db954bbec5203952bfe8cedadae7828" + integrity sha512-yg+zrL14bBTFrQ7n35CmByWUTFsgst5JhA4gJYoty4Dqzj4Z4Fr/DHekSS5aLfH9bdlfnSvKAWsAgJhIbogyBg== + dependencies: + micromark-util-symbol "^1.0.0" + +micromark-util-resolve-all@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/micromark-util-resolve-all/-/micromark-util-resolve-all-1.0.0.tgz#a7c363f49a0162e931960c44f3127ab58f031d88" + integrity sha512-CB/AGk98u50k42kvgaMM94wzBqozSzDDaonKU7P7jwQIuH2RU0TeBqGYJz2WY1UdihhjweivStrJ2JdkdEmcfw== + dependencies: + micromark-util-types "^1.0.0" + +micromark-util-sanitize-uri@^1.0.0, micromark-util-sanitize-uri@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/micromark-util-sanitize-uri/-/micromark-util-sanitize-uri-1.1.0.tgz#f12e07a85106b902645e0364feb07cf253a85aee" + integrity sha512-RoxtuSCX6sUNtxhbmsEFQfWzs8VN7cTctmBPvYivo98xb/kDEoTCtJQX5wyzIYEmk/lvNFTat4hL8oW0KndFpg== + dependencies: + micromark-util-character "^1.0.0" + micromark-util-encode "^1.0.0" + micromark-util-symbol "^1.0.0" + +micromark-util-subtokenize@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/micromark-util-subtokenize/-/micromark-util-subtokenize-1.0.2.tgz#ff6f1af6ac836f8bfdbf9b02f40431760ad89105" + integrity sha512-d90uqCnXp/cy4G881Ub4psE57Sf8YD0pim9QdjCRNjfas2M1u6Lbt+XZK9gnHL2XFhnozZiEdCa9CNfXSfQ6xA== + dependencies: + micromark-util-chunked "^1.0.0" + micromark-util-symbol "^1.0.0" + micromark-util-types "^1.0.0" + uvu "^0.5.0" + +micromark-util-symbol@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/micromark-util-symbol/-/micromark-util-symbol-1.0.1.tgz#b90344db62042ce454f351cf0bebcc0a6da4920e" + integrity sha512-oKDEMK2u5qqAptasDAwWDXq0tG9AssVwAx3E9bBF3t/shRIGsWIRG+cGafs2p/SnDSOecnt6hZPCE2o6lHfFmQ== + +micromark-util-types@^1.0.0, micromark-util-types@^1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/micromark-util-types/-/micromark-util-types-1.0.2.tgz#f4220fdb319205812f99c40f8c87a9be83eded20" + integrity sha512-DCfg/T8fcrhrRKTPjRrw/5LLvdGV7BHySf/1LOZx7TzWZdYRjogNtyNq885z3nNallwr3QUKARjqvHqX1/7t+w== + +micromark@^3.0.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/micromark/-/micromark-3.1.0.tgz#eeba0fe0ac1c9aaef675157b52c166f125e89f62" + integrity sha512-6Mj0yHLdUZjHnOPgr5xfWIMqMWS12zDN6iws9SLuSz76W8jTtAv24MN4/CL7gJrl5vtxGInkkqDv/JIoRsQOvA== + dependencies: + "@types/debug" "^4.0.0" + debug "^4.0.0" + decode-named-character-reference "^1.0.0" + micromark-core-commonmark "^1.0.1" + micromark-factory-space "^1.0.0" + micromark-util-character "^1.0.0" + micromark-util-chunked "^1.0.0" + micromark-util-combine-extensions "^1.0.0" + micromark-util-decode-numeric-character-reference "^1.0.0" + micromark-util-encode "^1.0.0" + micromark-util-normalize-identifier "^1.0.0" + micromark-util-resolve-all "^1.0.0" + micromark-util-sanitize-uri "^1.0.0" + micromark-util-subtokenize "^1.0.0" + micromark-util-symbol "^1.0.0" + micromark-util-types "^1.0.1" + uvu "^0.5.0" + micromatch@^2.1.5: version "2.3.11" resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-2.3.11.tgz#86677c97d1720b363431d04d0d15293bd38c1565" @@ -18609,6 +19110,11 @@ move-concurrently@^1.0.1, move-concurrently@~1.0.1: rimraf "^2.5.4" run-queue "^1.0.3" +mri@^1.1.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/mri/-/mri-1.2.0.tgz#6721480fec2a11a4889861115a48b6cbe7cc8f0b" + integrity sha512-tzzskb3bG8LvYGFF/mDTpq3jpI6Q9wc3LEmBaghu+DdCssd1FakN7Bc0hVNmEyGq1bq3RgfkCb3cmQLpNPOroA== + mrmime@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/mrmime/-/mrmime-1.0.1.tgz#5f90c825fad4bdd41dc914eff5d1a8cfdaf24f27" @@ -20536,7 +21042,7 @@ path-dirname@^1.0.0: path-exists@^2.0.0: version "2.1.0" resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-2.1.0.tgz#0feb6c64f0fc518d9a754dd5efb62c7022761f4b" - integrity sha1-D+tsZPD8UY2adU3V77YscCJ2H0s= + integrity sha512-yTltuKuhtNeFJKa1PiRzfLAU5182q1y4Eb4XCJ3PBqyzEDkAZRzBrKKBct682ls9reBVHf9udYLN5Nd+K1B9BQ== dependencies: pinkie-promise "^2.0.0" @@ -20682,7 +21188,7 @@ pify@^2.0.0, pify@^2.3.0: pify@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/pify/-/pify-3.0.0.tgz#e5a4acd2c101fdf3d9a4d07f0dbc4db49dd28176" - integrity sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY= + integrity sha512-C3FsVNH1udSEX48gGX1xfvwTWfsYWj5U+8/uK15BGzIGrKoUpghX8hWZwa/OFnakBiiVNmBvemTJR5mcy7iPcg== pify@^4.0.1: version "4.0.1" @@ -21297,6 +21803,15 @@ prop-types-extra@^1.1.0: react-is "^16.3.2" warning "^4.0.0" +prop-types@^15.0.0, prop-types@^15.8.1: + version "15.8.1" + resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.8.1.tgz#67d87bf1a694f48435cf332c24af10214a3140b5" + integrity sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg== + dependencies: + loose-envify "^1.4.0" + object-assign "^4.1.1" + react-is "^16.13.1" + prop-types@^15.5.0, prop-types@^15.6.2, prop-types@^15.7.2: version "15.7.2" resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.7.2.tgz#52c41e75b8c87e72b9d9360e0206b99dcbffa6c5" @@ -21306,15 +21821,6 @@ prop-types@^15.5.0, prop-types@^15.6.2, prop-types@^15.7.2: object-assign "^4.1.1" react-is "^16.8.1" -prop-types@^15.8.1: - version "15.8.1" - resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.8.1.tgz#67d87bf1a694f48435cf332c24af10214a3140b5" - integrity sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg== - dependencies: - loose-envify "^1.4.0" - object-assign "^4.1.1" - react-is "^16.13.1" - proper-lockfile@^4.1.1: version "4.1.2" resolved "https://registry.yarnpkg.com/proper-lockfile/-/proper-lockfile-4.1.2.tgz#c8b9de2af6b2f1601067f98e01ac66baa223141f" @@ -21324,6 +21830,11 @@ proper-lockfile@^4.1.1: retry "^0.12.0" signal-exit "^3.0.2" +property-information@^6.0.0: + version "6.2.0" + resolved "https://registry.yarnpkg.com/property-information/-/property-information-6.2.0.tgz#b74f522c31c097b5149e3c3cb8d7f3defd986a1d" + integrity sha512-kma4U7AFCTwpqq5twzC1YVIDXSqg6qQK6JN0smOw8fgRy1OkMi0CYSzFmsy6dnqSenamAtj0CyXMUJ1Mf6oROg== + proto-list@~1.2.1: version "1.2.4" resolved "https://registry.yarnpkg.com/proto-list/-/proto-list-1.2.4.tgz#212d5bfe1318306a420f6402b8e26ff39647a849" @@ -21773,6 +22284,27 @@ react-lifecycles-compat@^3.0.4: resolved "https://registry.yarnpkg.com/react-lifecycles-compat/-/react-lifecycles-compat-3.0.4.tgz#4f1a273afdfc8f3488a8c516bfda78f872352362" integrity sha512-fBASbA6LnOU9dOU2eW7aQ8xmYBSXUIWr+UmF9b1efZBazGNO+rcXT/icdKnYm2pTwcRylVUYwW7H1PHfLekVzA== +react-markdown@^8.0.5: + version "8.0.5" + resolved "https://registry.yarnpkg.com/react-markdown/-/react-markdown-8.0.5.tgz#c9a70a33ca9aeeafb769c6582e7e38843b9d70ad" + integrity sha512-jGJolWWmOWAvzf+xMdB9zwStViODyyFQhNB/bwCerbBKmrTmgmA599CGiOlP58OId1IMoIRsA8UdI1Lod4zb5A== + dependencies: + "@types/hast" "^2.0.0" + "@types/prop-types" "^15.0.0" + "@types/unist" "^2.0.0" + comma-separated-tokens "^2.0.0" + hast-util-whitespace "^2.0.0" + prop-types "^15.0.0" + property-information "^6.0.0" + react-is "^18.0.0" + remark-parse "^10.0.0" + remark-rehype "^10.0.0" + space-separated-tokens "^2.0.0" + style-to-object "^0.4.0" + unified "^10.0.0" + unist-util-visit "^4.0.0" + vfile "^5.0.0" + react-multi-carousel@^2.8.2: version "2.8.2" resolved "https://registry.yarnpkg.com/react-multi-carousel/-/react-multi-carousel-2.8.2.tgz#4bbd7a9656d8e49e081745331593e5500eefdbe4" @@ -22015,7 +22547,7 @@ read-pkg@^1.0.0: read-pkg@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/read-pkg/-/read-pkg-3.0.0.tgz#9cbc686978fee65d16c00e2b19c237fcf6e38389" - integrity sha1-nLxoaXj+5l0WwA4rGcI3/Pbjg4k= + integrity sha512-BLq/cCO9two+lBgiTYNqD6GdtK8s4NpaWrl6/rCO9w0TUS8oJl7cmToOZfRYllKTISY6nt1U7jQ53brmKqY6BA== dependencies: load-json-file "^4.0.0" normalize-package-data "^2.3.2" @@ -22381,6 +22913,35 @@ release-zalgo@^1.0.0: dependencies: es6-error "^4.0.1" +remark-gfm@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/remark-gfm/-/remark-gfm-3.0.1.tgz#0b180f095e3036545e9dddac0e8df3fa5cfee54f" + integrity sha512-lEFDoi2PICJyNrACFOfDD3JlLkuSbOa5Wd8EPt06HUdptv8Gn0bxYTdbU/XXQ3swAPkEaGxxPN9cbnMHvVu1Ig== + dependencies: + "@types/mdast" "^3.0.0" + mdast-util-gfm "^2.0.0" + micromark-extension-gfm "^2.0.0" + unified "^10.0.0" + +remark-parse@^10.0.0: + version "10.0.1" + resolved "https://registry.yarnpkg.com/remark-parse/-/remark-parse-10.0.1.tgz#6f60ae53edbf0cf38ea223fe643db64d112e0775" + integrity sha512-1fUyHr2jLsVOkhbvPRBJ5zTKZZyD6yZzYaWCS6BPBdQ8vEMBCH+9zNCDA6tET/zHCi/jLqjCWtlJZUPk+DbnFw== + dependencies: + "@types/mdast" "^3.0.0" + mdast-util-from-markdown "^1.0.0" + unified "^10.0.0" + +remark-rehype@^10.0.0: + version "10.1.0" + resolved "https://registry.yarnpkg.com/remark-rehype/-/remark-rehype-10.1.0.tgz#32dc99d2034c27ecaf2e0150d22a6dcccd9a6279" + integrity sha512-EFmR5zppdBp0WQeDVZ/b66CWJipB2q2VLNFMabzDSGR66Z2fQii83G5gTBbgGEnEEA0QRussvrFHxk1HWGJskw== + dependencies: + "@types/hast" "^2.0.0" + "@types/mdast" "^3.0.0" + mdast-util-to-hast "^12.1.0" + unified "^10.0.0" + remove-bom-buffer@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/remove-bom-buffer/-/remove-bom-buffer-3.0.0.tgz#c2bf1e377520d324f623892e33c10cac2c252b53" @@ -22856,6 +23417,13 @@ rxjs@^6.4.0, rxjs@^6.5.4: dependencies: tslib "^1.9.0" +sade@^1.7.3: + version "1.8.1" + resolved "https://registry.yarnpkg.com/sade/-/sade-1.8.1.tgz#0a78e81d658d394887be57d2a409bf703a3b2701" + integrity sha512-xal3CZX1Xlo/k4ApwCFrHVACi9fBqJ7V+mwhBsuf/1IOKbBy098Fex+Wa/5QMubw09pSZ/u8EY8PWgevJsXp1A== + dependencies: + mri "^1.1.0" + safe-buffer@*, safe-buffer@5.2.1, safe-buffer@>=5.1.0, safe-buffer@^5.1.0, safe-buffer@^5.1.1, safe-buffer@^5.1.2, safe-buffer@^5.2.0, safe-buffer@^5.2.1, safe-buffer@~5.2.0: version "5.2.1" resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.1.tgz#1eaf9fa9bdb1fdd4ec75f58f9cdb4e6b7827eec6" @@ -23668,6 +24236,11 @@ sourcemap-codec@^1.4.1, sourcemap-codec@^1.4.8: resolved "https://registry.yarnpkg.com/sourcemap-codec/-/sourcemap-codec-1.4.8.tgz#ea804bd94857402e6992d05a38ef1ae35a9ab4c4" integrity sha512-9NykojV5Uih4lgo5So5dtw+f0JgJX30KCNI8gwhz2J9A15wD0Ml6tjHKwf6fTSa6fAdVBdZeNOs9eJ71qCk8vA== +space-separated-tokens@^2.0.0: + version "2.0.2" + resolved "https://registry.yarnpkg.com/space-separated-tokens/-/space-separated-tokens-2.0.2.tgz#1ecd9d2350a3844572c3f4a312bceb018348859f" + integrity sha512-PEGlAwrG8yXGXRjW32fGbg66JAlOAwbObuqVoJpv/mRgoWDQfgH1wDPvtzWyUSNAXBGSk8h755YDbbcEy3SH2Q== + sparkles@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/sparkles/-/sparkles-1.0.1.tgz#008db65edce6c50eec0c5e228e1945061dd0437c" @@ -24225,6 +24798,13 @@ style-to-object@0.3.0: dependencies: inline-style-parser "0.1.1" +style-to-object@^0.4.0: + version "0.4.1" + resolved "https://registry.yarnpkg.com/style-to-object/-/style-to-object-0.4.1.tgz#53cf856f7cf7f172d72939d9679556469ba5de37" + integrity sha512-HFpbb5gr2ypci7Qw+IOhnP2zOU7e77b+rzM+wTzXzfi1PrtBCX0E7Pk4wL4iTLnhzZ+JgEGAhX81ebTg/aYjQw== + dependencies: + inline-style-parser "0.1.1" + stylehacks@^5.1.0: version "5.1.0" resolved "https://registry.yarnpkg.com/stylehacks/-/stylehacks-5.1.0.tgz#a40066490ca0caca04e96c6b02153ddc39913520" @@ -24843,7 +25423,7 @@ tough-cookie@~2.5.0: tr46@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/tr46/-/tr46-1.0.1.tgz#a8b13fd6bfd2489519674ccde55ba3693b706d09" - integrity sha1-qLE/1r/SSJUZZ0zN5VujaTtwbQk= + integrity sha512-dTpowEjclQ7Kgx5SdBkqRzVhERQXov8/l9Ft9dVM9fmg0W0KQSVaXX9T4i6twCPNtYiZM53lpSSUAwJbFPOHxA== dependencies: punycode "^2.1.0" @@ -24870,6 +25450,11 @@ tree-kill@1.2.2, tree-kill@^1.2.2, tree-kill@~1.2.0: resolved "https://registry.yarnpkg.com/tree-kill/-/tree-kill-1.2.2.tgz#4ca09a9092c88b73a7cdc5e8a01b507b0790a0cc" integrity sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A== +trim-lines@^3.0.0: + version "3.0.1" + resolved "https://registry.yarnpkg.com/trim-lines/-/trim-lines-3.0.1.tgz#d802e332a07df861c48802c04321017b1bd87338" + integrity sha512-kRj8B+YHZCc9kQYdWfJB2/oUl9rA99qbowYYBtr4ui4mZyAQ2JpvVBd/6U2YloATfqBhBTSMhTpgBHtU0Mf3Rg== + trim-newlines@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/trim-newlines/-/trim-newlines-1.0.0.tgz#5887966bb582a4503a41eb524f7d35011815a613" @@ -24900,6 +25485,11 @@ triple-beam@^1.2.0, triple-beam@^1.3.0: resolved "https://registry.yarnpkg.com/triple-beam/-/triple-beam-1.3.0.tgz#a595214c7298db8339eeeee083e4d10bd8cb8dd9" integrity sha512-XrHUvV5HpdLmIj4uVMxHggLbFSZYIn7HEWsqePZcI50pco+MPqJ50wMGY794X7AOOhxOBAjbkqfAbEe/QMp2Lw== +trough@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/trough/-/trough-2.1.0.tgz#0f7b511a4fde65a46f18477ab38849b22c554876" + integrity sha512-AqTiAOLcj85xS7vQ8QkAV41hPDIJ71XJB4RCUrzo/1GM2CQwhkJGaf9Hgr7BOugMRpgGUrqRg/DrBDl4H40+8g== + truncate-utf8-bytes@^1.0.0: version "1.0.2" resolved "https://registry.yarnpkg.com/truncate-utf8-bytes/-/truncate-utf8-bytes-1.0.2.tgz#405923909592d56f78a5818434b0b78489ca5f2b" @@ -25328,6 +25918,19 @@ unicode-property-aliases-ecmascript@^2.0.0: resolved "https://registry.yarnpkg.com/unicode-property-aliases-ecmascript/-/unicode-property-aliases-ecmascript-2.0.0.tgz#0a36cb9a585c4f6abd51ad1deddb285c165297c8" integrity sha512-5Zfuy9q/DFr4tfO7ZPeVXb1aPoeQSdeFMLpYuFebehDAhbuevLs5yxSZmIFN1tP5F9Wl4IpJrYojg85/zgyZHQ== +unified@^10.0.0: + version "10.1.2" + resolved "https://registry.yarnpkg.com/unified/-/unified-10.1.2.tgz#b1d64e55dafe1f0b98bb6c719881103ecf6c86df" + integrity sha512-pUSWAi/RAnVy1Pif2kAoeWNBa3JVrx0MId2LASj8G+7AiHWoKZNTomq6LG326T68U7/e263X6fTdcXIy7XnF7Q== + dependencies: + "@types/unist" "^2.0.0" + bail "^2.0.0" + extend "^3.0.0" + is-buffer "^2.0.0" + is-plain-obj "^4.0.0" + trough "^2.0.0" + vfile "^5.0.0" + union-value@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/union-value/-/union-value-1.0.1.tgz#0b6fe7b835aecda61c6ea4d4f02c14221e109847" @@ -25381,6 +25984,49 @@ unique-string@^1.0.0: dependencies: crypto-random-string "^1.0.0" +unist-util-generated@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/unist-util-generated/-/unist-util-generated-2.0.1.tgz#e37c50af35d3ed185ac6ceacb6ca0afb28a85cae" + integrity sha512-qF72kLmPxAw0oN2fwpWIqbXAVyEqUzDHMsbtPvOudIlUzXYFIeQIuxXQCRCFh22B7cixvU0MG7m3MW8FTq/S+A== + +unist-util-is@^5.0.0: + version "5.2.1" + resolved "https://registry.yarnpkg.com/unist-util-is/-/unist-util-is-5.2.1.tgz#b74960e145c18dcb6226bc57933597f5486deae9" + integrity sha512-u9njyyfEh43npf1M+yGKDGVPbY/JWEemg5nH05ncKPfi+kBbKBJoTdsogMu33uhytuLlv9y0O7GH7fEdwLdLQw== + dependencies: + "@types/unist" "^2.0.0" + +unist-util-position@^4.0.0: + version "4.0.4" + resolved "https://registry.yarnpkg.com/unist-util-position/-/unist-util-position-4.0.4.tgz#93f6d8c7d6b373d9b825844645877c127455f037" + integrity sha512-kUBE91efOWfIVBo8xzh/uZQ7p9ffYRtUbMRZBNFYwf0RK8koUMx6dGUfwylLOKmaT2cs4wSW96QoYUSXAyEtpg== + dependencies: + "@types/unist" "^2.0.0" + +unist-util-stringify-position@^3.0.0: + version "3.0.3" + resolved "https://registry.yarnpkg.com/unist-util-stringify-position/-/unist-util-stringify-position-3.0.3.tgz#03ad3348210c2d930772d64b489580c13a7db39d" + integrity sha512-k5GzIBZ/QatR8N5X2y+drfpWG8IDBzdnVj6OInRNWm1oXrzydiaAT2OQiA8DPRRZyAKb9b6I2a6PxYklZD0gKg== + dependencies: + "@types/unist" "^2.0.0" + +unist-util-visit-parents@^5.0.0, unist-util-visit-parents@^5.1.1: + version "5.1.3" + resolved "https://registry.yarnpkg.com/unist-util-visit-parents/-/unist-util-visit-parents-5.1.3.tgz#b4520811b0ca34285633785045df7a8d6776cfeb" + integrity sha512-x6+y8g7wWMyQhL1iZfhIPhDAs7Xwbn9nRosDXl7qoPTSCy0yNxnKc+hWokFifWQIDGi154rdUqKvbCa4+1kLhg== + dependencies: + "@types/unist" "^2.0.0" + unist-util-is "^5.0.0" + +unist-util-visit@^4.0.0: + version "4.1.2" + resolved "https://registry.yarnpkg.com/unist-util-visit/-/unist-util-visit-4.1.2.tgz#125a42d1eb876283715a3cb5cceaa531828c72e2" + integrity sha512-MSd8OUGISqHdVvfY9TPhyK2VdUrPgxkUtWSuMHF6XAAFuL4LokseigBnZtPnJMu+FbynTkFNnFlyjxpVKujMRg== + dependencies: + "@types/unist" "^2.0.0" + unist-util-is "^5.0.0" + unist-util-visit-parents "^5.1.1" + universal-user-agent@^4.0.0: version "4.0.1" resolved "https://registry.yarnpkg.com/universal-user-agent/-/universal-user-agent-4.0.1.tgz#fd8d6cb773a679a709e967ef8288a31fcc03e557" @@ -25658,6 +26304,16 @@ uuid@^9.0.0: resolved "https://registry.yarnpkg.com/uuid/-/uuid-9.0.0.tgz#592f550650024a38ceb0c562f2f6aa435761efb5" integrity sha512-MXcSTerfPa4uqyzStbRoTgt5XIe3x5+42+q1sDuy3R5MDk66URdLMOZe5aPX/SQd+kuYAh0FdP/pO28IkQyTeg== +uvu@^0.5.0: + version "0.5.6" + resolved "https://registry.yarnpkg.com/uvu/-/uvu-0.5.6.tgz#2754ca20bcb0bb59b64e9985e84d2e81058502df" + integrity sha512-+g8ENReyr8YsOc6fv/NVJs2vFdHBnBNdfE49rshrTzDWOlUx4Gq7KOS2GD8eqhy2j+Ejq29+SbKH8yjkAqXqoA== + dependencies: + dequal "^2.0.0" + diff "^5.0.0" + kleur "^4.0.3" + sade "^1.7.3" + v8-compile-cache-lib@^3.0.1: version "3.0.1" resolved "https://registry.yarnpkg.com/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz#6336e8d71965cb3d35a1bbb7868445a7c05264bf" @@ -25726,6 +26382,24 @@ verror@1.3.6: dependencies: extsprintf "1.0.2" +vfile-message@^3.0.0: + version "3.1.4" + resolved "https://registry.yarnpkg.com/vfile-message/-/vfile-message-3.1.4.tgz#15a50816ae7d7c2d1fa87090a7f9f96612b59dea" + integrity sha512-fa0Z6P8HUrQN4BZaX05SIVXic+7kE3b05PWAtPuYP9QLHsLKYR7/AlLW3NtOrpXRLeawpDLMsVkmk5DG0NXgWw== + dependencies: + "@types/unist" "^2.0.0" + unist-util-stringify-position "^3.0.0" + +vfile@^5.0.0: + version "5.3.7" + resolved "https://registry.yarnpkg.com/vfile/-/vfile-5.3.7.tgz#de0677e6683e3380fafc46544cfe603118826ab7" + integrity sha512-r7qlzkgErKjobAmyNIkkSpizsFPYiUPuJb5pNW1RB4JcYVZhs4lIbVqk8XPk033CV/1z8ss5pkax8SuhGpcG8g== + dependencies: + "@types/unist" "^2.0.0" + is-buffer "^2.0.0" + unist-util-stringify-position "^3.0.0" + vfile-message "^3.0.0" + vinyl-fs@^3.0.0: version "3.0.3" resolved "https://registry.yarnpkg.com/vinyl-fs/-/vinyl-fs-3.0.3.tgz#c85849405f67428feabbbd5c5dbdd64f47d31bc7" @@ -26453,7 +27127,7 @@ workerpool@6.2.1: wrap-ansi@^2.0.0: version "2.1.0" resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-2.1.0.tgz#d8fc3d284dd05794fe84973caecdd1cf824fdd85" - integrity sha1-2Pw9KE3QV5T+hJc8rs3Rz4JP3YU= + integrity sha512-vAaEaDM946gbNpH5pLVNR+vX2ht6n0Bt3GXwVB1AuAqZosOvHNF3P7wDnh8KLkSqgUh0uh77le7Owgoz+Z9XBw== dependencies: string-width "^1.0.1" strip-ansi "^3.0.1" @@ -26895,3 +27569,8 @@ yocto-queue@^0.1.0: version "0.1.0" resolved "https://registry.yarnpkg.com/yocto-queue/-/yocto-queue-0.1.0.tgz#0294eb3dee05028d31ee1a5fa2c556a6aaf10a1b" integrity sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q== + +zwitch@^2.0.0: + version "2.0.4" + resolved "https://registry.yarnpkg.com/zwitch/-/zwitch-2.0.4.tgz#c827d4b0acb76fc3e685a4c6ec2902d51070e9d7" + integrity sha512-bXE4cR/kVZhKZX/RjPEflHaKVhUVl85noU3v6b8apfQEc1x4A+zBxjZ4lN8LqGd6WZ3dl98pY4o717VFmoPp+A==