Full Code of berialjs/berial for AI

master 12770c698e06 cached
29 files
30.2 KB
9.0k tokens
53 symbols
1 requests
Download .txt
Repository: berialjs/berial
Branch: master
Commit: 12770c698e06
Files: 29
Total size: 30.2 KB

Directory structure:
gitextract_21d_bcf2/

├── .eslintignore
├── .eslintrc
├── .gitattributes
├── .github/
│   └── workflows/
│       └── ci.yml
├── .gitignore
├── .prettierignore
├── .prettierrc
├── LICENSE
├── README.md
├── example/
│   ├── .gitignore
│   ├── App.js
│   ├── README.md
│   ├── index.css
│   ├── index.html
│   ├── index.js
│   ├── package.json
│   └── webpack.config.js
├── package.json
├── plugin/
│   ├── bridge-event.ts
│   └── package.json
├── rollup.config.js
├── src/
│   ├── entity.ts
│   ├── html-loader.ts
│   ├── index.ts
│   ├── mixin.ts
│   ├── sandbox.ts
│   ├── types.ts
│   └── util.ts
└── tsconfig.json

================================================
FILE CONTENTS
================================================

================================================
FILE: .eslintignore
================================================
dist
coverage
node_modules


================================================
FILE: .eslintrc
================================================
{
  "parser": "@typescript-eslint/parser",
  "parserOptions": {
    "ecmaVersion": 2019,
    "sourceType": "module",
    "ecmaFeatures": {
      "jsx": true
    }
  },
  "extends": [
    "prettier/@typescript-eslint",
    "plugin:prettier/recommended",
    "plugin:react/recommended",
    "plugin:@typescript-eslint/recommended"
  ],
  "plugins": ["@typescript-eslint"],
  "globals": {
    "__DEV__": true
  },
  "env": {
    "browser": true
  },
  "settings": {
    "react": {
      "pragma": "React",
      "version": "detect"
    }
  },
  "rules": {
    "@typescript-eslint/no-use-before-define": 0,
    "@typescript-eslint/no-var-requires": 0,
    "@typescript-eslint/no-unused-vars": 0,
    "@typescript-eslint/ban-ts-comment": 1,
    "@typescript-eslint/camelcase": 0,
    "@typescript-eslint/interface-name-prefix": 0,
    "@typescript-eslint/no-explicit-any": 0,
    "@typescript-eslint/no-empty-function": 0,
    "@typescript-eslint/explicit-function-return-type": 2,
    "@typescript-eslint/explicit-module-boundary-types": 0,
    "@typescript-eslint/no-non-null-assertion": 0,
    "no-shadow": 1,
    "prefer-const": 0,
    "jsx-quotes": 0,
    "prefer-rest-params":0,
    "react/prop-types": 0,
    "react/no-deprecated": 1,
    "react/display-name": 1
  }
}


================================================
FILE: .gitattributes
================================================
# Use Unix line endings in all text files.
* text=auto eol=lf


================================================
FILE: .github/workflows/ci.yml
================================================
name: ci

on: [push, pull_request]

jobs:
  build:
    runs-on: ubuntu-latest

    steps:
      - uses: actions/checkout@v2

      - run: npm i
      - run: npm run check


================================================
FILE: .gitignore
================================================
# dependencies
node_modules/
npm-debug.log*
yarn-error.log
yarn.lock
lerna-debug.log
**/**/node_modules/
**/**/**/node_modules/

# production
/dist

# misc
.DS_Store
.cache
coverage

# Editor directories and files
.idea
.vscode
*.suo
*.ntvs*
*.njsproj
*.sln
*.sw*

# Lock files
package-lock.json
yarn.lock


================================================
FILE: .prettierignore
================================================
dist/


================================================
FILE: .prettierrc
================================================
tabWidth: 2
useTabs: false
semi: false
arrowParens: always
singleQuote: true
printWidth: 80
trailingComma: none


================================================
FILE: LICENSE
================================================
MIT License

Copyright (c) 2020 yisar h-a-n-a

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.


================================================
FILE: README.md
================================================
<p align="center"><img src="https://avatars0.githubusercontent.com/u/68577605?s=200&v=4" alt="berial logo" width="150"></p>
<h1 align="center">Berial</h1>
<p align="center">:imp: Simple micro-front-end framework.</p>
<p align="center">
<a href="https://github.com/berialjs/berial/actions"><img src="https://img.shields.io/github/workflow/status/berialjs/berial/ci.svg" alt="Build Status"></a>
<a href="https://npmjs.com/package/berial"><img src="https://img.shields.io/npm/v/berial.svg" alt="npm-v"></a>
<a href="https://npmjs.com/package/berial"><img src="https://img.shields.io/npm/dt/berial.svg" alt="npm-d"></a>
</p>

### Why Berial

Berial is a new approach to a popular idea: build a javascript framework for front-end microservices.

There are any wonderful features of it, such as Asynchronous rendering pipeline, Web components (shadow DOM + scoped css), JavaScript sandbox (Proxy).

Note: diffence form fre, Berial will pay attention to business value.

### Use

```html
<one-app></one-app>
<two-app></two-app>

<script type="module">
  import { register } from 'berial'
  register([{
    name: 'one-app',
    url: '1.html',
    allowList: ['fre'] // 沙箱白名单
  },{
    name: 'two-app',
    scripts: ['2.js'], // 可选
    styles: ['2.css']
  }])
</script>
```

### License

MIT ©yisar ©h-a-n-a 


================================================
FILE: example/.gitignore
================================================
# Logs
logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*

# Runtime data
pids
*.pid
*.seed
*.pid.lock

# Directory for instrumented libs generated by jscoverage/JSCover
lib-cov

# Coverage directory used by tools like istanbul
coverage

# nyc test coverage
.nyc_output

# Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)
.grunt

# Bower dependency directory (https://bower.io/)
bower_components

# node-waf configuration
.lock-wscript

# Compiled binary addons (https://nodejs.org/api/addons.html)
build/Release

# Dependency directories
node_modules/
jspm_packages/

# TypeScript v1 declaration files
typings/

# Optional npm cache directory
.npm

