diff --git a/.env b/.env new file mode 100644 index 000000000..b20e07093 --- /dev/null +++ b/.env @@ -0,0 +1,2 @@ +VITE_FEEDBACK_URL=https://164.92.190.45/feedback/form +VITE_COMPAT_MATRIX_URL=https://docs-compat.iroha2.tachi.soramitsu.co.jp/compat-matrix diff --git a/.eslintignore b/.eslintignore new file mode 100644 index 000000000..a7fd5fc17 --- /dev/null +++ b/.eslintignore @@ -0,0 +1,3 @@ +.vitepress/dist +.vitepress/cache +src/snippets diff --git a/.eslintrc.js b/.eslintrc.js index 50d0d3aab..c1e88f677 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -1,15 +1,29 @@ +// eslint-disable-next-line no-undef module.exports = { - extends: ['plugin:vue'], - // env: { - // es2021: true, - // }, - rules: { - 'spaced-comment': [ - 'error', - 'always', - { - markers: ['/'], - }, - ], + root: true, + extends: ['plugin:vue/vue3-recommended', 'eslint:recommended', 'plugin:@typescript-eslint/recommended'], + parser: 'vue-eslint-parser', + parserOptions: { + parser: '@typescript-eslint/parser', + sourceType: 'module', + }, + rules: { + 'vue/html-indent': ['error', 2], + 'spaced-comment': [ + 'error', + 'always', + { + markers: ['/'], + }, + ], + }, + overrides: [ + { + files: ['.vitepress/theme/components/MermaidRender.vue'], + rules: { + // FIXME: find a way to disable this it for the particular line + 'vue/no-v-html': 'off', + }, }, + ], } diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS new file mode 100644 index 000000000..d93597c6a --- /dev/null +++ b/.github/CODEOWNERS @@ -0,0 +1,14 @@ +* @outoftardis + +# doc sources +/src/ @outoftardis @WRRicht3r @nxsaken +*.md @outoftardis @WRRicht3r @nxsaken +src/guide/javascript.md @0x009922 @outoftardis @WRRicht3r @nxsaken + +# configurations +/.vitepress/ @0x009922 +*.js @0x009922 +*.ts @0x009922 +*.json @0x009922 +*.yaml @0x009922 +*.vue @0x009922 diff --git a/.github/workflows/gh-pages-deploy.yaml b/.github/workflows/gh-pages-deploy.yaml new file mode 100644 index 000000000..1d9e7fff1 --- /dev/null +++ b/.github/workflows/gh-pages-deploy.yaml @@ -0,0 +1,68 @@ +name: Deploy at GitHub Pages + +on: + push: + branches: [main] + +jobs: + build: + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v2 + + - uses: actions/setup-node@v3 + with: + node-version: 18 + + # --- Install with caching + # https://github.com/pnpm/action-setup#use-cache-to-reduce-installation-time + + - name: Enable Corepack + run: corepack enable + + - name: Get pnpm store directory + id: pnpm-cache + run: | + echo "::set-output name=pnpm_cache_dir::$(pnpm store path)" + + - uses: actions/cache@v3 + name: Setup pnpm cache + with: + path: | + ${{ steps.pnpm-cache.outputs.pnpm_cache_dir }} + /home/runner/.cache/Cypress + key: ${{ runner.os }}-pnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }} + restore-keys: | + ${{ runner.os }}-pnpm-store- + + - name: Install packages + run: pnpm install + + - name: Check formatting + run: pnpm format:check + + - name: Run linter + run: pnpm lint + + - name: Run tests + run: pnpm test + + - name: Build VitePress + run: | + pnpm build + pnpm cli validate-links .vitepress/dist --public-path $PUBLIC_PATH + env: + PUBLIC_PATH: /iroha-2-docs/ + # chalk has a color detection bug + FORCE_COLOR: 2 + + - name: Push static content into master:gh-pages + working-directory: .vitepress/dist + run: | + git config --global user.email "${GITHUB_ACTOR}@https://users.noreply.github.com/" + git config --global user.name "${GITHUB_ACTOR}" + git init + git add --all + git commit -m "Auto update pages on $(date +'%Y-%m-%d %H:%M:%S')" + git push -f -q https://git:${{ secrets.github_token }}@github.com/${{ github.repository }} master:gh-pages diff --git a/.github/workflows/pull-request-ci.yaml b/.github/workflows/pull-request-ci.yaml new file mode 100644 index 000000000..dcd411472 --- /dev/null +++ b/.github/workflows/pull-request-ci.yaml @@ -0,0 +1,58 @@ +name: Pull Request CI +on: + pull_request: + branches: [main] +jobs: + check: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + + - uses: actions/setup-node@v3 + with: + node-version: 18 + + # --- Install with caching + # https://github.com/pnpm/action-setup#use-cache-to-reduce-installation-time + + - name: Enable Corepack + run: corepack enable + + - name: Get pnpm store directory + id: pnpm-cache + run: | + echo "pnpm_cache_dir=$(pnpm store path)" >> $GITHUB_OUTPUT + + - uses: actions/cache@v3 + name: Setup pnpm cache + with: + path: | + ${{ steps.pnpm-cache.outputs.pnpm_cache_dir }} + /home/runner/.cache/Cypress + key: ${{ runner.os }}-pnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }} + restore-keys: | + ${{ runner.os }}-pnpm-store- + + - name: Install packages + run: pnpm install + + - name: Type check + run: pnpm typecheck + + - name: Lint + run: pnpm lint + + - name: Format + run: pnpm format:check + + - name: Run tests + run: pnpm test + + - name: Build + run: pnpm build + + - name: Validate links + run: pnpm cli validate-links .vitepress/dist + env: + # chalk has a color detection bug + FORCE_COLOR: 2 diff --git a/.gitignore b/.gitignore index f06235c46..989426f81 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,9 @@ +.DS_Store node_modules dist +/src/flymd.md +/src/flymd.html +/src/*.temp +/src/snippets +.vitepress/cache +.idea diff --git a/.npmrc b/.npmrc new file mode 100644 index 000000000..a65759dba --- /dev/null +++ b/.npmrc @@ -0,0 +1 @@ +@iroha2:registry=https://nexus.iroha.tech/repository/npm-group/ diff --git a/.prettierignore b/.prettierignore new file mode 100644 index 000000000..f2d21b03a --- /dev/null +++ b/.prettierignore @@ -0,0 +1,4 @@ +.vitepress/dist +.vitepress/cache +/src/snippets +/src/example_code diff --git a/.prettierrc.js b/.prettierrc.js index e084c13df..2053034c0 100644 --- a/.prettierrc.js +++ b/.prettierrc.js @@ -1,39 +1,32 @@ +// eslint-disable-next-line no-undef module.exports = { - // max 120 characters per line - printWidth: 120, - // use 24spaces for indentation - tabWidth: 4, - // use spaces instead of indentations - useTabs: false, - // semicolon at the end of the line - semi: false, - // use single quotes - singleQuote: true, - // object's key is quoted only when necessary - quoteProps: 'as-needed', - // use double quotes instead of single quotes in jsx - jsxSingleQuote: false, - // no comma at the end - trailingComma: 'all', - // spaces are required at the beginning and end of the braces - bracketSpacing: true, - // brackets are required for arrow function parameter, even when there is only one parameter - arrowParens: 'always', - // format the entire contents of the file - rangeStart: 0, - rangeEnd: Infinity, - // no need to write the beginning @prettier of the file - requirePragma: false, - // No need to automatically insert @prettier at the beginning of the file - insertPragma: false, - // use default break criteria - proseWrap: 'preserve', - // decide whether to break the html according to the display style - htmlWhitespaceSensitivity: 'css', - // vue files script and style tags indentation - vueIndentScriptAndStyle: false, - // lf for newline - endOfLine: 'lf', - // formats quoted code embedded - embeddedLanguageFormatting: 'auto', + printWidth: 120, + tabWidth: 2, + useTabs: false, + semi: false, + singleQuote: true, + quoteProps: 'as-needed', + jsxSingleQuote: false, + trailingComma: 'all', + bracketSpacing: true, + arrowParens: 'always', + rangeStart: 0, + rangeEnd: Infinity, + requirePragma: false, + insertPragma: false, + proseWrap: 'preserve', + htmlWhitespaceSensitivity: 'css', + vueIndentScriptAndStyle: false, + endOfLine: 'lf', + embeddedLanguageFormatting: 'auto', + + overrides: [ + { + files: ['./src/**/*.md'], + options: { + printWidth: 75, + proseWrap: 'always', + }, + }, + ], } diff --git a/.vitepress/config.mts b/.vitepress/config.mts new file mode 100644 index 000000000..a19463ad6 --- /dev/null +++ b/.vitepress/config.mts @@ -0,0 +1,482 @@ +/// + +import { defineConfig, DefaultTheme } from 'vitepress' +import footnote from 'markdown-it-footnote' +import { resolve } from 'path' +import ViteSvgLoader from 'vite-svg-loader' +import ViteUnoCSS from 'unocss/vite' +import { mermaid } from './md-mermaid' +import { katex } from '@mdit/plugin-katex' + +function nav(): DefaultTheme.NavItem[] { + return [ + { + text: 'Get Started', + link: '/get-started/', + activeMatch: '/get-started/', + }, + { + text: 'Build on Iroha', + link: '/guide/tutorials/', + activeMatch: '/guide/', + }, + { + text: 'Iroha Explained', + link: '/blockchain/iroha-explained', + activeMatch: '/blockchain/', + }, + { + text: 'Reference', + link: '/reference/torii-endpoints', + activeMatch: '/reference/', + }, + { + text: 'Help', + link: '/help/', + activeMatch: '/help/', + }, + ] +} + +function sidebarStart(): DefaultTheme.SidebarItem[] { + return [ + { + text: 'Get Started', + link: '/get-started/', + items: [ + { + text: 'Install Iroha', + link: '/get-started/install-iroha-2', + }, + { + text: 'Launch Iroha', + link: '/get-started/launch-iroha-2', + }, + { + text: 'Operate Iroha via CLI', + link: '/get-started/operate-iroha-2-via-cli', + }, + { + text: 'Iroha 2 vs. Iroha 1', + link: '/get-started/iroha-2', + }, + ], + }, + ] +} + +function sidebarGuide(): DefaultTheme.SidebarItem[] { + return [ + { + text: 'SDK Tutorials', + link: '/guide/tutorials/', + collapsed: false, + items: [ + /* a common lang-agnostic section will go here */ + { + text: 'Rust', + link: '/guide/tutorials/rust', + }, + { + text: 'Python 3', + link: '/guide/tutorials/python', + }, + { + text: 'Kotlin/Java', + link: '/guide/tutorials/kotlin-java', + }, + { + text: 'JavaScript', + link: '/guide/tutorials/javascript', + }, + ], + }, + { + text: 'Configuration and Management', + collapsed: false, + items: [ + { + text: 'Configure Iroha', + collapsed: true, + items: [ + { + text: 'Configuration Types', + link: '/guide/configure/configuration-types', + }, + { + text: 'Samples', + link: '/guide/configure/sample-configuration', + }, + { + text: 'Peer Configuration', + link: '/guide/configure/peer-configuration', + }, + { + text: 'Client Configuration', + link: '/guide/configure/client-configuration', + }, + { + text: 'Genesis Block', + link: '/guide/configure/genesis', + }, + { + text: 'Metadata and Store assets', + link: '/guide/configure/metadata-and-store-assets', + }, + ], + }, + { + text: 'Keys for Network Deployment', + link: '/guide/configure/keys-for-network-deployment.md', + }, + { + text: 'Peer Management', + link: '/guide/configure/peer-management', + }, + { + text: 'Public and Private Blockchains', + link: '/guide/configure/modes', + }, + ], + }, + { + text: 'Security', + link: '/guide/security/', + collapsed: false, + items: [ + { + text: 'Security Principles', + link: '/guide/security/security-principles.md', + }, + { + text: 'Operational Security', + link: '/guide/security/operational-security.md', + }, + { + text: 'Password Security', + link: '/guide/security/password-security.md', + }, + { + text: 'Public Key Cryptography', + collapsed: true, + link: '/guide/security/public-key-cryptography.md', + items: [ + { + text: 'Generating Cryptographic Keys', + link: '/guide/security/generating-cryptographic-keys.md', + }, + { + text: 'Storing Cryptographic Keys', + link: '/guide/security/storing-cryptographic-keys.md', + }, + ], + }, + ], + }, + { + text: 'Advanced Use Cases', + collapsed: false, + items: [ + { + text: 'Iroha On Bare Metal', + link: '/guide/advanced/running-iroha-on-bare-metal', + }, + { + text: 'Hot Reload Iroha', + link: '/guide/advanced/hot-reload', + }, + { + text: 'Monitor Iroha Performance', + link: '/guide/advanced/metrics', + }, + ], + }, + /* { + text: 'Reports', + collapsed: true, + items: [ + { + text: 'CSD/RTGS linkages via on-chain scripting', + link: '/guide/reports/csd-rtgs', + }, + ], + }, +*/ + ] +} + +function sidebarChain(): DefaultTheme.SidebarItem[] { + return [ + { + text: 'Iroha Explained', + link: '/blockchain/iroha-explained', + items: [ + { + text: 'Overview', + items: [ + { + text: 'Transactions', + link: '/blockchain/transactions', + }, + { + text: 'Consensus', + link: '/blockchain/consensus', + }, + { + text: 'Data Model', + link: '/blockchain/data-model', + }, + ], + }, + { + text: 'Entities', + items: [ + { + text: 'Assets', + link: '/blockchain/assets', + }, + /* + { + text: 'Accounts', + link: '/blockchain/accounts', + }, + { + text: 'Domains', + link: '/blockchain/domains', + }, + */ + { + text: 'Metadata', + link: '/blockchain/metadata', + }, + { + text: 'Events', + link: '/blockchain/events', + }, + { + text: 'Filters', + link: '/blockchain/filters', + }, + { + text: 'Triggers', + link: '/blockchain/triggers', + items: [ + { + text: 'Event Triggers by Example', + link: '/blockchain/trigger-examples', + }, + ], + }, + { + text: 'Queries', + link: '/blockchain/queries', + }, + { + text: 'Permissions', + link: '/blockchain/permissions', + }, + { + text: 'World', + link: '/blockchain/world', + }, + ], + }, + { + text: 'Operations', + items: [ + { + text: 'Instructions', + link: '/blockchain/instructions', + }, + { + text: 'Expressions', + link: '/blockchain/expressions', + }, + { + text: 'Web Assembly', + link: '/blockchain/wasm', + }, + ], + }, + ], + }, + ] +} + +function sidebarAPI(): DefaultTheme.SidebarItem[] { + return [ + { + text: 'About', + items: [ + { + text: 'Glossary', + link: '/reference/glossary.md', + }, + { + text: 'Naming Conventions', + link: '/reference/naming.md', + }, + { + text: 'Compatibility Matrix', + link: '/reference/compatibility-matrix', + }, + { + text: 'Foreign Function Interfaces', + link: '/reference/ffi', + }, + ], + }, + { + text: 'Reference', + items: [ + { + text: 'Torii Endpoints', + link: '/reference/torii-endpoints.md', + }, + { + text: 'Data Model Schema', + link: '/reference/data-model-schema', + }, + { + text: 'Instructions', + link: '/reference/instructions', + }, + { + text: 'Queries', + link: '/reference/queries.md', + }, + { + text: 'Permissions', + link: '/reference/permissions.md', + }, + ], + }, + ] +} + +function sidebarHelp(): DefaultTheme.SidebarItem[] { + return [ + { + text: 'Receive support', + link: '/help/', + }, + { + text: 'Troubleshooting', + items: [ + { + text: 'Overview', + link: '/help/overview', + }, + { + text: 'Installation', + link: '/help/installation-issues', + }, + { + text: 'Configuration', + link: '/help/configuration-issues', + }, + { + text: 'Deployment', + link: '/help/deployment-issues', + }, + { + text: 'Integration', + link: '/help/integration-issues', + }, + ], + }, + ] +} + +const BASE = process.env.PUBLIC_PATH ?? '/' + +export default defineConfig({ + base: BASE, + srcDir: 'src', + srcExclude: ['snippets/*.md'], + title: "Hyperledger Iroha 2 Docs | World's Most Advanced Blockchain Framework", + description: + 'Documentation for Hyperledger Iroha 2 offering step-by-step guides for SDKs and outlining the main differences between Iroha versions.', + lang: 'en-US', + vite: { + plugins: [ViteUnoCSS('../uno.config.ts'), ViteSvgLoader()], + envDir: resolve(__dirname, '../'), + }, + lastUpdated: true, + + head: [ + // Based on: https://evilmartians.com/chronicles/how-to-favicon-in-2021-six-files-that-fit-most-needs + ['link', { rel: 'icon', href: BASE + 'favicon.ico', sizes: 'any' }], + ['link', { rel: 'icon', href: BASE + 'icon.svg', sizes: 'image/svg+xml' }], + ['link', { rel: 'apple-touch-icon', href: BASE + 'apple-touch-icon.png' }], + ['link', { rel: 'manifest', href: BASE + 'manifest.webmanifest' }], + // Google Analytics integration + ['script', { src: 'https://www.googletagmanager.com/gtag/js?id=G-D6ETK9TN47' }], + [ + 'script', + {}, + ` + window.dataLayer = window.dataLayer || []; + function gtag(){dataLayer.push(arguments);} + gtag('js', new Date()); + + gtag('config', 'G-D6ETK9TN47'); + `, + ], + // KaTeX stylesheet + ['link', { rel: 'stylesheet', href: 'https://esm.sh/katex@0.16.8/dist/katex.min.css' }], + ], + + markdown: { + async config(md) { + md.use(footnote) + .use(mermaid) + // Note: Since vitepress@1.0.0-rc.14, it supports MathJax natively with `markdown.math = true`: + // https://github.com/vuejs/vitepress/pull/2977 + // Although KaTeX is more efficient, we might consider removing it in the future. + .use(katex) + }, + }, + + themeConfig: { + logo: '/icon.svg', + siteTitle: 'Iroha 2', + + socialLinks: [ + { icon: 'github', link: 'https://github.com/hyperledger-iroha/iroha-2-docs' }, + { + icon: { + /** + * https://icones.js.org/collection/material-symbols?s=bug + */ + svg: ``, + }, + link: 'https://github.com/hyperledger-iroha/iroha-2-docs/issues/new', + }, + ], + + editLink: { + pattern: 'https://github.com/hyperledger-iroha/iroha-2-docs/edit/main/src/:path', + text: 'Edit this page on GitHub', + }, + + lastUpdated: { + text: 'Last Updated', + }, + + nav: nav(), + outline: [2, 3], + + sidebar: { + '/get-started/': sidebarStart(), + '/guide/': sidebarGuide(), + '/blockchain/': sidebarChain(), + '/reference/': sidebarAPI(), + '/help/': sidebarHelp(), + }, + + search: { + provider: 'local', + }, + }, +}) diff --git a/.vitepress/config.ts b/.vitepress/config.ts deleted file mode 100644 index 189af52aa..000000000 --- a/.vitepress/config.ts +++ /dev/null @@ -1,5 +0,0 @@ -import { defineConfigWithTheme } from 'vitepress' - -export default defineConfigWithTheme({ - srcDir: 'src', -}) diff --git a/.vitepress/md-mermaid.ts b/.vitepress/md-mermaid.ts new file mode 100644 index 000000000..222131391 --- /dev/null +++ b/.vitepress/md-mermaid.ts @@ -0,0 +1,26 @@ +import MarkdownIt from 'markdown-it' +import hasha from 'hasha' + +/** + * Mermaid-js markdown-it plugin + */ +export const mermaid = (md: MarkdownIt) => { + const fence = md.renderer.rules.fence.bind(md.renderer.rules) + + md.renderer.rules.fence = (tokens, index, options, env, slf) => { + const token = tokens[index] + + if (token.info.trim() === 'mermaid') { + const content = token.content.trim() + const id = `mermaid_${hasha(content)}` + return `` + } + + // Shiki will highlight `mmd` as `mermaid` + if (token.info.trim() === 'mmd') { + tokens[index].info = 'mermaid' + } + + return fence(tokens, index, options, env, slf) + } +} diff --git a/.vitepress/theme/components/CompatibilityMatrixTable.vue b/.vitepress/theme/components/CompatibilityMatrixTable.vue new file mode 100644 index 000000000..fe377806d --- /dev/null +++ b/.vitepress/theme/components/CompatibilityMatrixTable.vue @@ -0,0 +1,104 @@ + + + + + diff --git a/.vitepress/theme/components/CompatibilityMatrixTableIcon.vue b/.vitepress/theme/components/CompatibilityMatrixTableIcon.vue new file mode 100644 index 000000000..4a895f98a --- /dev/null +++ b/.vitepress/theme/components/CompatibilityMatrixTableIcon.vue @@ -0,0 +1,57 @@ + + + + + diff --git a/.vitepress/theme/components/LayoutCustom.vue b/.vitepress/theme/components/LayoutCustom.vue new file mode 100644 index 000000000..2be2e3235 --- /dev/null +++ b/.vitepress/theme/components/LayoutCustom.vue @@ -0,0 +1,35 @@ + + + + + diff --git a/.vitepress/theme/components/MermaidRender.vue b/.vitepress/theme/components/MermaidRender.vue new file mode 100644 index 000000000..f6dbcc7df --- /dev/null +++ b/.vitepress/theme/components/MermaidRender.vue @@ -0,0 +1,71 @@ + + + diff --git a/.vitepress/theme/components/MermaidRenderWrap.vue b/.vitepress/theme/components/MermaidRenderWrap.vue new file mode 100644 index 000000000..e7b4b20d5 --- /dev/null +++ b/.vitepress/theme/components/MermaidRenderWrap.vue @@ -0,0 +1,16 @@ + + + diff --git a/.vitepress/theme/components/ShareFeedback.vue b/.vitepress/theme/components/ShareFeedback.vue new file mode 100644 index 000000000..4f9f88888 --- /dev/null +++ b/.vitepress/theme/components/ShareFeedback.vue @@ -0,0 +1,260 @@ + + +