# Optional eslint cache
.eslintcache

# Optional REPL history
.node_repl_history

# Output of 'npm pack'
*.tgz

# Yarn Integrity file
.yarn-integrity

# dotenv environment variables file
.env

# next.js build output
.next

.idea/
server/config.js
server/hcy.js
server/san.js

dist/


================================================
FILE: example/App.js
================================================
import { h, useEffect } from 'fre'
import { register } from '../dist/berial.esm'


function App() {

  const changeRoute = (pathname) => {
    history.pushState({}, '', pathname)
  }

  return <div>
    <header className='header'>
      <button onClick={() => changeRoute('/')} >Fre</button>
      <button onClick={() => changeRoute('/react')} >React</button>
      <button onClick={() => changeRoute('/vue')} >Vue</button>
    </header>
    <child-fre></child-fre>
    <child-react></child-react>
    <child-vue></child-vue>
  </div>
}

export default App


================================================
FILE: example/README.md
================================================
# Example

```
yarn install
yarn start
```


================================================
FILE: example/index.css
================================================
.header {
  height: 60px;
  display: flex;
  align-items: center;
  padding: 0 24px;
}

.header button {
  padding:10px 30px;
  cursor: pointer;
  background: #000;
  color: #fff;
  border: none;
  margin: 10px;
}


================================================
FILE: example/index.html
================================================
<html>
  <head> </head>
  <body>
    <div id='app'></div>
  </body>
</html>


================================================
FILE: example/index.js
================================================
import { h, render } from 'fre'
import './index.css'
import { register } from '../dist/berial.esm'

import App from './App'

if (!window.IS_BERIAL_SANDBOX) {
  render(<App />, document.getElementById('app'))
}

register([
  {
    name: 'child-fre',
    url: 'https://berial-child-fre.vercel.app',
    path: ({ pathname }) => pathname !== '/react' && pathname !== '/vue',
    allowList:['document']
  },
  {
    name: 'child-react',
    url: 'https://berial-child-react.vercel.app',
    path: ({ pathname }) => pathname === '/react'
  },
  {
    name: 'child-vue',
    url: 'https://berial-child-vue.vercel.app',
    path: ({ pathname }) => pathname === '/vue'
  }
])


================================================
FILE: example/package.json
================================================
{
  "scripts": {
    "start": "cross-env NODE_ENV=development webpack-dev-server --mode production"
  },
  "dependencies": {
    "fre": "^2.0.0-alpha.1"
  },
  "devDependencies": {
    "@babel/core": "^7.6.4",
    "@babel/plugin-transform-react-jsx": "^7.3.0",
    "@babel/preset-env": "^7.6.3",
    "babel-loader": "^8.0.6",
    "concurrently": "^5.3.0",
    "cross-env": "^6.0.3",
    "css-loader": "^3.2.0",
    "html-webpack-plugin": "^3.2.0",
    "mini-css-extract-plugin": "^0.8.0",
    "style-loader": "^1.0.1",
    "webpack": "^4.41.1",
    "webpack-cli": "^3.3.9",
    "webpack-dev-server": "^3.8.2"
  }
}


================================================
FILE: example/webpack.config.js
================================================
const path = require('path')
const HtmlWebpackPlugin = require('html-webpack-plugin')
const MiniCssExtractPlugin = require('mini-css-extract-plugin')

module.exports = {
  entry: './index.js',
  output: {
    path: path.resolve(__dirname, 'dist'),
    filename: '[name].js',
    library: 'one-app',
    libraryTarget: 'umd',
    umdNamedDefine: true,
    publicPath:
      process.env.NODE_ENV === 'production'
        ? 'https://berial.vercel.app'
        : 'http://localhost:3000'
  },
  module: {
    rules: [
      {
        test: /\.js$/,
        use: {
          loader: 'babel-loader',
          options: {
            plugins: [
              [
                '@babel/plugin-transform-react-jsx',
                {
                  pragma: 'h'
                }
              ]
            ]
          }
        }
      },
      {
        test: /\.css$/,
        use: [MiniCssExtractPlugin.loader, 'css-loader']
      }
    ]
  },
  optimization: {
    splitChunks: false
  },
  plugins: [
    new HtmlWebpackPlugin({
      template: './index.html'
    }),

    new MiniCssExtractPlugin({
      filename: '[name].css'
    })
  ],
  devServer: {
    headers: { 'Access-Control-Allow-Origin': '*' },
    contentBase: path.join(__dirname, 'dist'),
    compress: true,
    port: 3000,
    historyApiFallback: true,
    hot: true,
    open: true
  }
}


================================================
FILE: package.json
================================================
{
  "name": "berial",
  "version": "0.1.6",
  "description": "micro frontend",
  "main": "dist/berial.js",
  "module": "dist/berial.esm.js",
  "types": "dist/types/index.d.ts",
  "scripts": {
    "build": "rollup -c",
    "dev": "rollup -c --watch",
    "check": "run-p fmt-check lint",
    "fix": "run-s \"lint -- --fix\"",
    "fmt": "run-s \"fmt-check -- --write\"",
    "fmt-check": "prettier --check **/*.{json,ts}",
    "lint": "eslint **/*.ts",
    "type": "tsc --project tsconfig.json --skipLibCheck --noEmit"
  },
  "repository": {
    "type": "git",
    "url": "git+https://github.com/berialjs/berial.git"
  },
  "keywords": [],
  "author": "",
  "license": "MIT",
  "bugs": {
    "url": "https://github.com/berialjs/berial/issues"
  },
  "homepage": "https://github.com/berialjs/berial#readme",
  "devDependencies": {
    "cross-env": "^7.0.2",
    "eslint": "^7.5.0",
    "eslint-config-prettier": "^6.11.0",
    "eslint-plugin-prettier": "^3.1.4",
    "eslint-plugin-react": "^7.20.5",
    "http-server": "^0.12.3",
    "husky": "^4.2.5",
    "npm-run-all": "^4.1.5",
    "prettier": "^2.0.5",
    "rollup": "^2.23.0",
    "rollup-plugin-dts": "^1.4.11",
    "rollup-plugin-typescript2": "^0.27.1",
    "serve": "^11.3.2",
    "tslib": "^2.0.0",
    "typescript": "^3.9.7",
    "@typescript-eslint/eslint-plugin": "^3.7.0",
    "@typescript-eslint/parser": "^3.7.0"
  },
  "husky": {
    "hooks": {
      "pre-commit": "npm run fmt && npm run fix;"
    }
  }
}


================================================
FILE: plugin/bridge-event.ts
================================================
import { mixin } from 'berial'

export function bridgeEvent(): void {
  mixin({ boostrap })
}

async function boostrap(app): Promise<void> {
  const shadowRoot = app.host
  const define = Object.defineProperty
  const fromNode = shadowRoot,
    toNode = shadowRoot.host
  BRIDGE_EVENT_NAMES.map((eventName) => {
    fromNode.addEventListener(eventName, (fromEvent) => {
      fromEvent.stopPropagation()
      const Event = fromEvent.constructor
      const toEvent = new Event(eventName, {
        ...fromEvent,
        bubbles: true,
        cancelable: true,
        composed: true
      })
      const {
        path = [],
        target = path[0],
        srcElement = path[0],
        toElement = path[0],
        preventDefault
      } = fromEvent as any
      define(toEvent, 'path', { get: () => path })
      define(toEvent, 'target', { get: () => target })
      define(toEvent, 'srcElement', { get: () => srcElement })
      define(toEvent, 'toElement', { get: () => toElement })
      define(toEvent, 'preventDefault', {
        value: () => {
          preventDefault.call(fromEvent)
          return preventDefault.call(toEvent)
        }
      })
      toNode.dispatchEvent(toEvent)
    })
  })
}

const BRIDGE_EVENT_NAMES = [
  'abort',
  'animationcancel',
  'animationend',
  'animationiteration',
  'auxclick',
  'blur',
  'change',
  'click',
  'close',
  'contextmenu',
  'doubleclick',
  'error',
  'focus',
  'gotpointercapture',
  'input',
  'keydown',
  'keypress',
  'keyup',
  'load',
  'loadend',
  'loadstart',
  'lostpointercapture',
  'mousedown',
  'mousemove',
  'mouseout',
  'mouseover',
  'mouseup',
  'pointercancel',
  'pointerdown',
  'pointerenter',
  'pointerleave',
  'pointermove',
  'pointerout',
  'pointerover',
  'pointerup',
  'reset',
  'resize',
  'scroll',
  'select',
  'selectionchange',
  'selectstart',
  'submit',
  'touchcancel',
  'touchmove',
  'touchstart',
  'transitioncancel',
  'transitionend',
  'drag',
  'dragend',
  'dragenter',
  'dragexit',
  'dragleave',
  'dragover',
  'dragstart',
  'drop',
  'focusout'
]


================================================
FILE: plugin/package.json
================================================
{
  "name": "compat",
  "version": "0.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    "build": "tsc index.ts"
  },
  "keywords": [],
  "author": "",
  "license": "ISC",
  "dependencies": {
    "berial": "^0.0.4"
  }
}


================================================
FILE: rollup.config.js
================================================
import typescript from 'rollup-plugin-typescript2'

export default {
  input: 'src/index.ts',
  output: [
    { file: 'dist/berial.d.ts', format: 'esm', exports: 'named' },
    {
      file: 'dist/berial.esm.js',
      format: 'esm',
      sourcemap: true
    },
    {
      file: 'dist/berial.js',
      format: 'umd',
      sourcemap: true,
      name: 'berial'
    }
  ],
  plugins: [
    typescript({
      tsconfig: 'tsconfig.json',
      removeComments: true,
      useTsconfigDeclarationDir: true,
    }),
  ]
}


================================================
FILE: src/entity.ts
================================================
import type { App } from './types'
import { mapMixin } from './mixin'
import { importHtml } from './html-loader'

export enum Status {
  NOT_LOADED = 'NOT_LOADED',
  LOADING = 'LOADING',
  NOT_BOOTSTRAPPED = 'NOT_BOOTSTRAPPED',
  BOOTSTRAPPING = 'BOOTSTRAPPING',
  NOT_MOUNTED = 'NOT_MOUNTED',
  MOUNTING = 'MOUNTING',
  MOUNTED = 'MOUNTED',
  UPDATING = 'UPDATING',
  UPDATED = 'UPDATED',
  UNMOUNTING = 'UNMOUNTING'
}

let apps: App[] = []

export function register(appArray: any[]): void {
  appArray.forEach((app: any) => (app.status = Status.NOT_LOADED))
  apps = appArray
  hack()
  reroute()
}

function reroute(): void {
  const { loads, mounts, unmounts } = getAppChanges()
  perform()
  async function perform(): Promise<void> {
    unmounts.map(runUnmount)

    loads.map(async (app) => {
      app = await runLoad(app)
      app = await runBootstrap(app)
      return runMount(app)
    })

    mounts.map(async (app) => {
      app = await runBootstrap(app)
      return runMount(app)
    })
  }
}

function getAppChanges(): {
  unmounts: App[]
  loads: App[]
  mounts: App[]
} {
  const unmounts: App[] = []
  const loads: App[] = []
  const mounts: App[] = []

  apps.forEach((app: any) => {
    const isActive =
      typeof app.path === 'function'
        ? app.path(window.location)
        : window.location.pathname === app.path
    switch (app.status) {
      case Status.NOT_LOADED:
      case Status.LOADING:
        isActive && loads.push(app)
        break
      case Status.NOT_BOOTSTRAPPED:
      case Status.BOOTSTRAPPING:
      case Status.NOT_MOUNTED:
        isActive && mounts.push(app)
        break
      case Status.MOUNTED:
        !isActive && unmounts.push(app)
        break
    }
  })
  return { unmounts, loads, mounts }
}

function compose(
  fns: ((app: App) => Promise<any>)[]
): (app: App) => Promise<void> {
  fns = Array.isArray(fns) ? fns : [fns]
  return (app: App): Promise<void> =>
    fns.reduce((p, fn) => p.then(() => fn(app)), Promise.resolve())
}

async function runLoad(app: App): Promise<any> {
  if (app.loaded) return app.loaded
  app.loaded = Promise.resolve().then(async () => {
    app.status = Status.LOADING
    let mixinLife = mapMixin()
    app.host = await loadShadowDOM(app)
    const { dom, lifecycles } = await importHtml(app)
    app.host?.appendChild(dom)
    app.status = Status.NOT_BOOTSTRAPPED
    app.bootstrap = compose(mixinLife.bootstrap.concat(lifecycles.bootstrap))
    app.mount = compose(mixinLife.mount.concat(lifecycles.mount))
    app.unmount = compose(mixinLife.unmount.concat(lifecycles.unmount))
    delete app.loaded
    return app
  })
  return app.loaded
}

function loadShadowDOM(app: App): Promise<DocumentFragment> {
  return new Promise((resolve, reject) => {
    class Berial extends HTMLElement {
      static get tag(): string {
        return app.name
      }
      constructor() {
        super()
        resolve(this.attachShadow({ mode: 'open' }))
      }
    }
    const hasDef = window.customElements.get(app.name)
    if (!hasDef) {
      customElements.define(app.name, Berial)
    }
  })
}

async function runUnmount(app: App): Promise<App> {
  if (app.status != Status.MOUNTED) {
    return app
  }
  app.status = Status.UNMOUNTING
  await app.unmount(app)
  app.status = Status.NOT_MOUNTED
  return app
}

async function runBootstrap(app: App): Promise<App> {
  if (app.status !== Status.NOT_BOOTSTRAPPED) {
    return app
  }
  app.status = Status.BOOTSTRAPPING
  await app.bootstrap(app)
  app.status = Status.NOT_MOUNTED
  return app
}

async function runMount(app: App): Promise<App> {
  if (app.status !== Status.NOT_MOUNTED) {
    return app
  }
  app.status = Status.MOUNTING
  await app.mount(app)
  app.status = Status.MOUNTED
  return app
}

function hack(): void {
  window.addEventListener = hackEventListener(window.addEventListener)
  window.removeEventListener = hackEventListener(window.removeEventListener)

  window.history.pushState = hackHistory(window.history.pushState)
  window.history.replaceState = hackHistory(window.history.replaceState)

  window.addEventListener('hashchange', reroute)
  window.addEventListener('popstate', reroute)
}

const captured = {
  hashchange: [],
  popstate: []
} as any

function hackEventListener(func: any): any {
  return function (name: any, fn: any): any {
    if (name === 'hashchange' || name === 'popstate') {
      if (!captured[name].some((l: any) => l == fn)) {
        captured[name].push(fn)
        return
      } else {
        captured[name] = captured[name].filter((l: any) => l !== fn)
        return
      }
    }
    return func.apply(this, arguments as any)
  }
}

function hackHistory(fn: any): () => void {
  return function (): void {
    const before = window.location.href
    fn.apply(window.history, arguments)
    const after = window.location.href
    if (before !== after) {
      new PopStateEvent('popstate')
      reroute()
    }
  }
}


================================================
FILE: src/html-loader.ts
================================================
import { request } from './util'
import { runScript } from './sandbox'

const ALL_SCRIPT_REGEX = /<script\b[^<]*(?:(?!<\/script>)<[^<]*)*<\/script>/gi
const SCRIPT_TAG_REGEX = /<(script)\s+((?!type=('|')text\/ng-template\3).)*?>.*?<\/\1>/is
const SCRIPT_SRC_REGEX = /.*\ssrc=('|")?([^>'"\s]+)/
const SCRIPT_ENTRY_REGEX = /.*\sentry\s*.*/
const LINK_TAG_REGEX = /<(link)\s+.*?>/gi
const LINK_IGNORE_REGEX = /.*ignore\s*.*/
const LINK_PRELOAD_OR_PREFETCH_REGEX = /\srel=('|")?(preload|prefetch)\1/
const LINK_HREF_REGEX = /.*\shref=('|")?([^>'"\s]+)/
const STYLE_TAG_REGEX = /<style[^>]*>[\s\S]*?<\/style>/gi
const STYLE_TYPE_REGEX = /\s+rel=('|")?stylesheet\1.*/
const STYLE_HREF_REGEX = /.*\shref=('|")?([^>'"\s]+)/
const STYLE_IGNORE_REGEX = /<style(\s+|\s+.+\s+)ignore(\s*|\s+.*)>/i
const HTML_COMMENT_REGEX = /<!--([\s\S]*?)-->/g
const SCRIPT_IGNORE_REGEX = /<script(\s+|\s+.+\s+)ignore(\s*|\s+.*)>/i

export function getInlineCode(match: any): string {
  const start = match.indexOf('>') + 1
  const end = match.lastIndexOf('<')
  return match.substring(start, end)
}

function hasProtocol(url: string): any {
  return (
    url.startsWith('//') ||
    url.startsWith('http://') ||
    url.startsWith('https://')
  )
}

function getEntirePath(path: string, baseURI: string): string {
  return new URL(path, baseURI).toString()
}

export const genLinkReplaceSymbol = (linkHref: any): string =>
  `<!-- link ${linkHref} replaced by import-html-entry -->`
export const genScriptReplaceSymbol = (scriptSrc: any): string =>
  `<!-- script ${scriptSrc} replaced by import-html-entry -->`
export const inlineScriptReplaceSymbol = `<!-- inline scripts replaced by import-html-entry -->`
export const genIgnoreAssetReplaceSymbol = (url: any): string =>
  `<!-- ignore asset ${url || 'file'} replaced by import-html-entry -->`

export function parse(tpl: string, baseURI: string): any {
  let scripts: string[] = []
  const styles: string[] = []
  let entry: any = null

  const template = tpl
    .replace(HTML_COMMENT_REGEX, '')
    .replace(LINK_TAG_REGEX, (match) => {
      const styleType = !!match.match(STYLE_TYPE_REGEX)
      console.log(styleType)
      if (styleType) {
        const styleHref = match.match(STYLE_HREF_REGEX)
        const styleIgnore = match.match(LINK_IGNORE_REGEX)

        if (styleHref) {
          const href = styleHref && styleHref[2]
          let newHref = href
          if (href && !hasProtocol(href)) {
            newHref = getEntirePath(href, baseURI)
          }
          if (styleIgnore) {
            return genIgnoreAssetReplaceSymbol(newHref)
          }

          styles.push(newHref)
          return genLinkReplaceSymbol(newHref)
        }
      }

      const preloadOrPrefetchType = !!match.match(
        LINK_PRELOAD_OR_PREFETCH_REGEX
      )
      if (preloadOrPrefetchType) {
        const linkHref = match.match(LINK_HREF_REGEX)

        if (linkHref) {
          const href = linkHref[2]
          if (href && !hasProtocol(href)) {
            const newHref = getEntirePath(href, baseURI)
            return match.replace(href, newHref)
          }
        }
      }

      return match
    })
    .replace(STYLE_TAG_REGEX, (match) => {
      if (STYLE_IGNORE_REGEX.test(match)) {
        return genIgnoreAssetReplaceSymbol('style file')
      }
      return match
    })
    .replace(ALL_SCRIPT_REGEX, (match) => {
      const scriptIgnore = match.match(SCRIPT_IGNORE_REGEX)
      if (SCRIPT_TAG_REGEX.test(match) && match.match(SCRIPT_SRC_REGEX)) {
        const matchedScriptEntry = match.match(SCRIPT_ENTRY_REGEX)
        const matchedScriptSrcMatch = match.match(SCRIPT_SRC_REGEX)
        let matchedScriptSrc = matchedScriptSrcMatch && matchedScriptSrcMatch[2]

        if (entry && matchedScriptEntry) {
          throw new SyntaxError('You should not set multiply entry script!')
        } else {
          if (matchedScriptSrc && !hasProtocol(matchedScriptSrc)) {
            matchedScriptSrc = getEntirePath(matchedScriptSrc, baseURI)
          }

          entry = entry || (matchedScriptEntry && matchedScriptSrc)
        }

        if (scriptIgnore) {
          return genIgnoreAssetReplaceSymbol(matchedScriptSrc || 'js file')
        }

        if (matchedScriptSrc) {
          scripts.push(matchedScriptSrc)
          return genScriptReplaceSymbol(matchedScriptSrc)
        }

        return match
      } else {
        if (scriptIgnore) {
          return genIgnoreAssetReplaceSymbol('js file')
        }
        const code = getInlineCode(match)
        const isPureCommentBlock = code
          .split(/[\r\n]+/)
          .every((line) => !line.trim() || line.trim().startsWith('//'))

        if (!isPureCommentBlock) {
          scripts.push(match)
        }

        return inlineScriptReplaceSymbol
      }
    })

  scripts = scripts.filter((s: string) => !!s)

  return {
    template,
    scripts,
    styles,
    entry: entry || scripts[scripts.length - 1]
  }
}
export async function importHtml(app: any): Promise<any> {
  let template = '',
    scripts,
    styles
  if (app.scripts) {
    scripts = app.scripts || []
    styles = app.styles || []
  } else {
    const tpl = await request(app.url as string)
    let res = parse(tpl, '')
    scripts = res.scripts
    styles = res.styles
    template = res.template
  }

  scripts = await Promise.all(
    scripts.map((s: string) =>
      hasProtocol(s)
        ? request(s)
        : s.endsWith('.js') || s.endsWith('.jsx')
        ? request(window.origin + s)
        : s
    )
  )
  styles = styles.map((s: string) =>
    hasProtocol(s) || s.endsWith('.css')
      ? `<link rel="stylesheet" href="${s}" ></link>`
      : `<style>${s}<style>`
  )
  template = template

  let lifecycles = null
  scripts.forEach(async (script: any) => {
    lifecycles = runScript(script, app.allowList)[app.name]
  })

  const dom = document.createDocumentFragment()
  const body = document.createElement('template')
  let out = ''
  styles.forEach((s: string) => (out += s))
  out += template
  body.innerHTML = out
  dom.appendChild(body.content.cloneNode(true))
  return { dom, lifecycles }
}


================================================
FILE: src/index.ts
================================================
import { register } from './entity'
import { mixin, use } from './mixin'
import { importHtml } from './html-loader'
import { runScript } from './sandbox'

export { register, importHtml, runScript, mixin, use }


================================================
FILE: src/mixin.ts
================================================
import type { Lifecycles, Mixin, Plugin } from './types'

const mixins: Set<Mixin> = new Set()
const plugins: Set<Plugin> = new Set()

export function use(plugin: Plugin, ...args: any[]): void {
  if (!plugins.has(plugin)) {
    plugins.add(plugin)
    plugin(...args)
  }
}

export function mixin(mix: Mixin): void {
  if (!mixins.has(mix)) {
    mixins.add(mix)
  }
}

export function mapMixin(): Lifecycles {
  const out: Lifecycles = {
    load: [],
    bootstrap: [],
    mount: [],
    unmount: []
  }
  mixins.forEach((item: Mixin) => {
    item.load && out.load!.push(item.load)
    item.bootstrap && out.bootstrap.push(item.bootstrap)
    item.mount && out.mount.push(item.mount)
    item.unmount && out.unmount.push(item.unmount)
  })
  return out
}


================================================
FILE: src/sandbox.ts
================================================
export function runScript(code: string, allow: any = []): any {
  const allowObj = allow.reduce((obj: any, cur: any): any => {
    obj[cur] = window[cur]
    return obj
  }, {}) as any

  try {
    const handler = {
      get(obj: any, prop: string): any {
        return Reflect.has(obj, prop) ? obj[prop] : null
      },
      set(obj: any, prop: string, value: any): boolean {
        Reflect.set(obj, prop, value)
        return true
      },
      has(obj: any, prop: string): boolean {
        return obj && Reflect.has(obj, prop)
      }
    }
    const captureHandler = {
      get(obj: any, prop: string): any {
        return Reflect.get(obj, prop)
      },
      set(): boolean {
        return true
      },
      has(): boolean {
        return true
      }
    }

    const allowList = {
      IS_BERIAL_SANDBOX: true,
      __proto__: null,
      console,
      String,
      Number,
      Array,
      Symbol,
      Math,
      Object,
      Promise,
      RegExp,
      JSON,
      Date,
      Function,
      parseInt,
      document,
      location,
      performance,
      MessageChannel,
      SVGElement,
      HTMLElement,
      HTMLIFrameElement,
      history,
      Map,
      Set,
      WeakMap,
      WeakSet,
      Error,
      localStorage,
      decodeURI,
      encodeURI,
      decodeURIComponent,
      encodeURIComponent,
      fetch: fetch.bind(window),
      setTimeout: setTimeout.bind(window),
      clearTimeout: clearTimeout.bind(window),
      setInterval: setInterval.bind(window),
      clearInterval: clearInterval.bind(window),
      requestAnimationFrame: requestAnimationFrame.bind(window),
      cancelAnimationFrame: cancelAnimationFrame.bind(window),
      addEventListener: addEventListener.bind(window),
      removeEventListener: removeEventListener.bind(window),
      // eslint-disable-next-line no-shadow
      eval: function (code: string): any {
        return runScript('return ' + code, {})
      },
      alert: function (): void {
        alert('Sandboxed alert:' + arguments[0])
      },
      // position related properties
      innerHeight,
      innerWidth,
      outerHeight,
      outerWidth,
      pageXOffset,
      pageYOffset,
      screen,
      screenLeft,
      screenTop,
      screenX,
      screenY,
      scrollBy,
      scrollTo,
      scrollX,
      scrollY,
      // custom allow list
      ...allowObj
    }

    if (!Object.isFrozen(String.prototype)) {
      for (const k in allowList) {
        const fn = allowList[k]
        if (typeof fn === 'object' && fn.prototype) {
          Object.freeze(fn.prototype)
        }
        if (typeof fn === 'function') {
          Object.freeze(fn)
        }
      }
    }
    const proxy = new Proxy(allowList, handler)
    const capture = new Proxy(
      {
        __proto__: null,
        proxy,
        globalThis: new Proxy(allowList, handler),
        window: new Proxy(allowList, handler),
        self: new Proxy(allowList, handler)
      },
      captureHandler
    )
    return Function(
      'proxy',
      'capture',
      `with(capture) {     
            with(proxy) {  
              return (function(){                                               
                ${code};
                return window
              })();
            }
        }`
    )(proxy, capture)
  } catch (e) {
    throw e
  }
}


================================================
FILE: src/types.ts
================================================
import type { Status } from './entity'

export type Lifecycles = ToArray<Lifecycle>

export type Lifecycle = {
  bootstrap: PromiseFn
  unmount: PromiseFn
  mount: PromiseFn
  load?: PromiseFn
}

export type Mixin = {
  load?: PromiseFn
  mount?: PromiseFn
  unmount?: PromiseFn
  bootstrap?: PromiseFn
}

export type Plugin = (...args: any[]) => any

export type App = {
  name: string
  node: HTMLElement
  url: ((props: App['props']) => Lifecycle) | string
  match: (location: Location) => boolean
  host: DocumentFragment
  props: Record<string, unknown>
  status: Status
  loaded?: any
  store?: any
  loadLifecycle: any
  unmount: PromiseFn
  mount: PromiseFn
  bootstrap: PromiseFn
}

export type PromiseFn = (...args: any[]) => Promise<any>

export type ArrayType<T> = T extends (infer U)[] ? U : T

export type ToArray<T> = T extends Record<any, any>
  ? {
      [K in keyof T]: T[K][]
    }
  : unknown

export type ProxyType = Omit<ProxyConstructor, keyof ProxyConstructor>


================================================
FILE: src/util.ts
================================================
import type { Lifecycle, Lifecycles } from './types'

export function warn(trigger: string): void
export function warn(trigger: boolean, msg?: string): void
export function warn(trigger: any, msg?: any): void {
  if (typeof trigger === 'string') msg = trigger
  if (!trigger) return
  throw new Error(`[Berial: Warning]: ${msg}`)
}

export function error(trigger: string): void
export function error(trigger: boolean, msg?: string): void
export function error(trigger: any, msg?: any): void {
  if (typeof trigger === 'string') msg = trigger
  if (!trigger) return
  throw new Error(`[Berial: Error]: ${msg}`)
}

export function request(url: string, option?: RequestInit): Promise<string> {
  return fetch(url, {
    mode: 'cors',
    ...option
  }).then((res) => res.text())
}

export function reverse<T>(arr: T[]): T[] {
  return Array.from(arr).reverse()
}


================================================
FILE: tsconfig.json
================================================
{
  "compilerOptions": {
    "strict": true,
    "sourceMap": true,
    "noImplicitAny": true,
    "removeComments": true,
    "target": "es6",
    "module": "es6",
    "moduleResolution": "node",
    "esModuleInterop": true,
    "allowSyntheticDefaultImports": true,
    "downlevelIteration": true,
    "noImplicitThis": false,
    "jsx": "react",
    "lib": ["es6", "dom"],
    "baseUrl": ".",
    "outDir": "./dist",
    "paths": {
      "@/*": ["./src/*"]
    }
  },
  "include": ["src/**/*"],
  "exclude": ["test/*", "node_modules"]
}
Download .txt
gitextract_21d_bcf2/

├── .eslintignore
├── .eslintrc
├── .gitattributes
├── .github/
│   └── workflows/
│       └── ci.yml
├── .gitignore
├── .prettierignore
├── .prettierrc
├── LICENSE
├── README.md
├── example/
│   ├── .gitignore
│   ├── App.js
│   ├── README.md
│   ├── index.css
│   ├── index.html
│   ├── index.js
│   ├── package.json
│   └── webpack.config.js
├── package.json
├── plugin/
│   ├── bridge-event.ts
│   └── package.json
├── rollup.config.js
├── src/
│   ├── entity.ts
│   ├── html-loader.ts
│   ├── index.ts
│   ├── mixin.ts
│   ├── sandbox.ts
│   ├── types.ts
│   └── util.ts
└── tsconfig.json
Download .txt
SYMBOL INDEX (53 symbols across 8 files)

FILE: example/App.js
  function App (line 5) | function App() {

FILE: plugin/bridge-event.ts
  function bridgeEvent (line 3) | function bridgeEvent(): void {
  function boostrap (line 7) | async function boostrap(app): Promise<void> {
  constant BRIDGE_EVENT_NAMES (line 44) | const BRIDGE_EVENT_NAMES = [

FILE: src/entity.ts
  type Status (line 5) | enum Status {
  function register (line 20) | function register(appArray: any[]): void {
  function reroute (line 27) | function reroute(): void {
  function getAppChanges (line 46) | function getAppChanges(): {
  function compose (line 78) | function compose(
  function runLoad (line 86) | async function runLoad(app: App): Promise<any> {
  function loadShadowDOM (line 104) | function loadShadowDOM(app: App): Promise<DocumentFragment> {
  function runUnmount (line 122) | async function runUnmount(app: App): Promise<App> {
  function runBootstrap (line 132) | async function runBootstrap(app: App): Promise<App> {
  function runMount (line 142) | async function runMount(app: App): Promise<App> {
  function hack (line 152) | function hack(): void {
  function hackEventListener (line 168) | function hackEventListener(func: any): any {
  function hackHistory (line 183) | function hackHistory(fn: any): () => void {

FILE: src/html-loader.ts
  constant ALL_SCRIPT_REGEX (line 4) | const ALL_SCRIPT_REGEX = /<script\b[^<]*(?:(?!<\/script>)<[^<]*)*<\/scri...
  constant SCRIPT_TAG_REGEX (line 5) | const SCRIPT_TAG_REGEX = /<(script)\s+((?!type=('|')text\/ng-template\3)...
  constant SCRIPT_SRC_REGEX (line 6) | const SCRIPT_SRC_REGEX = /.*\ssrc=('|")?([^>'"\s]+)/
  constant SCRIPT_ENTRY_REGEX (line 7) | const SCRIPT_ENTRY_REGEX = /.*\sentry\s*.*/
  constant LINK_TAG_REGEX (line 8) | const LINK_TAG_REGEX = /<(link)\s+.*?>/gi
  constant LINK_IGNORE_REGEX (line 9) | const LINK_IGNORE_REGEX = /.*ignore\s*.*/
  constant LINK_PRELOAD_OR_PREFETCH_REGEX (line 10) | const LINK_PRELOAD_OR_PREFETCH_REGEX = /\srel=('|")?(preload|prefetch)\1/
  constant LINK_HREF_REGEX (line 11) | const LINK_HREF_REGEX = /.*\shref=('|")?([^>'"\s]+)/
  constant STYLE_TAG_REGEX (line 12) | const STYLE_TAG_REGEX = /<style[^>]*>[\s\S]*?<\/style>/gi
  constant STYLE_TYPE_REGEX (line 13) | const STYLE_TYPE_REGEX = /\s+rel=('|")?stylesheet\1.*/
  constant STYLE_HREF_REGEX (line 14) | const STYLE_HREF_REGEX = /.*\shref=('|")?([^>'"\s]+)/
  constant STYLE_IGNORE_REGEX (line 15) | const STYLE_IGNORE_REGEX = /<style(\s+|\s+.+\s+)ignore(\s*|\s+.*)>/i
  constant HTML_COMMENT_REGEX (line 16) | const HTML_COMMENT_REGEX = /<!--([\s\S]*?)-->/g
  constant SCRIPT_IGNORE_REGEX (line 17) | const SCRIPT_IGNORE_REGEX = /<script(\s+|\s+.+\s+)ignore(\s*|\s+.*)>/i
  function getInlineCode (line 19) | function getInlineCode(match: any): string {
  function hasProtocol (line 25) | function hasProtocol(url: string): any {
  function getEntirePath (line 33) | function getEntirePath(path: string, baseURI: string): string {
  function parse (line 45) | function parse(tpl: string, baseURI: string): any {
  function importHtml (line 150) | async function importHtml(app: any): Promise<any> {

FILE: src/mixin.ts
  function use (line 6) | function use(plugin: Plugin, ...args: any[]): void {
  function mixin (line 13) | function mixin(mix: Mixin): void {
  function mapMixin (line 19) | function mapMixin(): Lifecycles {

FILE: src/sandbox.ts
  function runScript (line 1) | function runScript(code: string, allow: any = []): any {

FILE: src/types.ts
  type Lifecycles (line 3) | type Lifecycles = ToArray<Lifecycle>
  type Lifecycle (line 5) | type Lifecycle = {
  type Mixin (line 12) | type Mixin = {
  type Plugin (line 19) | type Plugin = (...args: any[]) => any
  type App (line 21) | type App = {
  type PromiseFn (line 37) | type PromiseFn = (...args: any[]) => Promise<any>
  type ArrayType (line 39) | type ArrayType<T> = T extends (infer U)[] ? U : T
  type ToArray (line 41) | type ToArray<T> = T extends Record<any, any>
  type ProxyType (line 47) | type ProxyType = Omit<ProxyConstructor, keyof ProxyConstructor>

FILE: src/util.ts
  function warn (line 5) | function warn(trigger: any, msg?: any): void {
  function error (line 13) | function error(trigger: any, msg?: any): void {
  function request (line 19) | function request(url: string, option?: RequestInit): Promise<string> {
  function reverse (line 26) | function reverse<T>(arr: T[]): T[] {
Condensed preview — 29 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (34K chars).
[
  {
    "path": ".eslintignore",
    "chars": 27,
    "preview": "dist\ncoverage\nnode_modules\n"
  },
  {
    "path": ".eslintrc",
    "chars": 1271,
    "preview": "{\n  \"parser\": \"@typescript-eslint/parser\",\n  \"parserOptions\": {\n    \"ecmaVersion\": 2019,\n    \"sourceType\": \"module\",\n   "
  },
  {
    "path": ".gitattributes",
    "chars": 62,
    "preview": "# Use Unix line endings in all text files.\n* text=auto eol=lf\n"
  },
  {
    "path": ".github/workflows/ci.yml",
    "chars": 171,
    "preview": "name: ci\n\non: [push, pull_request]\n\njobs:\n  build:\n    runs-on: ubuntu-latest\n\n    steps:\n      - uses: actions/checkout"
  },
  {
    "path": ".gitignore",
    "chars": 306,
    "preview": "# dependencies\nnode_modules/\nnpm-debug.log*\nyarn-error.log\nyarn.lock\nlerna-debug.log\n**/**/node_modules/\n**/**/**/node_m"
  },
  {
    "path": ".prettierignore",
    "chars": 6,
    "preview": "dist/\n"
  },
  {
    "path": ".prettierrc",
    "chars": 112,
    "preview": "tabWidth: 2\nuseTabs: false\nsemi: false\narrowParens: always\nsingleQuote: true\nprintWidth: 80\ntrailingComma: none\n"
  },
  {
    "path": "LICENSE",
    "chars": 1070,
    "preview": "MIT License\n\nCopyright (c) 2020 yisar h-a-n-a\n\nPermission is hereby granted, free of charge, to any person obtaining a c"
  },
  {
    "path": "README.md",
    "chars": 1300,
    "preview": "<p align=\"center\"><img src=\"https://avatars0.githubusercontent.com/u/68577605?s=200&v=4\" alt=\"berial logo\" width=\"150\"><"
  },
  {
    "path": "example/.gitignore",
    "chars": 974,
    "preview": "# Logs\nlogs\n*.log\nnpm-debug.log*\nyarn-debug.log*\nyarn-error.log*\n\n# Runtime data\npids\n*.pid\n*.seed\n*.pid.lock\n\n# Directo"
  },
  {
    "path": "example/App.js",
    "chars": 557,
    "preview": "import { h, useEffect } from 'fre'\nimport { register } from '../dist/berial.esm'\n\n\nfunction App() {\n\n  const changeRoute"
  },
  {
    "path": "example/README.md",
    "chars": 43,
    "preview": "# Example\n\n```\nyarn install\nyarn start\n```\n"
  },
  {
    "path": "example/index.css",
    "chars": 214,
    "preview": ".header {\n  height: 60px;\n  display: flex;\n  align-items: center;\n  padding: 0 24px;\n}\n\n.header button {\n  padding:10px "
  },
  {
    "path": "example/index.html",
    "chars": 76,
    "preview": "<html>\n  <head> </head>\n  <body>\n    <div id='app'></div>\n  </body>\n</html>\n"
  },
  {
    "path": "example/index.js",
    "chars": 667,
    "preview": "import { h, render } from 'fre'\nimport './index.css'\nimport { register } from '../dist/berial.esm'\n\nimport App from './A"
  },
  {
    "path": "example/package.json",
    "chars": 615,
    "preview": "{\n  \"scripts\": {\n    \"start\": \"cross-env NODE_ENV=development webpack-dev-server --mode production\"\n  },\n  \"dependencies"
  },
  {
    "path": "example/webpack.config.js",
    "chars": 1357,
    "preview": "const path = require('path')\nconst HtmlWebpackPlugin = require('html-webpack-plugin')\nconst MiniCssExtractPlugin = requi"
  },
  {
    "path": "package.json",
    "chars": 1474,
    "preview": "{\n  \"name\": \"berial\",\n  \"version\": \"0.1.6\",\n  \"description\": \"micro frontend\",\n  \"main\": \"dist/berial.js\",\n  \"module\": \""
  },
  {
    "path": "plugin/bridge-event.ts",
    "chars": 2081,
    "preview": "import { mixin } from 'berial'\n\nexport function bridgeEvent(): void {\n  mixin({ boostrap })\n}\n\nasync function boostrap(a"
  },
  {
    "path": "plugin/package.json",
    "chars": 297,
    "preview": "{\n  \"name\": \"compat\",\n  \"version\": \"0.0.0\",\n  \"description\": \"\",\n  \"main\": \"index.js\",\n  \"scripts\": {\n    \"test\": \"echo "
  },
  {
    "path": "rollup.config.js",
    "chars": 519,
    "preview": "import typescript from 'rollup-plugin-typescript2'\n\nexport default {\n  input: 'src/index.ts',\n  output: [\n    { file: 'd"
  },
  {
    "path": "src/entity.ts",
    "chars": 4936,
    "preview": "import type { App } from './types'\nimport { mapMixin } from './mixin'\nimport { importHtml } from './html-loader'\n\nexport"
  },
  {
    "path": "src/html-loader.ts",
    "chars": 6118,
    "preview": "import { request } from './util'\nimport { runScript } from './sandbox'\n\nconst ALL_SCRIPT_REGEX = /<script\\b[^<]*(?:(?!<\\"
  },
  {
    "path": "src/index.ts",
    "chars": 210,
    "preview": "import { register } from './entity'\nimport { mixin, use } from './mixin'\nimport { importHtml } from './html-loader'\nimpo"
  },
  {
    "path": "src/mixin.ts",
    "chars": 760,
    "preview": "import type { Lifecycles, Mixin, Plugin } from './types'\n\nconst mixins: Set<Mixin> = new Set()\nconst plugins: Set<Plugin"
  },
  {
    "path": "src/sandbox.ts",
    "chars": 3353,
    "preview": "export function runScript(code: string, allow: any = []): any {\n  const allowObj = allow.reduce((obj: any, cur: any): an"
  },
  {
    "path": "src/types.ts",
    "chars": 985,
    "preview": "import type { Status } from './entity'\n\nexport type Lifecycles = ToArray<Lifecycle>\n\nexport type Lifecycle = {\n  bootstr"
  },
  {
    "path": "src/util.ts",
    "chars": 860,
    "preview": "import type { Lifecycle, Lifecycles } from './types'\n\nexport function warn(trigger: string): void\nexport function warn(t"
  },
  {
    "path": "tsconfig.json",
    "chars": 540,
    "preview": "{\n  \"compilerOptions\": {\n    \"strict\": true,\n    \"sourceMap\": true,\n    \"noImplicitAny\": true,\n    \"removeComments\": tru"
  }
]

About this extraction

This page contains the full source code of the berialjs/berial GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 29 files (30.2 KB), approximately 9.0k tokens, and a symbol index with 53 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.

Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.

Copied to clipboard!