mirror of
https://github.com/dream-num/univer.git
synced 2026-09-01 15:29:43 +08:00
init
This commit is contained in:
@@ -0,0 +1,8 @@
|
||||
# Changesets
|
||||
|
||||
Hello and welcome! This folder has been automatically generated by `@changesets/cli`, a build tool that works
|
||||
with multi-package repos, or single-package repos to help you version and publish your code. You can
|
||||
find the full documentation for it [in our repository](https://github.com/changesets/changesets)
|
||||
|
||||
We have a quick list of common questions to get you started engaging with this project in
|
||||
[our documentation](https://github.com/changesets/changesets/blob/main/docs/common-questions.md)
|
||||
@@ -0,0 +1,11 @@
|
||||
{
|
||||
"$schema": "https://unpkg.com/@changesets/config@2.0.0/schema.json",
|
||||
"changelog": "@changesets/cli/changelog",
|
||||
"commit": false,
|
||||
"fixed": [],
|
||||
"linked": [],
|
||||
"access": "restricted",
|
||||
"baseBranch": "main",
|
||||
"updateInternalDependencies": "patch",
|
||||
"ignore": []
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
.eslintrc.js
|
||||
vite.config.ts
|
||||
**/*.test.js
|
||||
dist
|
||||
lib
|
||||
node_modules
|
||||
package.json
|
||||
tsconfig.json
|
||||
jest.config.js
|
||||
+113
@@ -0,0 +1,113 @@
|
||||
module.exports = {
|
||||
// env: {
|
||||
// browser: true,
|
||||
// es2021: true,
|
||||
// node: true,
|
||||
// jest: true,
|
||||
// },
|
||||
globals: {
|
||||
page: true,
|
||||
browser: true,
|
||||
context: true,
|
||||
jestPuppeteer: true,
|
||||
},
|
||||
// parser: '@typescript-eslint/parser',
|
||||
// extends: ['airbnb-typescript', 'prettier', 'eslint:recommended', 'plugin:import/recommended', 'plugin:import/typescript'],
|
||||
extends: ['airbnb-base', 'airbnb-typescript/base', 'prettier'],
|
||||
env: {
|
||||
browser: true,
|
||||
es2021: true,
|
||||
},
|
||||
parser: '@typescript-eslint/parser',
|
||||
parserOptions: {
|
||||
warnOnUnsupportedTypeScriptVersion: false,
|
||||
ecmaVersion: 12,
|
||||
sourceType: 'module',
|
||||
tsconfigRootDir: __dirname,
|
||||
project: ['./packages/*/tsconfig.json'],
|
||||
},
|
||||
plugins: ['@typescript-eslint', 'prettier', 'import', 'import-newlines', 'unused-imports'],
|
||||
rules: {
|
||||
'prettier/prettier': [
|
||||
'error',
|
||||
{
|
||||
endOfLine: 'auto',
|
||||
},
|
||||
],
|
||||
'import/prefer-default-export': 'off',
|
||||
'import/no-extraneous-dependencies': ['error', { devDependencies: true }],
|
||||
// turn on errors for missing imports
|
||||
'import/no-unresolved': [2, { ignore: ['\\.less$', '^@'] }],
|
||||
'@typescript-eslint/naming-convention': 'off',
|
||||
'@typescript-eslint/no-unused-vars': 'off',
|
||||
'@typescript-eslint/no-use-before-define': 'off',
|
||||
'@typescript-eslint/no-shadow': 'off',
|
||||
'import/no-cycle': 'off',
|
||||
'no-param-reassign': 'off',
|
||||
'no-bitwise': 'off',
|
||||
'default-case': 'off',
|
||||
'class-methods-use-this': 'off',
|
||||
'consistent-return': 'off',
|
||||
'no-underscore-dangle': 'off',
|
||||
'no-restricted-syntax': 'off',
|
||||
'max-classes-per-file': 'off',
|
||||
'prefer-destructuring': 'off',
|
||||
'no-plusplus': 'off',
|
||||
'no-return-assign': 'off',
|
||||
'no-continue': 'off',
|
||||
'no-loop-func': 'off',
|
||||
'@typescript-eslint/no-loop-func': 'off',
|
||||
'guard-for-in': 'off',
|
||||
'no-prototype-builtins': 'off',
|
||||
'no-lonely-if': 'off',
|
||||
'prefer-const': 'off',
|
||||
radix: 'off',
|
||||
'no-nested-ternary': 'off',
|
||||
'no-new': 'off',
|
||||
'no-unused-expressions': 'off',
|
||||
'@typescript-eslint/no-unused-expressions': 'off',
|
||||
'no-console': 'off',
|
||||
'no-multi-assign': 'off',
|
||||
'no-restricted-properties': 'off',
|
||||
'no-control-regex': 'off',
|
||||
'@typescript-eslint/array-type': ['error', { default: 'array-simple' }],
|
||||
'no-await-in-loop': 'off',
|
||||
'@typescript-eslint/explicit-member-accessibility': [
|
||||
'error',
|
||||
{
|
||||
accessibility: 'no-public',
|
||||
},
|
||||
],
|
||||
'@typescript-eslint/consistent-type-assertions': ['error', { assertionStyle: 'as', objectLiteralTypeAssertions: 'allow-as-parameter' }],
|
||||
'spaced-comment': 'off',
|
||||
eqeqeq: ['error', 'always', { null: 'ignore' }],
|
||||
|
||||
// eslint-plugin-unused-imports
|
||||
'@typescript-eslint/no-unused-vars': 'off',
|
||||
'unused-imports/no-unused-imports': 'error',
|
||||
|
||||
'prefer-regex-literals': 'off',
|
||||
'@typescript-eslint/default-param-last': 'off',
|
||||
'grouped-accessor-pairs': 'off',
|
||||
},
|
||||
settings: {
|
||||
'import/parsers': {
|
||||
'@typescript-eslint/parser': ['.ts', '.tsx'],
|
||||
},
|
||||
'import/resolver': {
|
||||
typescript: {
|
||||
// always try to resolve config under `<root>@config`
|
||||
// directory even it doesn't contain any source code,
|
||||
// like `@config/unist`
|
||||
alwaysTryTypes: true,
|
||||
// Choose from one of the "project" configs below or omit
|
||||
// to use <root>/tsconfig.json by default
|
||||
// use <root>/path/to/folder/tsconfig.json
|
||||
project: './tsconfig.json',
|
||||
},
|
||||
node: {
|
||||
extensions: ['.js', '.jsx', '.ts', '.tsx'],
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,89 @@
|
||||
# Univer Contributing Guide
|
||||
|
||||
## Tool
|
||||
|
||||
- vite
|
||||
- Typescript/tsx
|
||||
- Typescript references
|
||||
- pnpm workspace
|
||||
|
||||
## Project Introduction
|
||||
|
||||
For multi-package projects managed by lerna, there are plugins and cores in the packages directory, and examples are in the examples directory
|
||||
|
||||
## Develop
|
||||
|
||||
### Install dependencies
|
||||
|
||||
Node.js >= 14.19
|
||||
|
||||
```bash
|
||||
git clone http://github.com/dream-num/univer
|
||||
cd univer
|
||||
npm i -g pnpm # MacOS : sudo npm i -g pnpm
|
||||
npx playwright install
|
||||
pnmp install
|
||||
npm run dev
|
||||
```
|
||||
|
||||
### Command
|
||||
|
||||
Execute a command in a subpackage
|
||||
|
||||
```bash
|
||||
pnpm run --filter [package name] [command]
|
||||
```
|
||||
|
||||
For example, start the `dev` development mode of the `packages/sheets-plugin-sort` project
|
||||
|
||||
```bash
|
||||
pnpm run --filter @univer/sheets-plugin-sort dev
|
||||
|
||||
```
|
||||
|
||||
### Clean
|
||||
|
||||
If you encounter any npm installation problems, please try one-click reinstallation of dependencies first
|
||||
|
||||
```bash
|
||||
npm run clean
|
||||
```
|
||||
|
||||
### Plug-in development
|
||||
|
||||
1. Quickly generate plug-in template directory
|
||||
|
||||
```bash
|
||||
npm run cli
|
||||
```
|
||||
|
||||
2. For example, select the `plugin-temp` template and enter the plugin name `filter` to generate the `packages/sheets-plugin-filter` plugin.
|
||||
|
||||
3. Execute the following command to start the plug-in development mode
|
||||
|
||||
```bash
|
||||
pnpm run --filter @univer/sheets-plugin-filter dev
|
||||
```
|
||||
|
||||
4. There will be an additional `filter` plugin button in the toolbar on the interface
|
||||
|
||||
## Code comment
|
||||
|
||||
English is preferred, if the comment is longer, you can add bilingual
|
||||
|
||||
```js
|
||||
/*
|
||||
en: get result
|
||||
|
||||
zh: 得出结果
|
||||
*/
|
||||
function(){
|
||||
|
||||
}
|
||||
```
|
||||
|
||||
## Update a dependency package
|
||||
|
||||
```bash
|
||||
pnpm update
|
||||
```
|
||||
+98
@@ -0,0 +1,98 @@
|
||||
#ide
|
||||
*.DS_Store
|
||||
.idea
|
||||
# .vscode
|
||||
|
||||
#npm
|
||||
package-lock.json
|
||||
yarn.lock
|
||||
pnpm-lock.yaml
|
||||
|
||||
dist
|
||||
lib
|
||||
docs/.vuepress/dist
|
||||
|
||||
# Logs
|
||||
logs
|
||||
*.log
|
||||
npm-debug.log*
|
||||
yarn-debug.log*
|
||||
yarn-error.log*
|
||||
lerna-debug.log*
|
||||
|
||||
# Runtime config
|
||||
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
|
||||
|
||||
#lerna-changelog
|
||||
.changelog
|
||||
|
||||
#editor workspace file
|
||||
.idea/
|
||||
|
||||
.history
|
||||
# examples
|
||||
|
||||
screenshot
|
||||
|
||||
univer-custom-build
|
||||
universheet-custom-build
|
||||
|
||||
temp
|
||||
etc
|
||||
|
||||
# api extractor, api documenter
|
||||
docs/input
|
||||
docs/markdown
|
||||
doc
|
||||
@@ -0,0 +1,4 @@
|
||||
#!/usr/bin/env sh
|
||||
. "$(dirname -- "$0")/_/husky.sh"
|
||||
|
||||
# npm run lint
|
||||
@@ -0,0 +1,7 @@
|
||||
module.exports = {
|
||||
singleQuote: true,
|
||||
trailingComma: 'es5',
|
||||
tabWidth: 4,
|
||||
semi: true,
|
||||
printWidth: 180,
|
||||
};
|
||||
Vendored
+25
@@ -0,0 +1,25 @@
|
||||
{
|
||||
// Use IntelliSense to learn about possible attributes.
|
||||
// Hover to view descriptions of existing attributes.
|
||||
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
|
||||
"version": "0.2.0",
|
||||
"configurations": [
|
||||
{
|
||||
"type": "node",
|
||||
"name": "vscode-jest-tests",
|
||||
"request": "launch",
|
||||
"args": [
|
||||
"--runInBand",
|
||||
"--watchAll=false"
|
||||
],
|
||||
"cwd": "${workspaceFolder}",
|
||||
"console": "integratedTerminal",
|
||||
"internalConsoleOptions": "neverOpen",
|
||||
"disableOptimisticBPs": true,
|
||||
"program": "${workspaceFolder}/node_modules/.bin/jest",
|
||||
"windows": {
|
||||
"program": "${workspaceFolder}/node_modules/jest/bin/jest"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
Vendored
+64
@@ -0,0 +1,64 @@
|
||||
{
|
||||
"prettier.eslintIntegration": true,
|
||||
"editor.formatOnSave": true,
|
||||
"editor.codeActionsOnSave": {
|
||||
"source.fixAll.eslint": true
|
||||
},
|
||||
"editor.defaultFormatter": "esbenp.prettier-vscode",
|
||||
"commentTranslate.targetLanguage": "zh-CN",
|
||||
"[html]": {
|
||||
"editor.defaultFormatter": "vscode.html-language-features"
|
||||
},
|
||||
"commentTranslate.hover.enabled": true,
|
||||
"commentTranslate.source": "Google",
|
||||
|
||||
"cSpell.words": [
|
||||
"Bandings",
|
||||
"Catmull",
|
||||
"clazz",
|
||||
"codelf",
|
||||
"compositionend",
|
||||
"compositionstart",
|
||||
"compositionupdate",
|
||||
"CRDT",
|
||||
"csstype",
|
||||
"customd",
|
||||
"Datas",
|
||||
"esbuild",
|
||||
"evented",
|
||||
"execa",
|
||||
"FONTFACE",
|
||||
"fract",
|
||||
"gainsboro",
|
||||
"Gridlines",
|
||||
"Hanalei",
|
||||
"hdmx",
|
||||
"Heiti",
|
||||
"Hiragino",
|
||||
"ilvl",
|
||||
"Kaiti",
|
||||
"Lerp",
|
||||
"Liti",
|
||||
"universheet",
|
||||
"mengshukeji",
|
||||
"Overlines",
|
||||
"Pacifico",
|
||||
"pnmp",
|
||||
"ponyfill",
|
||||
"preact",
|
||||
"PWDEBUG",
|
||||
"Quan",
|
||||
"Sider",
|
||||
"SUMIF",
|
||||
"Tahoma",
|
||||
"univer",
|
||||
"universheet",
|
||||
"Unmerge",
|
||||
"Verdana",
|
||||
"viewports",
|
||||
"Xingkai",
|
||||
"Xinwei"
|
||||
],
|
||||
"javascript.preferences.importModuleSpecifier": "relative",
|
||||
"typescript.preferences.importModuleSpecifier": "relative"
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2020-present, DreamNum
|
||||
|
||||
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.
|
||||
+133
@@ -0,0 +1,133 @@
|
||||
# Univer
|
||||
|
||||
##
|
||||
|
||||
简体中文 | [English](./README.md)
|
||||
|
||||
## 介绍
|
||||
|
||||
🚀Univer,原 [Luckysheet 2.0](https://github.com/dream-num/Luckysheet) 升级。
|
||||
|
||||
> ⚠️该项目仍在开发中,仅用于测试和学习,不得用于生产
|
||||
|
||||
## 开发
|
||||
|
||||
### 环境
|
||||
|
||||
[Node.js](https://nodejs.org/en/) Version >= 14.19
|
||||
|
||||
|
||||
### 安装
|
||||
```
|
||||
git clone http://github.com/dream-num/univer
|
||||
cd univer
|
||||
npm i -g pnpm # MacOS : sudo npm i -g pnpm
|
||||
npx playwright install
|
||||
pnmp i
|
||||
```
|
||||
### 开发
|
||||
```
|
||||
npm run dev
|
||||
```
|
||||
|
||||
更多开发教程请参考 [贡献指南](./.github/contributing-zh.md)。
|
||||
|
||||
## 问题反馈
|
||||
|
||||
请到 [Issues](http://github.com/dream-num/univer/issues) 提交问题。
|
||||
|
||||
## 开发计划
|
||||
|
||||
### Sheets
|
||||
|
||||
- 基础能力
|
||||
- [x] 核心数据结构
|
||||
- [x] 渲染
|
||||
- [x] 界面
|
||||
- [x] 单元格编辑
|
||||
|
||||
- sheet操作
|
||||
- [x] sheet删除
|
||||
- [x] sheet复制
|
||||
- [x] sheet排序
|
||||
- [x] sheet重命名
|
||||
- [x] sheet更改颜色
|
||||
- [x] sheet隐藏
|
||||
- [x] sheet取消隐藏
|
||||
- [x] sheet向左移
|
||||
- [x] sheet向右移
|
||||
|
||||
- 右击菜单
|
||||
- [x] 复制
|
||||
- [x] 粘贴
|
||||
- [x] 插入行
|
||||
- [x] 插入列
|
||||
- [x] 删除选中行
|
||||
- [x] 删除选中列
|
||||
- [x] 删除单元格
|
||||
- [x] 清除内容
|
||||
|
||||
- 工具栏
|
||||
- [x] 撤销
|
||||
- [x] 重做
|
||||
- [ ] 格式刷
|
||||
- [ ] 货币格式
|
||||
- [ ] 百分比格式
|
||||
- [ ] 减少小数位数
|
||||
- [ ] 增加小数位数
|
||||
- [ ] 更多格式
|
||||
- [x] 字体
|
||||
- [x] 字体大小
|
||||
- [x] 加粗
|
||||
- [x] 斜体
|
||||
- [x] 删除线
|
||||
- [x] 下划线
|
||||
- [x] 文本颜色
|
||||
- [x] 单元格颜色
|
||||
- [x] 边框
|
||||
- [x] 合并单元格
|
||||
- [x] 水平对齐
|
||||
- [x] 垂直对齐
|
||||
- [x] 文本换行
|
||||
- [x] 文本旋转
|
||||
|
||||
- 计数栏
|
||||
- [x] 计数
|
||||
- [x] 缩放
|
||||
|
||||
|
||||
- 插件
|
||||
- [x] 剪切板
|
||||
- [ ] 单元格格式
|
||||
- [ ] 公式
|
||||
- [ ] 图片
|
||||
- [ ] 冻结
|
||||
- [ ] 链接
|
||||
- [ ] 批注
|
||||
- [ ] 数据透视表
|
||||
- [ ] 图表
|
||||
- [ ] 排序
|
||||
- [ ] 筛选
|
||||
- [ ] 条件格式
|
||||
- [ ] 交替颜色
|
||||
- [ ] 数据验证
|
||||
- [ ] 分列
|
||||
- [ ] 截图
|
||||
- [ ] 查找
|
||||
- [ ] 替换
|
||||
- [ ] 工作表保护
|
||||
- [ ] 打印
|
||||
- [ ] 导入导出
|
||||
- [ ] 协同
|
||||
### Docs
|
||||
|
||||
- [x] 渲染
|
||||
- [ ] 界面
|
||||
- [ ] 待定
|
||||
|
||||
### Slides
|
||||
|
||||
- [ ] 渲染
|
||||
- [ ] 界面
|
||||
- [ ] 待定
|
||||
|
||||
@@ -0,0 +1,131 @@
|
||||
# Univer
|
||||
|
||||
English| [简体中文](./README-zh.md)
|
||||
|
||||
## Introduction
|
||||
|
||||
Univer,[Luckysheet 2.0](https://github.com/dream-num/luckysheet) upgrade version.
|
||||
|
||||
> ⚠️ This project is still in development, only for testing and learning, not for production
|
||||
|
||||
## Development
|
||||
|
||||
### Requirements
|
||||
|
||||
[Node.js](https://nodejs.org/en/) Version >= 14.19
|
||||
|
||||
|
||||
### Installation
|
||||
````
|
||||
git clone http://github.com/dream-num/univer
|
||||
cd univer
|
||||
npm i -g pnpm # MacOS : sudo npm i -g pnpm
|
||||
npx playwright install
|
||||
pnmp i
|
||||
````
|
||||
### Development
|
||||
````
|
||||
npm run dev
|
||||
````
|
||||
|
||||
For more development tutorials, please refer to [Contribution Guide](./.github/contributing.md).
|
||||
|
||||
## Issues
|
||||
|
||||
Please file an issue at [Issues](http://github.com/dream-num/univer/issues).
|
||||
|
||||
## Development Plan
|
||||
|
||||
### Sheets
|
||||
|
||||
- Basic ability
|
||||
- [x] core data structures
|
||||
- [x] render
|
||||
- [x] UI
|
||||
- [x] cell editing
|
||||
|
||||
- Sheet operation
|
||||
- [x] sheet delete
|
||||
- [x] sheet copy
|
||||
- [x] sheet sort
|
||||
- [x] sheet rename
|
||||
- [x] sheet change color
|
||||
- [x] sheet hide
|
||||
- [x] sheet unhide
|
||||
- [x] sheet move left
|
||||
- [x] sheet moves right
|
||||
|
||||
- Right click menu
|
||||
- [x] copy
|
||||
- [x] paste
|
||||
- [x] insert row
|
||||
- [x] insert column
|
||||
- [x] delete selected rows
|
||||
- [x] delete selected columns
|
||||
- [x] delete cell
|
||||
- [x] clear content
|
||||
|
||||
- Toolbar
|
||||
- [x] undo
|
||||
- [x] redo
|
||||
- [ ] formatter
|
||||
- [ ] currency format
|
||||
- [ ] percent format
|
||||
- [ ] Decrease decimal places
|
||||
- [ ] increase the number of decimal places
|
||||
- [ ] more formats
|
||||
- [x] font family
|
||||
- [x] font size
|
||||
- [x] bold
|
||||
- [x] italic
|
||||
- [x] strikethrough
|
||||
- [x] underscore
|
||||
- [x] text color
|
||||
- [x] fill color
|
||||
- [x] border
|
||||
- [x] merge cells
|
||||
- [x] horizontal alignment
|
||||
- [x] vertical alignment
|
||||
- [x] text wrap
|
||||
- [x] text rotation
|
||||
|
||||
- Count bar
|
||||
- [x] count
|
||||
- [x] zoom
|
||||
|
||||
|
||||
- Plugins
|
||||
- [x] clipboard
|
||||
- [ ] format
|
||||
- [ ] formula
|
||||
- [ ] image
|
||||
- [ ] Frozen
|
||||
- [ ] link
|
||||
- [ ] comment
|
||||
- [ ] pivot table
|
||||
- [ ] chart
|
||||
- [ ] sort
|
||||
- [ ] filter
|
||||
- [ ] conditional format
|
||||
- [ ] alternating colors
|
||||
- [ ] data validation
|
||||
- [ ] split column
|
||||
- [ ] screenshot
|
||||
- [ ] find
|
||||
- [ ] replace
|
||||
- [ ] protection
|
||||
- [ ] print
|
||||
- [ ] import and export
|
||||
- [ ] collaboration
|
||||
|
||||
### Docs
|
||||
|
||||
- [x] render
|
||||
- [ ] UI
|
||||
- [ ] Pending
|
||||
|
||||
### Slides
|
||||
|
||||
- [ ] render
|
||||
- [ ] UI
|
||||
- [ ] Pending
|
||||
@@ -0,0 +1,380 @@
|
||||
/**
|
||||
* Config file for API Extractor. For more info, please visit: https://api-extractor.com
|
||||
*/
|
||||
{
|
||||
"$schema": "https://developer.microsoft.com/json-schemas/api-extractor/v7/api-extractor.schema.json",
|
||||
|
||||
/**
|
||||
* Optionally specifies another JSON config file that this file extends from. This provides a way for
|
||||
* standard settings to be shared across multiple projects.
|
||||
*
|
||||
* If the path starts with "./" or "../", the path is resolved relative to the folder of the file that contains
|
||||
* the "extends" field. Otherwise, the first path segment is interpreted as an NPM package name, and will be
|
||||
* resolved using NodeJS require().
|
||||
*
|
||||
* SUPPORTED TOKENS: none
|
||||
* DEFAULT VALUE: ""
|
||||
*/
|
||||
// "extends": "./shared/api-extractor-base.json"
|
||||
// "extends": "my-package/include/api-extractor-base.json"
|
||||
|
||||
/**
|
||||
* Determines the "<projectFolder>" token that can be used with other config file settings. The project folder
|
||||
* typically contains the tsconfig.json and package.json config files, but the path is user-defined.
|
||||
*
|
||||
* The path is resolved relative to the folder of the config file that contains the setting.
|
||||
*
|
||||
* The default value for "projectFolder" is the token "<lookup>", which means the folder is determined by traversing
|
||||
* parent folders, starting from the folder containing api-extractor.json, and stopping at the first folder
|
||||
* that contains a tsconfig.json file. If a tsconfig.json file cannot be found in this way, then an error
|
||||
* will be reported.
|
||||
*
|
||||
* SUPPORTED TOKENS: <lookup>
|
||||
* DEFAULT VALUE: "<lookup>"
|
||||
*/
|
||||
// "projectFolder": "..",
|
||||
|
||||
/**
|
||||
* (REQUIRED) Specifies the .d.ts file to be used as the starting point for analysis. API Extractor
|
||||
* analyzes the symbols exported by this module.
|
||||
*
|
||||
* The file extension must be ".d.ts" and not ".ts".
|
||||
*
|
||||
* The path is resolved relative to the folder of the config file that contains the setting; to change this,
|
||||
* prepend a folder token such as "<projectFolder>".
|
||||
*
|
||||
* SUPPORTED TOKENS: <projectFolder>, <packageName>, <unscopedPackageName>
|
||||
*/
|
||||
"mainEntryPointFilePath": "<projectFolder>/lib/src/index.d.ts",
|
||||
|
||||
/**
|
||||
* A list of NPM package names whose exports should be treated as part of this package.
|
||||
*
|
||||
* For example, suppose that Webpack is used to generate a distributed bundle for the project "library1",
|
||||
* and another NPM package "library2" is embedded in this bundle. Some types from library2 may become part
|
||||
* of the exported API for library1, but by default API Extractor would generate a .d.ts rollup that explicitly
|
||||
* imports library2. To avoid this, we can specify:
|
||||
*
|
||||
* "bundledPackages": [ "library2" ],
|
||||
*
|
||||
* This would direct API Extractor to embed those types directly in the .d.ts rollup, as if they had been
|
||||
* local files for library1.
|
||||
*/
|
||||
"bundledPackages": [],
|
||||
|
||||
/**
|
||||
* Determines how the TypeScript compiler engine will be invoked by API Extractor.
|
||||
*/
|
||||
"compiler": {
|
||||
/**
|
||||
* Specifies the path to the tsconfig.json file to be used by API Extractor when analyzing the project.
|
||||
*
|
||||
* The path is resolved relative to the folder of the config file that contains the setting; to change this,
|
||||
* prepend a folder token such as "<projectFolder>".
|
||||
*
|
||||
* Note: This setting will be ignored if "overrideTsconfig" is used.
|
||||
*
|
||||
* SUPPORTED TOKENS: <projectFolder>, <packageName>, <unscopedPackageName>
|
||||
* DEFAULT VALUE: "<projectFolder>/tsconfig.json"
|
||||
*/
|
||||
// "tsconfigFilePath": "<projectFolder>/tsconfig.json",
|
||||
/**
|
||||
* Provides a compiler configuration that will be used instead of reading the tsconfig.json file from disk.
|
||||
* The object must conform to the TypeScript tsconfig schema:
|
||||
*
|
||||
* http://json.schemastore.org/tsconfig
|
||||
*
|
||||
* If omitted, then the tsconfig.json file will be read from the "projectFolder".
|
||||
*
|
||||
* DEFAULT VALUE: no overrideTsconfig section
|
||||
*/
|
||||
// "overrideTsconfig": {
|
||||
// . . .
|
||||
// }
|
||||
/**
|
||||
* This option causes the compiler to be invoked with the --skipLibCheck option. This option is not recommended
|
||||
* and may cause API Extractor to produce incomplete or incorrect declarations, but it may be required when
|
||||
* dependencies contain declarations that are incompatible with the TypeScript engine that API Extractor uses
|
||||
* for its analysis. Where possible, the underlying issue should be fixed rather than relying on skipLibCheck.
|
||||
*
|
||||
* DEFAULT VALUE: false
|
||||
*/
|
||||
// "skipLibCheck": true,
|
||||
},
|
||||
|
||||
/**
|
||||
* Configures how the API report file (*.api.md) will be generated.
|
||||
*/
|
||||
"apiReport": {
|
||||
/**
|
||||
* (REQUIRED) Whether to generate an API report.
|
||||
*/
|
||||
"enabled": true,
|
||||
|
||||
/**
|
||||
* The filename for the API report files. It will be combined with "reportFolder" or "reportTempFolder" to produce
|
||||
* a full file path.
|
||||
*
|
||||
* The file extension should be ".api.md", and the string should not contain a path separator such as "\" or "/".
|
||||
*
|
||||
* SUPPORTED TOKENS: <packageName>, <unscopedPackageName>
|
||||
* DEFAULT VALUE: "<unscopedPackageName>.api.md"
|
||||
*/
|
||||
// "reportFileName": "<unscopedPackageName>.api.md",
|
||||
|
||||
/**
|
||||
* Specifies the folder where the API report file is written. The file name portion is determined by
|
||||
* the "reportFileName" setting.
|
||||
*
|
||||
* The API report file is normally tracked by Git. Changes to it can be used to trigger a branch policy,
|
||||
* e.g. for an API review.
|
||||
*
|
||||
* The path is resolved relative to the folder of the config file that contains the setting; to change this,
|
||||
* prepend a folder token such as "<projectFolder>".
|
||||
*
|
||||
* SUPPORTED TOKENS: <projectFolder>, <packageName>, <unscopedPackageName>
|
||||
* DEFAULT VALUE: "<projectFolder>/etc/"
|
||||
*/
|
||||
"reportFolder": "<projectFolder>/etc/"
|
||||
|
||||
/**
|
||||
* Specifies the folder where the temporary report file is written. The file name portion is determined by
|
||||
* the "reportFileName" setting.
|
||||
*
|
||||
* After the temporary file is written to disk, it is compared with the file in the "reportFolder".
|
||||
* If they are different, a production build will fail.
|
||||
*
|
||||
* The path is resolved relative to the folder of the config file that contains the setting; to change this,
|
||||
* prepend a folder token such as "<projectFolder>".
|
||||
*
|
||||
* SUPPORTED TOKENS: <projectFolder>, <packageName>, <unscopedPackageName>
|
||||
* DEFAULT VALUE: "<projectFolder>/temp/"
|
||||
*/
|
||||
// "reportTempFolder": "<projectFolder>/temp/"
|
||||
},
|
||||
|
||||
/**
|
||||
* Configures how the doc model file (*.api.json) will be generated.
|
||||
*/
|
||||
"docModel": {
|
||||
/**
|
||||
* (REQUIRED) Whether to generate a doc model file.
|
||||
*/
|
||||
"enabled": true
|
||||
|
||||
/**
|
||||
* The output path for the doc model file. The file extension should be ".api.json".
|
||||
*
|
||||
* The path is resolved relative to the folder of the config file that contains the setting; to change this,
|
||||
* prepend a folder token such as "<projectFolder>".
|
||||
*
|
||||
* SUPPORTED TOKENS: <projectFolder>, <packageName>, <unscopedPackageName>
|
||||
* DEFAULT VALUE: "<projectFolder>/temp/<unscopedPackageName>.api.json"
|
||||
*/
|
||||
// "apiJsonFilePath": "<projectFolder>/temp/<unscopedPackageName>.api.json"
|
||||
},
|
||||
|
||||
/**
|
||||
* Configures how the .d.ts rollup file will be generated.
|
||||
*/
|
||||
"dtsRollup": {
|
||||
/**
|
||||
* (REQUIRED) Whether to generate the .d.ts rollup file.
|
||||
*/
|
||||
"enabled": true
|
||||
|
||||
/**
|
||||
* Specifies the output path for a .d.ts rollup file to be generated without any trimming.
|
||||
* This file will include all declarations that are exported by the main entry point.
|
||||
*
|
||||
* If the path is an empty string, then this file will not be written.
|
||||
*
|
||||
* The path is resolved relative to the folder of the config file that contains the setting; to change this,
|
||||
* prepend a folder token such as "<projectFolder>".
|
||||
*
|
||||
* SUPPORTED TOKENS: <projectFolder>, <packageName>, <unscopedPackageName>
|
||||
* DEFAULT VALUE: "<projectFolder>/dist/<unscopedPackageName>.d.ts"
|
||||
*/
|
||||
// "untrimmedFilePath": "<projectFolder>/dist/<unscopedPackageName>.d.ts",
|
||||
|
||||
/**
|
||||
* Specifies the output path for a .d.ts rollup file to be generated with trimming for an "alpha" release.
|
||||
* This file will include only declarations that are marked as "@public", "@beta", or "@alpha".
|
||||
*
|
||||
* The path is resolved relative to the folder of the config file that contains the setting; to change this,
|
||||
* prepend a folder token such as "<projectFolder>".
|
||||
*
|
||||
* SUPPORTED TOKENS: <projectFolder>, <packageName>, <unscopedPackageName>
|
||||
* DEFAULT VALUE: ""
|
||||
*/
|
||||
// "alphaTrimmedFilePath": "<projectFolder>/dist/<unscopedPackageName>-alpha.d.ts",
|
||||
|
||||
/**
|
||||
* Specifies the output path for a .d.ts rollup file to be generated with trimming for a "beta" release.
|
||||
* This file will include only declarations that are marked as "@public" or "@beta".
|
||||
*
|
||||
* The path is resolved relative to the folder of the config file that contains the setting; to change this,
|
||||
* prepend a folder token such as "<projectFolder>".
|
||||
*
|
||||
* SUPPORTED TOKENS: <projectFolder>, <packageName>, <unscopedPackageName>
|
||||
* DEFAULT VALUE: ""
|
||||
*/
|
||||
// "betaTrimmedFilePath": "<projectFolder>/dist/<unscopedPackageName>-beta.d.ts",
|
||||
|
||||
/**
|
||||
* Specifies the output path for a .d.ts rollup file to be generated with trimming for a "public" release.
|
||||
* This file will include only declarations that are marked as "@public".
|
||||
*
|
||||
* If the path is an empty string, then this file will not be written.
|
||||
*
|
||||
* The path is resolved relative to the folder of the config file that contains the setting; to change this,
|
||||
* prepend a folder token such as "<projectFolder>".
|
||||
*
|
||||
* SUPPORTED TOKENS: <projectFolder>, <packageName>, <unscopedPackageName>
|
||||
* DEFAULT VALUE: ""
|
||||
*/
|
||||
// "publicTrimmedFilePath": "<projectFolder>/dist/<unscopedPackageName>-public.d.ts",
|
||||
|
||||
/**
|
||||
* When a declaration is trimmed, by default it will be replaced by a code comment such as
|
||||
* "Excluded from this release type: exampleMember". Set "omitTrimmingComments" to true to remove the
|
||||
* declaration completely.
|
||||
*
|
||||
* DEFAULT VALUE: false
|
||||
*/
|
||||
// "omitTrimmingComments": true
|
||||
},
|
||||
|
||||
/**
|
||||
* Configures how the tsdoc-metadata.json file will be generated.
|
||||
*/
|
||||
"tsdocMetadata": {
|
||||
/**
|
||||
* Whether to generate the tsdoc-metadata.json file.
|
||||
*
|
||||
* DEFAULT VALUE: true
|
||||
*/
|
||||
// "enabled": true,
|
||||
/**
|
||||
* Specifies where the TSDoc metadata file should be written.
|
||||
*
|
||||
* The path is resolved relative to the folder of the config file that contains the setting; to change this,
|
||||
* prepend a folder token such as "<projectFolder>".
|
||||
*
|
||||
* The default value is "<lookup>", which causes the path to be automatically inferred from the "tsdocMetadata",
|
||||
* "typings" or "main" fields of the project's package.json. If none of these fields are set, the lookup
|
||||
* falls back to "tsdoc-metadata.json" in the package folder.
|
||||
*
|
||||
* SUPPORTED TOKENS: <projectFolder>, <packageName>, <unscopedPackageName>
|
||||
* DEFAULT VALUE: "<lookup>"
|
||||
*/
|
||||
// "tsdocMetadataFilePath": "<projectFolder>/dist/tsdoc-metadata.json"
|
||||
},
|
||||
|
||||
/**
|
||||
* Specifies what type of newlines API Extractor should use when writing output files. By default, the output files
|
||||
* will be written with Windows-style newlines. To use POSIX-style newlines, specify "lf" instead.
|
||||
* To use the OS's default newline kind, specify "os".
|
||||
*
|
||||
* DEFAULT VALUE: "crlf"
|
||||
*/
|
||||
// "newlineKind": "crlf",
|
||||
|
||||
/**
|
||||
* Configures how API Extractor reports error and warning messages produced during analysis.
|
||||
*
|
||||
* There are three sources of messages: compiler messages, API Extractor messages, and TSDoc messages.
|
||||
*/
|
||||
"messages": {
|
||||
/**
|
||||
* Configures handling of diagnostic messages reported by the TypeScript compiler engine while analyzing
|
||||
* the input .d.ts files.
|
||||
*
|
||||
* TypeScript message identifiers start with "TS" followed by an integer. For example: "TS2551"
|
||||
*
|
||||
* DEFAULT VALUE: A single "default" entry with logLevel=warning.
|
||||
*/
|
||||
"compilerMessageReporting": {
|
||||
/**
|
||||
* Configures the default routing for messages that don't match an explicit rule in this table.
|
||||
*/
|
||||
"default": {
|
||||
/**
|
||||
* Specifies whether the message should be written to the the tool's output log. Note that
|
||||
* the "addToApiReportFile" property may supersede this option.
|
||||
*
|
||||
* Possible values: "error", "warning", "none"
|
||||
*
|
||||
* Errors cause the build to fail and return a nonzero exit code. Warnings cause a production build fail
|
||||
* and return a nonzero exit code. For a non-production build (e.g. when "api-extractor run" includes
|
||||
* the "--local" option), the warning is displayed but the build will not fail.
|
||||
*
|
||||
* DEFAULT VALUE: "warning"
|
||||
*/
|
||||
"logLevel": "warning"
|
||||
|
||||
/**
|
||||
* When addToApiReportFile is true: If API Extractor is configured to write an API report file (.api.md),
|
||||
* then the message will be written inside that file; otherwise, the message is instead logged according to
|
||||
* the "logLevel" option.
|
||||
*
|
||||
* DEFAULT VALUE: false
|
||||
*/
|
||||
// "addToApiReportFile": false
|
||||
}
|
||||
|
||||
// "TS2551": {
|
||||
// "logLevel": "warning",
|
||||
// "addToApiReportFile": true
|
||||
// },
|
||||
//
|
||||
// . . .
|
||||
},
|
||||
|
||||
/**
|
||||
* Configures handling of messages reported by API Extractor during its analysis.
|
||||
*
|
||||
* API Extractor message identifiers start with "ae-". For example: "ae-extra-release-tag"
|
||||
*
|
||||
* DEFAULT VALUE: See api-extractor-defaults.json for the complete table of extractorMessageReporting mappings
|
||||
*/
|
||||
"extractorMessageReporting": {
|
||||
// "default": {
|
||||
// "logLevel": "warning"
|
||||
// // "addToApiReportFile": false
|
||||
// },
|
||||
"ae-forgotten-export": {
|
||||
"logLevel": "warning",
|
||||
"addToApiReportFile": true
|
||||
}
|
||||
|
||||
// "ae-extra-release-tag": {
|
||||
// "logLevel": "warning",
|
||||
// "addToApiReportFile": true
|
||||
// },
|
||||
//
|
||||
// . . .
|
||||
},
|
||||
|
||||
/**
|
||||
* Configures handling of messages reported by the TSDoc parser when analyzing code comments.
|
||||
*
|
||||
* TSDoc message identifiers start with "tsdoc-". For example: "tsdoc-link-tag-unescaped-text"
|
||||
*
|
||||
* DEFAULT VALUE: A single "default" entry with logLevel=warning.
|
||||
*/
|
||||
"tsdocMessageReporting": {
|
||||
"default": {
|
||||
"logLevel": "warning"
|
||||
// "addToApiReportFile": false
|
||||
}
|
||||
|
||||
// "tsdoc-link-tag-unescaped-text": {
|
||||
// "logLevel": "warning",
|
||||
// "addToApiReportFile": true
|
||||
// },
|
||||
//
|
||||
// . . .
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
# Univer CLI Tool
|
||||
|
||||
## Usage
|
||||
|
||||
Install dependency
|
||||
|
||||
```sh
|
||||
npm i -g @univer/cli
|
||||
```
|
||||
|
||||
### Create Plugin
|
||||
Create a Univer plugin named `my-plugin` from a template
|
||||
|
||||
```sh
|
||||
univer-cli create my-plugin
|
||||
```
|
||||
|
||||
start develop plugin
|
||||
```sh
|
||||
cd my-plugin
|
||||
npm i
|
||||
npm run dev
|
||||
```
|
||||
|
||||
### Custom Build
|
||||
|
||||
|
||||
```sh
|
||||
univer-cli build --include sort comment
|
||||
```
|
||||
|
||||
## API
|
||||
|
||||
### Create
|
||||
|
||||
Command
|
||||
```sh
|
||||
univer-cli create <plugin> [inner]
|
||||
```
|
||||
|
||||
- plugin: Required parameters, specify a plugin name, Please use `param-case` format, such as `data-validation`
|
||||
- inner: Optional parameter, use this tag inside the Univer repository. With this flag set, we will put the plugin in the packages directory, otherwise we will create a new plugin in the current directory where the script is executed by default
|
||||
|
||||
### Build
|
||||
|
||||
### Init
|
||||
@@ -0,0 +1,44 @@
|
||||
{
|
||||
"name": "@univer/cli",
|
||||
"version": "1.0.26",
|
||||
"description": "Quickly build univer plugins, custom package univer cores and plugins",
|
||||
"main": "./src/index.ts",
|
||||
"module": "./src/index.ts",
|
||||
"types": "./src/type.d.ts",
|
||||
"publishConfig": {
|
||||
"main": "./lib/index.js",
|
||||
"module": "./lib/index.js",
|
||||
"types": "./lib/index.d.ts"
|
||||
},
|
||||
"scripts": {
|
||||
"dev": "tsc --project tsconfig.cli.json -w",
|
||||
"cli": "ts-node --project tsconfig.cli.json src/cli.ts",
|
||||
"build": "shx rm -rf lib/* && npx tsc --project tsconfig.cli.json && shx cp -r src/templates lib/templates"
|
||||
},
|
||||
"author": "DreamNum <msoffice2@126.com>",
|
||||
"license": "MIT",
|
||||
"files": [
|
||||
"package.json",
|
||||
"lib"
|
||||
],
|
||||
"dependencies": {
|
||||
"chalk": "4.1.2",
|
||||
"commander": "^9.0.0",
|
||||
"ejs": "^3.0.2",
|
||||
"execa": "^4.1.0",
|
||||
"inquirer": "^7.1.0",
|
||||
"shelljs": "^0.8.4",
|
||||
"shx": "^0.3.4"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/ejs": "^3.0.2",
|
||||
"@types/inquirer": "^6.5.0",
|
||||
"@types/node": "^13.11.1",
|
||||
"@types/shelljs": "^0.8.7",
|
||||
"ts-node": "^10.2.1",
|
||||
"typescript": "^4.4.1-rc"
|
||||
},
|
||||
"bin": {
|
||||
"univer-cli": "./lib/cli.js"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,182 @@
|
||||
#!/usr/bin/env node
|
||||
|
||||
import * as fs from 'fs';
|
||||
import * as path from 'path';
|
||||
import shell from 'shelljs';
|
||||
import { FgGreen, FgRed, Reset } from './utils/color';
|
||||
const execa = require('execa');
|
||||
import { renderContent } from './utils/template';
|
||||
import { generateRandomId } from './utils/tool';
|
||||
import { IEventBus } from './utils/event-bus';
|
||||
import { exec } from 'child_process';
|
||||
|
||||
// TODO 提供clear目录方法,用于下载完后删除项目
|
||||
// dynamic 模式
|
||||
|
||||
interface IOption {
|
||||
all?: boolean;
|
||||
include?: string[];
|
||||
exclude?: string[];
|
||||
}
|
||||
|
||||
export interface IBuildJson {
|
||||
[key: string]: string;
|
||||
}
|
||||
|
||||
export interface IObj {
|
||||
msg: string;
|
||||
}
|
||||
|
||||
type PublishType = [IObj, number];
|
||||
|
||||
const defaultBuildList: IBuildJson = {
|
||||
filter: '//',
|
||||
sort: '//',
|
||||
alternatingColors: '//',
|
||||
comment: '//',
|
||||
};
|
||||
|
||||
const allBuildList: IBuildJson = {
|
||||
filter: ' ',
|
||||
sort: ' ',
|
||||
alternatingColors: ' ',
|
||||
comment: ' ',
|
||||
};
|
||||
|
||||
const CURR_DIR = process.cwd();
|
||||
|
||||
interface ILibOptions {
|
||||
eventBus: IEventBus;
|
||||
buildId: string;
|
||||
}
|
||||
|
||||
export function build(options: IOption, libOptions?: ILibOptions) {
|
||||
return new Promise((resolve, reject) => {
|
||||
const buildList: IBuildJson = filterBuild(options);
|
||||
const { eventBus, buildId } = libOptions || {};
|
||||
// When we provide nodejs interface, support library mode, create a new project directory with a random name to prevent directory conflicts from running by multiple users at the same time.
|
||||
const id = buildId ? buildId : '';
|
||||
const randomFolderName = 'univer-custom-build-' + id;
|
||||
|
||||
eventBus?.publish<PublishType>('progress', { msg: 'Pull template files' }, 0.1);
|
||||
|
||||
copyTemplate(randomFolderName);
|
||||
|
||||
eventBus?.publish<PublishType>('progress', { msg: 'Update custom configuration' }, 0.2);
|
||||
|
||||
updateEntry(buildList, randomFolderName);
|
||||
|
||||
eventBus?.publish<PublishType>('progress', { msg: 'Install dependencies' }, 0.3);
|
||||
|
||||
buildScript(resolve, reject, randomFolderName, eventBus);
|
||||
});
|
||||
}
|
||||
|
||||
function filterBuild(options: IOption): IBuildJson {
|
||||
const { all, include, exclude } = options;
|
||||
let filterBuildList: IBuildJson = defaultBuildList;
|
||||
|
||||
if (all) {
|
||||
filterBuildList = allBuildList;
|
||||
}
|
||||
|
||||
if (include) {
|
||||
filterBuildList = defaultBuildList;
|
||||
include.forEach((plugin) => {
|
||||
if (plugin in defaultBuildList) {
|
||||
filterBuildList[plugin] = ' ';
|
||||
}
|
||||
});
|
||||
}
|
||||
if (exclude) {
|
||||
filterBuildList = allBuildList;
|
||||
exclude.forEach((plugin) => {
|
||||
if (plugin in allBuildList) {
|
||||
filterBuildList[plugin] = '//';
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
return filterBuildList;
|
||||
}
|
||||
|
||||
function copyTemplate(folderName: string) {
|
||||
const templatePath = path.join(__dirname, 'templates/univer-custom-build');
|
||||
copyFolderRecursiveSync(templatePath, CURR_DIR);
|
||||
fs.rename(path.join(CURR_DIR, 'univer-custom-build'), path.join(CURR_DIR, folderName), () => {});
|
||||
}
|
||||
|
||||
function updateEntry(json: IBuildJson, folderName: string) {
|
||||
const entryFolder = path.join(CURR_DIR, folderName);
|
||||
const entryFile = path.join(entryFolder, 'index-template.ts');
|
||||
|
||||
// read file content and transform it using template engine
|
||||
let contents = fs.readFileSync(entryFile, 'utf8');
|
||||
|
||||
contents = renderContent(contents, json);
|
||||
|
||||
// write file to destination folder
|
||||
let writePath = path.join(entryFolder, 'src/index.custom.ts');
|
||||
fs.writeFileSync(writePath, contents, 'utf8');
|
||||
}
|
||||
|
||||
async function buildScript(resolve: Function, reject: Function, folderName: string, eventBus?: IEventBus) {
|
||||
shell.cd(folderName);
|
||||
// execa('cd', ['univer-custom-build'], { stdio: 'inherit' })
|
||||
// The host environment may be production, which will cause development dependencies to fail to be installed, reference https://docs.npmjs.com/cli/v8/commands/npm-install
|
||||
await execa('npm', ['i', '--production=false', '--prefer-offline'], { stdio: 'inherit' });
|
||||
|
||||
eventBus?.publish<PublishType>('progress', { msg: 'Build source code' }, 0.8);
|
||||
|
||||
try {
|
||||
await execa('npm', ['run', 'build'], { stdio: 'inherit' });
|
||||
console.log(`\n${FgGreen}Custom build success!${Reset} \n`);
|
||||
eventBus?.publish<PublishType>('progress', { msg: 'Build complete' }, 1.0);
|
||||
resolve('success');
|
||||
} catch (error) {
|
||||
console.error(`\n${FgRed}Custom build fail!${Reset} \n`);
|
||||
eventBus?.publish<PublishType>('progress', { msg: 'Build interrupt' }, 0);
|
||||
reject('fail');
|
||||
}
|
||||
}
|
||||
|
||||
function copyFileSync(source: string, target: string) {
|
||||
var targetFile = target;
|
||||
|
||||
// If target is a directory, a new file with the same name will be created
|
||||
if (fs.existsSync(target)) {
|
||||
if (fs.lstatSync(target).isDirectory()) {
|
||||
targetFile = path.join(target, path.basename(source));
|
||||
}
|
||||
}
|
||||
|
||||
fs.writeFileSync(targetFile, fs.readFileSync(source));
|
||||
}
|
||||
|
||||
/**
|
||||
* Reference https://stackoverflow.com/a/26038979
|
||||
* @param source
|
||||
* @param target
|
||||
*/
|
||||
function copyFolderRecursiveSync(source: string, target: string) {
|
||||
var files = [];
|
||||
|
||||
// Check if folder needs to be created or integrated
|
||||
var targetFolder = path.join(target, path.basename(source));
|
||||
if (!fs.existsSync(targetFolder)) {
|
||||
fs.mkdirSync(targetFolder);
|
||||
}
|
||||
|
||||
// Copy
|
||||
if (fs.lstatSync(source).isDirectory()) {
|
||||
files = fs.readdirSync(source);
|
||||
files.forEach(function (file) {
|
||||
var curSource = path.join(source, file);
|
||||
if (fs.lstatSync(curSource).isDirectory()) {
|
||||
copyFolderRecursiveSync(curSource, targetFolder);
|
||||
} else {
|
||||
copyFileSync(curSource, targetFolder);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
#!/usr/bin/env node
|
||||
|
||||
import { Command } from 'commander';
|
||||
import { build } from './build';
|
||||
import { create } from './create';
|
||||
const program = new Command();
|
||||
|
||||
program
|
||||
.command('build')
|
||||
.option('-a, --all', 'Package the core and all plugins together')
|
||||
.option('-i, --include <plugins...>', 'List plugins that need to be packaged')
|
||||
.option('-e, --exclude <plugins...>', 'List plugins that do not need to be packaged')
|
||||
.description('Package the core and plugins together,core and base plugins are packaged by default')
|
||||
.action((options) => {
|
||||
build(options);
|
||||
});
|
||||
|
||||
// TODO:check npm package name conflict
|
||||
program
|
||||
.command('create <plugin> [inner]')
|
||||
.description('Create a Univer plugin from a template')
|
||||
.action((plugin) => {
|
||||
create(plugin);
|
||||
});
|
||||
|
||||
program.parse(process.argv);
|
||||
@@ -0,0 +1,169 @@
|
||||
#!/usr/bin/env node
|
||||
|
||||
/**
|
||||
* Quickly generate plug-in directory
|
||||
*
|
||||
* Reference from https://github.com/DuwainevanDriel/project-template-generator
|
||||
*/
|
||||
|
||||
import chalk from 'chalk';
|
||||
import * as fs from 'fs';
|
||||
import * as path from 'path';
|
||||
import * as template from './utils/template';
|
||||
interface CliOptions {
|
||||
projectName: string;
|
||||
templateName: string;
|
||||
templatePath: string;
|
||||
tartgetPath: string;
|
||||
}
|
||||
|
||||
// interface IOptions {
|
||||
// inner?: boolean;
|
||||
// }
|
||||
export function create(plugin: string) {
|
||||
console.log('plugin create', plugin);
|
||||
|
||||
const cliOptions: CliOptions = {
|
||||
//@ts-ignore
|
||||
projectName: '',
|
||||
//@ts-ignore
|
||||
templateName: '',
|
||||
templatePath: '',
|
||||
tartgetPath: '',
|
||||
};
|
||||
|
||||
const SKIP_FILES = ['node_modules', '.template.json'];
|
||||
|
||||
const CURR_DIR = process.cwd();
|
||||
const inner = process.argv[4];
|
||||
|
||||
let DESTINATION_DIR = '';
|
||||
|
||||
if (inner === 'inner') {
|
||||
// core repository create plugin
|
||||
DESTINATION_DIR = path.join(CURR_DIR, '../packages');
|
||||
} else {
|
||||
// cli
|
||||
DESTINATION_DIR = path.join(CURR_DIR, '');
|
||||
}
|
||||
|
||||
const TEMP_PLUGIN_NAME = 'Sort';
|
||||
|
||||
const projectChoice = 'plugin-temp';
|
||||
const projectValue = covertToCamelCase(plugin);
|
||||
const projectUpperValue = covertToPascalCase(projectValue);
|
||||
const projectName = covertToParamCase(projectValue);
|
||||
|
||||
//@ts-ignore
|
||||
const templatePath = path.join(__dirname, 'templates', projectChoice);
|
||||
|
||||
// sheets-plugin-data-validation => sheets-plugin-data-validation
|
||||
//@ts-ignore
|
||||
const tartgetPath = path.join(DESTINATION_DIR, projectName);
|
||||
|
||||
cliOptions.projectName = projectName;
|
||||
cliOptions.templateName = projectChoice;
|
||||
cliOptions.templatePath = templatePath;
|
||||
cliOptions.tartgetPath = tartgetPath;
|
||||
|
||||
if (!createProject(tartgetPath)) {
|
||||
return;
|
||||
}
|
||||
|
||||
//@ts-ignore
|
||||
createDirectoryContents(templatePath, projectName, cliOptions);
|
||||
|
||||
// postProcess(cliOptions);
|
||||
devTips(projectName);
|
||||
|
||||
function createDirectoryContents(templatePath: string, projectName: string) {
|
||||
// read all files/folders (1 level) from template folder
|
||||
const filesToCreate = fs.readdirSync(templatePath);
|
||||
// loop each file/folder
|
||||
filesToCreate.forEach((file) => {
|
||||
const origFilePath = path.join(templatePath, file);
|
||||
|
||||
// get stats about the current file
|
||||
const stats = fs.statSync(origFilePath);
|
||||
|
||||
// skip files that should not be copied
|
||||
if (SKIP_FILES.indexOf(file) > -1) return;
|
||||
|
||||
if (stats.isFile()) {
|
||||
// read file content and transform it using template engine
|
||||
let contents = fs.readFileSync(origFilePath, 'utf8');
|
||||
|
||||
contents = template.render(contents, { projectValue, projectUpperValue, projectName: cliOptions.projectName });
|
||||
|
||||
// write file to destination folder
|
||||
let writePath = path.join(DESTINATION_DIR, projectName, file);
|
||||
|
||||
// change file name
|
||||
if (writePath.indexOf(TEMP_PLUGIN_NAME) > -1) {
|
||||
writePath = writePath.replace(TEMP_PLUGIN_NAME, projectUpperValue);
|
||||
}
|
||||
|
||||
fs.writeFileSync(writePath, contents, 'utf8');
|
||||
} else if (stats.isDirectory()) {
|
||||
// create folder in destination folder
|
||||
|
||||
let writeFolderPath = path.join(DESTINATION_DIR, projectName, file);
|
||||
|
||||
// change folder name (Not recommended. Because the directory of each plug-in should be the same)
|
||||
// if (writeFolderPath.indexOf(TEMP_PLUGIN_NAME) > -1) {
|
||||
// writeFolderPath = writeFolderPath.replace(TEMP_PLUGIN_NAME, projectUpperValue);
|
||||
// }
|
||||
|
||||
fs.mkdirSync(writeFolderPath);
|
||||
|
||||
// const destination = path.join(CURR_DIR, 'packages');
|
||||
// fs.mkdirSync(path.join(destination, projectName, file));
|
||||
// copy files/folder inside current folder recursively
|
||||
createDirectoryContents(path.join(templatePath, file), path.join(projectName, file));
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function createProject(projectPath: string) {
|
||||
if (fs.existsSync(projectPath)) {
|
||||
console.log(chalk.red(`Folder ${projectPath} exists. Delete or use another name.`));
|
||||
return false;
|
||||
}
|
||||
fs.mkdirSync(projectPath);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
function devTips(projectName: string) {
|
||||
// pnpm run --filter @univer/sheets-plugin-<%= projectValue %> dev
|
||||
console.log(chalk.green(`\nSuccess!\n`));
|
||||
console.log(chalk.white(`Install Dependencies: \n`, chalk.green(`pnpm i --filter @univer/${projectName}\n`)));
|
||||
console.log(chalk.white(`Develop: \n`, chalk.green(`pnpm run --filter @univer/${projectName} dev\n`)));
|
||||
}
|
||||
|
||||
function covertToPascalCase(str: string) {
|
||||
return str
|
||||
.replace(/\b\w/g, (match) => {
|
||||
return match.toUpperCase();
|
||||
})
|
||||
.replace(/-/g, '');
|
||||
}
|
||||
|
||||
function covertToParamCase(str: string, prefix = 'plugin') {
|
||||
return prefix + str.replace(/(-\w|[A-Z]|\b\w)/g, (match) => (match.indexOf('-') > -1 ? match.toLowerCase() : `-${match.toLowerCase()}`));
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* Reference: https://stackoverflow.com/a/2970667
|
||||
* @param str
|
||||
* @returns
|
||||
*/
|
||||
function covertToCamelCase(str: string) {
|
||||
return str
|
||||
.replace(/(?:\b\w)/g, function (match, index) {
|
||||
return index === 0 ? match.toLowerCase() : match.toUpperCase();
|
||||
})
|
||||
.replace(/-/g, '');
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
#!/usr/bin/env node
|
||||
|
||||
import { build, IObj } from './build';
|
||||
import { create } from './create';
|
||||
import { EventBus, IEventBus } from './utils/event-bus';
|
||||
|
||||
export { build, create, EventBus};
|
||||
export type {IObj,IEventBus}
|
||||
+166
@@ -0,0 +1,166 @@
|
||||
#!/usr/bin/env node
|
||||
|
||||
/**
|
||||
* Quickly generate plug-in directory
|
||||
*
|
||||
* Reference from https://github.com/DuwainevanDriel/project-template-generator
|
||||
*/
|
||||
|
||||
import chalk from 'chalk';
|
||||
import * as fs from 'fs';
|
||||
import * as inquirer from 'inquirer';
|
||||
import * as path from 'path';
|
||||
import * as template from './utils/template';
|
||||
interface CliOptions {
|
||||
projectName: string;
|
||||
templateName: string;
|
||||
templatePath: string;
|
||||
tartgetPath: string;
|
||||
}
|
||||
|
||||
interface IOptions {
|
||||
inner?: boolean;
|
||||
}
|
||||
export function init(options: IOptions) {
|
||||
console.log('template init', options);
|
||||
|
||||
const cliOptions: CliOptions = {
|
||||
//@ts-ignore
|
||||
projectName: '',
|
||||
//@ts-ignore
|
||||
templateName: '',
|
||||
templatePath: '',
|
||||
tartgetPath: '',
|
||||
};
|
||||
|
||||
const SKIP_FILES = ['node_modules', '.template.json'];
|
||||
|
||||
const CURR_DIR = process.cwd();
|
||||
|
||||
let DESTINATION_DIR = '';
|
||||
|
||||
if (options.inner == true) {
|
||||
// core repository create plugin
|
||||
DESTINATION_DIR = path.join(CURR_DIR, '../packages');
|
||||
} else {
|
||||
// cli
|
||||
DESTINATION_DIR = path.join(CURR_DIR, '');
|
||||
}
|
||||
|
||||
const TEMP_PLUGIN_NAME = 'Sort';
|
||||
|
||||
let projectValue: string = '';
|
||||
let projectUpperValue: string = '';
|
||||
|
||||
const CHOICES = fs.readdirSync(path.join(__dirname, 'templates'));
|
||||
const QUESTIONS = [
|
||||
{
|
||||
name: 'template',
|
||||
type: 'list',
|
||||
message: 'What template would you like to use?',
|
||||
choices: CHOICES,
|
||||
},
|
||||
{
|
||||
name: 'name',
|
||||
type: 'input',
|
||||
message: 'Please input a new plugin name:',
|
||||
},
|
||||
];
|
||||
|
||||
inquirer.prompt(QUESTIONS).then((answers) => {
|
||||
const projectChoice = answers['template'] as string;
|
||||
projectValue = answers['name'] as string;
|
||||
projectUpperValue = capitalizeFirstLetter(projectValue);
|
||||
|
||||
const projectName = ('plugin-' + projectValue).replace(/([A-Z])/g, (match) => `-${match.toLowerCase()}`);
|
||||
|
||||
//@ts-ignore
|
||||
const templatePath = path.join(__dirname, 'templates', projectChoice);
|
||||
|
||||
// sheets-plugin-data-validation => sheets-plugin-data-validation
|
||||
//@ts-ignore
|
||||
const tartgetPath = path.join(DESTINATION_DIR, projectName);
|
||||
|
||||
cliOptions.projectName = projectName;
|
||||
cliOptions.templateName = projectChoice;
|
||||
cliOptions.templatePath = templatePath;
|
||||
cliOptions.tartgetPath = tartgetPath;
|
||||
|
||||
if (!createProject(tartgetPath)) {
|
||||
return;
|
||||
}
|
||||
|
||||
//@ts-ignore
|
||||
createDirectoryContents(templatePath, projectName, cliOptions);
|
||||
|
||||
// postProcess(cliOptions);
|
||||
devTips(projectName);
|
||||
});
|
||||
|
||||
function createDirectoryContents(templatePath: string, projectName: string) {
|
||||
// read all files/folders (1 level) from template folder
|
||||
const filesToCreate = fs.readdirSync(templatePath);
|
||||
// loop each file/folder
|
||||
filesToCreate.forEach((file) => {
|
||||
const origFilePath = path.join(templatePath, file);
|
||||
|
||||
// get stats about the current file
|
||||
const stats = fs.statSync(origFilePath);
|
||||
|
||||
// skip files that should not be copied
|
||||
if (SKIP_FILES.indexOf(file) > -1) return;
|
||||
|
||||
if (stats.isFile()) {
|
||||
// read file content and transform it using template engine
|
||||
let contents = fs.readFileSync(origFilePath, 'utf8');
|
||||
|
||||
contents = template.render(contents, { projectValue, projectUpperValue, projectName: cliOptions.projectName });
|
||||
|
||||
// write file to destination folder
|
||||
let writePath = path.join(DESTINATION_DIR, projectName, file);
|
||||
|
||||
// change file name
|
||||
if (writePath.indexOf(TEMP_PLUGIN_NAME) > -1) {
|
||||
writePath = writePath.replace(TEMP_PLUGIN_NAME, projectUpperValue);
|
||||
}
|
||||
|
||||
fs.writeFileSync(writePath, contents, 'utf8');
|
||||
} else if (stats.isDirectory()) {
|
||||
// create folder in destination folder
|
||||
|
||||
let writeFolderPath = path.join(DESTINATION_DIR, projectName, file);
|
||||
|
||||
// change folder name (Not recommended. Because the directory of each plug-in should be the same)
|
||||
// if (writeFolderPath.indexOf(TEMP_PLUGIN_NAME) > -1) {
|
||||
// writeFolderPath = writeFolderPath.replace(TEMP_PLUGIN_NAME, projectUpperValue);
|
||||
// }
|
||||
|
||||
fs.mkdirSync(writeFolderPath);
|
||||
|
||||
// const destination = path.join(CURR_DIR, 'packages');
|
||||
// fs.mkdirSync(path.join(destination, projectName, file));
|
||||
// copy files/folder inside current folder recursively
|
||||
createDirectoryContents(path.join(templatePath, file), path.join(projectName, file));
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function createProject(projectPath: string) {
|
||||
if (fs.existsSync(projectPath)) {
|
||||
console.log(chalk.red(`Folder ${projectPath} exists. Delete or use another name.`));
|
||||
return false;
|
||||
}
|
||||
fs.mkdirSync(projectPath);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
function capitalizeFirstLetter(string: string) {
|
||||
return string.charAt(0).toUpperCase() + string.slice(1);
|
||||
}
|
||||
|
||||
function devTips(projectName: string) {
|
||||
// pnpm run --filter @univer/sheets-plugin-<%= projectValue %> dev
|
||||
console.log(chalk.green(` SUCCESS!\n\n`), chalk.white(`Check directory packages/${projectName}, run the following command to develop: \n\n`), chalk.green(`pnpm run --filter @univer/${projectName} dev`));
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
module.exports = {
|
||||
env: {
|
||||
browser: true,
|
||||
es2021: true,
|
||||
node: true,
|
||||
},
|
||||
parser: '@typescript-eslint/parser',
|
||||
extends: [
|
||||
'airbnb-typescript',
|
||||
'prettier',
|
||||
'eslint:recommended',
|
||||
'plugin:import/recommended',
|
||||
'plugin:import/typescript',
|
||||
],
|
||||
parserOptions: {
|
||||
ecmaVersion: 12,
|
||||
sourceType: 'module',
|
||||
project: './tsconfig.json',
|
||||
},
|
||||
plugins: ['@typescript-eslint', 'prettier', 'import'],
|
||||
rules: {
|
||||
'prettier/prettier': [
|
||||
'error',
|
||||
{
|
||||
endOfLine: 'auto',
|
||||
},
|
||||
],
|
||||
'import/prefer-default-export': 'off',
|
||||
'import/no-extraneous-dependencies': [
|
||||
'error',
|
||||
{ devDependencies: true },
|
||||
],
|
||||
// turn on errors for missing imports
|
||||
'import/no-unresolved': 'error',
|
||||
},
|
||||
settings: {
|
||||
'import/parsers': {
|
||||
'@typescript-eslint/parser': ['.ts', '.tsx'],
|
||||
},
|
||||
'import/resolver': {
|
||||
typescript: {
|
||||
alwaysTryTypes: true, // always try to resolve config under `<root>@config` directory even it doesn't contain any source code, like `@config/unist`
|
||||
|
||||
// Choose from one of the "project" configs below or omit to use <root>/tsconfig.json by default
|
||||
|
||||
// use <root>/path/to/folder/tsconfig.json
|
||||
project: './tsconfig.json',
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
@@ -0,0 +1,101 @@
|
||||
#ide
|
||||
*.DS_Store
|
||||
.idea
|
||||
.vscode
|
||||
|
||||
#npm
|
||||
package-lock.json
|
||||
|
||||
dist
|
||||
lib
|
||||
docs/.vuepress/dist
|
||||
|
||||
# Logs
|
||||
logs
|
||||
*.log
|
||||
npm-debug.log*
|
||||
yarn-debug.log*
|
||||
yarn-error.log*
|
||||
lerna-debug.log*
|
||||
|
||||
# Runtime config
|
||||
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
|
||||
|
||||
#lerna-changelog
|
||||
.changelog
|
||||
|
||||
|
||||
#editor workspace file
|
||||
.idea/
|
||||
|
||||
|
||||
.DS_Store
|
||||
|
||||
.history
|
||||
# examples
|
||||
|
||||
|
||||
# Production
|
||||
/build
|
||||
|
||||
# Generated files
|
||||
.docusaurus
|
||||
.cache-loader
|
||||
|
||||
# Misc
|
||||
.env.local
|
||||
.env.development.local
|
||||
.env.test.local
|
||||
.env.production.local
|
||||
@@ -0,0 +1,7 @@
|
||||
module.exports = {
|
||||
singleQuote: true,
|
||||
trailingComma: 'es5',
|
||||
tabWidth: 4,
|
||||
semi: true,
|
||||
printWidth: 180,
|
||||
};
|
||||
@@ -0,0 +1,55 @@
|
||||
# style-universheet
|
||||
|
||||
简体中文 | [English](./README.md)
|
||||
|
||||
## 介绍
|
||||
|
||||
UniverSheet <%= projectUpperValue %>插件
|
||||
|
||||
### 安装
|
||||
|
||||
```bash
|
||||
npm i @univer/<%= projectName %>
|
||||
```
|
||||
|
||||
### 使用
|
||||
|
||||
```js
|
||||
impport {<%= projectUpperValue %>} from '@univer/<%= projectName %>'
|
||||
|
||||
const univerSheet = new UniverSheet();
|
||||
univerSheet.installPlugin(new <%= projectUpperValue %>());
|
||||
```
|
||||
|
||||
## 本地开发
|
||||
|
||||
### 环境
|
||||
|
||||
- [Node.js](https://nodejs.org/en/) Version >= 10
|
||||
- [npm](https://www.npmjs.com/) Version >= 6
|
||||
|
||||
### 安装
|
||||
|
||||
```
|
||||
pnpm install
|
||||
```
|
||||
|
||||
### 开发
|
||||
|
||||
```
|
||||
# 当前目录 ./packages/<%= projectName %>/
|
||||
npm run dev
|
||||
|
||||
# 或者项目根目录 ./
|
||||
pnpm run --filter @univer/<%= projectName %> dev
|
||||
```
|
||||
|
||||
### 打包
|
||||
|
||||
```
|
||||
# 当前目录 ./packages/<%= projectName %>/
|
||||
npm run build
|
||||
|
||||
# 或者根目录 ./
|
||||
pnpm run --filter @univer/<%= projectName %> build
|
||||
```
|
||||
@@ -0,0 +1,55 @@
|
||||
# style-universheet
|
||||
|
||||
English| [简体中文](./README-zh.md)
|
||||
|
||||
## Introduction
|
||||
|
||||
UniverSheet Plugin <%= projectUpperValue %>
|
||||
|
||||
### Installation
|
||||
|
||||
```bash
|
||||
npm i @univer/<%= projectName %>
|
||||
```
|
||||
|
||||
### Usage
|
||||
|
||||
```js
|
||||
impport {<%= projectUpperValue %>} from '@univer/<%= projectName %>'
|
||||
|
||||
const univerSheet = new UniverSheet();
|
||||
univerSheet.installPlugin(new <%= projectUpperValue %>());
|
||||
```
|
||||
|
||||
## Local development
|
||||
|
||||
### Requirements
|
||||
|
||||
- [Node.js](https://nodejs.org/en/) Version >= 10
|
||||
- [npm](https://www.npmjs.com/) Version >= 6
|
||||
|
||||
### Installation
|
||||
|
||||
```
|
||||
pnpm install
|
||||
```
|
||||
|
||||
### Development
|
||||
|
||||
```
|
||||
# Current directory ./packages/<%= projectName %>/
|
||||
npm run dev
|
||||
|
||||
# Or project root directory ./
|
||||
pnpm run --filter @univer/<%= projectName %> dev
|
||||
```
|
||||
|
||||
### Package
|
||||
|
||||
```
|
||||
# Current directory ./packages/<%= projectName %>/
|
||||
npm run build
|
||||
|
||||
# Or root directory ./
|
||||
pnpm run --filter @univer/<%= projectName %> build
|
||||
```
|
||||
@@ -0,0 +1,24 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<link rel="icon" type="image/svg+xml" href="favicon.svg" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>UniverSheet</title>
|
||||
<style>
|
||||
html,
|
||||
body {
|
||||
height: 100%;
|
||||
margin: 0;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div id="app"></div>
|
||||
<div id="universheet-demo" style="height: 100%;"></div>
|
||||
<script type="module" src="/src/main.tsx"></script>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
@@ -0,0 +1,18 @@
|
||||
/** @type {import('ts-jest/dist/types').InitialOptionsTsJest} */
|
||||
module.exports = {
|
||||
preset: 'ts-jest',
|
||||
testEnvironment: 'jsdom',
|
||||
moduleFileExtensions: ['js', 'ts', 'tsx'],
|
||||
|
||||
roots: ['<rootDir>/src'],
|
||||
testMatch: ['**/__tests__/**/*.+(ts|tsx|js)', '**/?(*.)+(spec|test).+(ts|tsx|js)'],
|
||||
transform: {
|
||||
'^.+\\.(ts|tsx)$': 'ts-jest',
|
||||
'^.+\\.tsx?$': 'babel-jest', // https://github.com/kulshekhar/ts-jest/issues/937#issuecomment-455431207
|
||||
},
|
||||
globals: {
|
||||
'ts-jest': {
|
||||
tsConfig: 'tsconfig.test.json',
|
||||
},
|
||||
},
|
||||
};
|
||||
@@ -0,0 +1,59 @@
|
||||
{
|
||||
"name": "@univer/<%= projectName %>",
|
||||
"version": "0.0.1",
|
||||
"description": "UniverSheet normal <%= projectName %>",
|
||||
"keywords": [],
|
||||
"author": "DreamNum <msoffice2@126.com>",
|
||||
"license": "MIT",
|
||||
"main": "./src/index.ts",
|
||||
"module": "./src/index.ts",
|
||||
"types": "./src/Types/index.d.ts",
|
||||
"exports": {
|
||||
".": "./src/index.ts",
|
||||
"./*": "./src/*"
|
||||
},
|
||||
"publishConfig": {
|
||||
"main": "./lib/index.umd.js",
|
||||
"module": "./lib/index.es.js",
|
||||
"types": "./lib/index.d.ts"
|
||||
},
|
||||
"directories": {
|
||||
"lib": "lib"
|
||||
},
|
||||
"scripts": {
|
||||
"test": "jest",
|
||||
"dev": "vite",
|
||||
"build": "tsc && vite build",
|
||||
"serve": "vite preview"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@preact/preset-vite": "2.0.0",
|
||||
"@testing-library/preact": "^2.0.1",
|
||||
"@types/jest": "^27.0.1",
|
||||
"@types/node": "^16.4.6",
|
||||
"@vitejs/plugin-legacy": "^1.5.1",
|
||||
"eslint": "^8.22.0",
|
||||
"eslint-config-airbnb-typescript": "^17.0.0",
|
||||
"eslint-config-prettier": "^8.3.0",
|
||||
"eslint-plugin-import": "^2.23.4",
|
||||
"eslint-plugin-prettier": "^3.4.0",
|
||||
"eslint-plugin-jsx-a11y": "^6.5.1",
|
||||
"eslint-plugin-react": "^7.28.0",
|
||||
"eslint-plugin-react-hooks": "^4.3.0",
|
||||
"less": "^4.1.1",
|
||||
"prettier": "^2.3.2",
|
||||
"ts-jest": "29.0.1",
|
||||
"ts-node": "^10.2.1",
|
||||
"typescript": "^4.4.1-rc",
|
||||
"vite": "^2.4.4"
|
||||
},
|
||||
"dependencies": {
|
||||
"@univer/base-component": "workspace:^0.0.1",
|
||||
"@univer/base-render": "workspace:^0.0.1",
|
||||
"@univer/core": "workspace:^0.0.1",
|
||||
"@univer/base-sheets": "workspace:^0.0.1",
|
||||
"@univer/sheets-plugin-filter": "workspace:^0.0.1",
|
||||
"@univer/style-universheet": "workspace:^0.0.1",
|
||||
"preact": "^10.5.14"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
export * from './Const';
|
||||
export * from './Enum';
|
||||
export * from '../Locale';
|
||||
export * from './Shared';
|
||||
@@ -0,0 +1,9 @@
|
||||
export default {
|
||||
<%= projectValue %>Label: '<%= projectUpperValue %>',
|
||||
<%= projectValue %>RightLabel: 'more <%= projectUpperValue %>',
|
||||
<%= projectValue %>: {
|
||||
one:'one',
|
||||
two:'two',
|
||||
three:'three',
|
||||
},
|
||||
};
|
||||
@@ -0,0 +1,4 @@
|
||||
import zh from './zh';
|
||||
import en from './en';
|
||||
|
||||
export { zh, en };
|
||||
@@ -0,0 +1,9 @@
|
||||
export default {
|
||||
<%= projectValue %>Label: '插件',
|
||||
<%= projectValue %>RightLabel: '更多 <%= projectUpperValue %>',
|
||||
<%= projectValue %>: {
|
||||
one:'一',
|
||||
two:'二',
|
||||
three:'三',
|
||||
},
|
||||
};
|
||||
@@ -0,0 +1,47 @@
|
||||
import { Context, Plugin, PLUGIN_NAMES } from '@univer/core';
|
||||
import { <%= projectUpperValue %>Button } from './View/UI/<%= projectUpperValue %>Button';
|
||||
import { zh, en } from './Locale';
|
||||
|
||||
import { IToolBarItemProps, ISlotElement } from '@univer/base-component';
|
||||
import { IOCContainer } from '@univer/core';
|
||||
|
||||
interface IPluginConfig {}
|
||||
|
||||
interface IConfig {}
|
||||
|
||||
export class <%= projectUpperValue %>Plugin extends Plugin {
|
||||
|
||||
constructor(config ?: IPluginConfig) {
|
||||
super('plugin<%= projectUpperValue %>');
|
||||
}
|
||||
|
||||
initialize(): void {
|
||||
|
||||
const context = this.getContext();
|
||||
|
||||
/**
|
||||
* load more Locale object
|
||||
*/
|
||||
context.getLocale().load({
|
||||
en: en,
|
||||
zh: zh,
|
||||
});
|
||||
const config: IConfig = {};
|
||||
|
||||
const item: IToolBarItemProps = {
|
||||
locale: '<%= projectValue %>',
|
||||
type: ISlotElement.JSX,
|
||||
show: true,
|
||||
label: <<%= projectUpperValue %>Button config={ config } />
|
||||
}
|
||||
context.getPluginManager().getPluginByName<SpreadsheetPlugin>(PLUGIN_NAMES.SPREADSHEET)?.addButton(item)
|
||||
}
|
||||
|
||||
onMapping(IOC: IOCContainer): void {}
|
||||
|
||||
onMounted(ctx: Context): void {
|
||||
this.initialize()
|
||||
}
|
||||
|
||||
onDestroy(): void {}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
/// <reference types="vite/client" />
|
||||
|
||||
export * from '../index';
|
||||
declare module '@univer/<%= projectName %>' {}
|
||||
|
||||
import JSX = preact.JSX;
|
||||
|
||||
// use css module
|
||||
declare module '*.less' {
|
||||
const resource: { [key: string]: string };
|
||||
export = resource;
|
||||
}
|
||||
@@ -0,0 +1,104 @@
|
||||
import { Nullable, Observer, WorkBook } from '@univer/core';
|
||||
import { ISelectButton, IToolBarItemProps, Component } from '@univer/base-component';
|
||||
|
||||
interface IProps {}
|
||||
// Types for state
|
||||
interface IState {
|
||||
<%= projectValue %>: IToolBarItemProps;
|
||||
}
|
||||
|
||||
export class <%= projectUpperValue %>Button extends Component<IProps, IState> {
|
||||
|
||||
private _localeObserver: Nullable<Observer<WorkBook>>;
|
||||
initialize(props: IProps) {
|
||||
|
||||
const OrderASCIcon = this.getComponentRender().renderFunction('OrderASCIcon');
|
||||
const OrderDESCIcon = this.getComponentRender().renderFunction('OrderDESCIcon');
|
||||
const OrderIcon = this.getComponentRender().renderFunction('OrderIcon');
|
||||
const NextIcon = this.getComponentRender().renderFunction('NextIcon');
|
||||
|
||||
const <%= projectValue %> = {
|
||||
locale: '<%= projectValue %>',
|
||||
type: 'select',
|
||||
label: <OrderASCIcon />,
|
||||
icon: <NextIcon />,
|
||||
show: true,
|
||||
border: false,
|
||||
selectType: ISelectButton.DOUBLE,
|
||||
needChange: false,
|
||||
children: [
|
||||
{
|
||||
locale: '<%= projectValue %>.one',
|
||||
icon: <OrderASCIcon />,
|
||||
},
|
||||
{
|
||||
locale: '<%= projectValue %>.two',
|
||||
icon: <OrderDESCIcon />,
|
||||
},
|
||||
{
|
||||
locale: '<%= projectValue %>.three',
|
||||
icon: <OrderIcon />,
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
this.state = {
|
||||
<%= projectValue %>: <%= projectValue %>,
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* init
|
||||
*/
|
||||
componentWillMount() {
|
||||
this.setLocale();
|
||||
|
||||
// subscribe Locale change event
|
||||
|
||||
this._localeObserver = this._context.getObserverManager().getObserver('onAfterChangeUILocaleObservable','core')?.add(() => {
|
||||
this.setLocale();
|
||||
});
|
||||
}
|
||||
/**
|
||||
* destory
|
||||
*/
|
||||
componentWillUnmount() {
|
||||
this._context.getObserverManager().getObserver('onAfterChangeUILocaleObservable','core')?.remove(this._localeObserver);
|
||||
}
|
||||
/**
|
||||
* set text by config setting and Locale message
|
||||
*/
|
||||
setLocale() {
|
||||
const locale = this._context.getLocale();
|
||||
this.setState((prevState: IState) => {
|
||||
let item = prevState.<%= projectValue %>;
|
||||
// set current Locale string for tooltip
|
||||
item.tooltip = locale.get(`${item.locale}Label`);
|
||||
item.tooltipRight = locale.get(`${item.locale}RightLabel`);
|
||||
|
||||
// set current Locale string for select
|
||||
item.children?.forEach((ele: IToolBarItemProps) => {
|
||||
if (ele.locale) {
|
||||
ele.label = locale.get(`${ele.locale}`);
|
||||
}
|
||||
});
|
||||
item.label = typeof item.label == 'object' ? item.label : item.children![0].label;
|
||||
|
||||
return {
|
||||
<%= projectValue %>: item,
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Render the component's HTML
|
||||
*
|
||||
* @returns {void}
|
||||
*/
|
||||
render(props: IProps, state: IState) {
|
||||
const { <%= projectValue %> } = state;
|
||||
const Select = this.getComponentRender().renderFunction('Select');
|
||||
// Set Provider for entire Container
|
||||
return <Select tooltip={<%= projectValue %>.tooltip} tooltipRight={<%= projectValue %>.tooltipRight} border={<%= projectValue %>.border} isDouble={<%= projectValue %>.isDouble} needChange={<%= projectValue %>.needChange} key={<%= projectValue %>.locale} children={<%= projectValue %>.children as IToolBarItemProps[]} label={<%= projectValue %>.label} icon={<%= projectValue %>.icon} />;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
import { <%= projectUpperValue %>Plugin } from './<%= projectUpperValue %>Plugin';
|
||||
|
||||
export { <%= projectUpperValue %>Plugin };
|
||||
@@ -0,0 +1,22 @@
|
||||
import { defaultWorkbookData, UniverSheet } from '@univer/core';
|
||||
import { RenderEngine } from '@univer/base-render';
|
||||
import { SpreadsheetPlugin } from '@univer/base-sheets';
|
||||
import { UniverComponentSheet } from '@univer/style-universheet';
|
||||
|
||||
import { FilterPlugin } from '@univer/sheets-plugin-filter';
|
||||
import { <%= projectUpperValue %>Plugin } from './<%= projectUpperValue %>Plugin';
|
||||
|
||||
|
||||
const uiDefaultConfigUp = {
|
||||
containerId: 'universheet-demo',
|
||||
layout: 'auto',
|
||||
};
|
||||
|
||||
const univerSheetUp = UniverSheet.newInstance(defaultWorkbookData);
|
||||
|
||||
univerSheetUp.installPlugin(new RenderEngine());
|
||||
univerSheetUp.installPlugin(new UniverComponentSheet());
|
||||
|
||||
univerSheetUp.installPlugin(new SpreadsheetPlugin(uiDefaultConfigUp));
|
||||
univerSheetUp.installPlugin(new FilterPlugin());
|
||||
univerSheetUp.installPlugin(new <%= projectUpperValue %>Plugin());
|
||||
@@ -0,0 +1 @@
|
||||
import JSX = preact.JSX;
|
||||
@@ -0,0 +1,31 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"rootDir": "./",
|
||||
"outDir": "lib",
|
||||
"target": "ESNext",
|
||||
|
||||
"lib": ["ESNext", "DOM", "WebWorker"],
|
||||
"module": "ESNext",
|
||||
"moduleResolution": "Node", //This value is needed for Node.js.
|
||||
|
||||
"declaration": true,
|
||||
"declarationDir": "./lib",
|
||||
"declarationMap": true,
|
||||
"sourceMap": true,
|
||||
"resolveJsonModule": true,
|
||||
"strict": true,
|
||||
"allowJs": true,
|
||||
|
||||
"baseUrl": "./",
|
||||
"skipLibCheck": true,
|
||||
"esModuleInterop": true, // auto allowSyntheticDefaultImports tru
|
||||
"suppressImplicitAnyIndexErrors": true,
|
||||
"experimentalDecorators": true,
|
||||
"jsx": "preserve",
|
||||
"jsxFactory": "h",
|
||||
"jsxFragmentFactory": "Fragment",
|
||||
"strictPropertyInitialization": false,
|
||||
"types": ["jest", "node", "@types/jest"]
|
||||
},
|
||||
"include": ["src/**/*", "test/**/*.test.(ts|tsx|js)"]
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"extends": "./tsconfig.json",
|
||||
"include": ["src/**/*"],
|
||||
"compilerOptions": {
|
||||
"composite": true
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"extends": "./tsconfig.json",
|
||||
"compilerOptions": {
|
||||
"jsx": "react-jsx",
|
||||
"jsxImportSource": "preact"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
import { defineConfig } from 'vite';
|
||||
import path from 'path';
|
||||
import preact from '@preact/preset-vite';
|
||||
import legacy from '@vitejs/plugin-legacy';
|
||||
import { name, version } from './package.json';
|
||||
|
||||
const resolve = (url: string) => path.resolve(__dirname, url);
|
||||
|
||||
export default defineConfig({
|
||||
build: {
|
||||
// lib: {
|
||||
// entry: resolve('src/index.ts'),
|
||||
// name: 'BaseStyleUniver',
|
||||
// formats: ['es', 'umd'],
|
||||
// fileName: 'index',
|
||||
// },
|
||||
// outDir: './lib',
|
||||
},
|
||||
define: {
|
||||
pkgJson: { name, version },
|
||||
},
|
||||
css: {
|
||||
modules: {
|
||||
localsConvention: 'camelCaseOnly', // dash to camelCase conversion// .apply-color -> applyColor
|
||||
generateScopedName: 'univer-[local]', // custom prefix class name
|
||||
},
|
||||
preprocessorOptions: {
|
||||
less: {
|
||||
javascriptEnabled: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
server: {
|
||||
port: 3103,
|
||||
open: true, // Automatically open the app in the browser on server start.
|
||||
},
|
||||
plugins: [
|
||||
preact(),
|
||||
legacy({
|
||||
targets: ['ie >= 11'],
|
||||
additionalLegacyPolyfills: ['regenerator-runtime/runtime'],
|
||||
}),
|
||||
],
|
||||
});
|
||||
Vendored
+2
@@ -0,0 +1,2 @@
|
||||
export * from './index';
|
||||
declare module '@univer/cli' {}
|
||||
@@ -0,0 +1,27 @@
|
||||
// colors reference of text to command when running node.js application
|
||||
// https://stackoverflow.com/a/41407246
|
||||
export const Reset = '\x1b[0m';
|
||||
export const Bright = '\x1b[1m';
|
||||
export const Dim = '\x1b[2m';
|
||||
export const Underscore = '\x1b[4m';
|
||||
export const Blink = '\x1b[5m';
|
||||
export const Reverse = '\x1b[7m';
|
||||
export const Hidden = '\x1b[8m';
|
||||
|
||||
export const FgBlack = '\x1b[30m';
|
||||
export const FgRed = '\x1b[31m';
|
||||
export const FgGreen = '\x1b[32m';
|
||||
export const FgYellow = '\x1b[33m';
|
||||
export const FgBlue = '\x1b[34m';
|
||||
export const FgMagenta = '\x1b[35m';
|
||||
export const FgCyan = '\x1b[36m';
|
||||
export const FgWhite = '\x1b[37m';
|
||||
|
||||
export const BgBlack = '\x1b[40m';
|
||||
export const BgRed = '\x1b[41m';
|
||||
export const BgGreen = '\x1b[42m';
|
||||
export const BgYellow = '\x1b[43m';
|
||||
export const BgBlue = '\x1b[44m';
|
||||
export const BgMagenta = '\x1b[45m';
|
||||
export const BgCyan = '\x1b[46m';
|
||||
export const BgWhite = '\x1b[47m';
|
||||
@@ -0,0 +1,121 @@
|
||||
/**
|
||||
* Event Bus
|
||||
*
|
||||
* Reference https://www.thisdot.co/blog/how-to-implement-an-event-bus-in-typescript
|
||||
*/
|
||||
|
||||
interface ICallbackList {
|
||||
[id: string]: Function;
|
||||
}
|
||||
|
||||
interface IEventObject {
|
||||
[eventName: string]: ICallbackList;
|
||||
}
|
||||
|
||||
interface ISubscribe {
|
||||
unSubscribe: () => void;
|
||||
}
|
||||
|
||||
export interface IEventBus {
|
||||
publish<T extends any[]>(eventName: string, ...args: T): void;
|
||||
subscribe(eventName: string, callback: Function): ISubscribe;
|
||||
subscribeOnce(eventName: string, callback: Function): ISubscribe;
|
||||
clear(eventName: string): void;
|
||||
}
|
||||
|
||||
export class EventBus implements IEventBus {
|
||||
private _eventObject: IEventObject;
|
||||
private _callbackId: number;
|
||||
constructor() {
|
||||
// initialize event list
|
||||
this._eventObject = {};
|
||||
// id of the callback function list
|
||||
this._callbackId = 0;
|
||||
}
|
||||
// publish event
|
||||
publish<T extends any[]>(eventName: string, ...args: T): void {
|
||||
// Get all the callback functions of the current event
|
||||
const callbackObject = this._eventObject[eventName];
|
||||
|
||||
if (!callbackObject) return console.warn(eventName + ' not found!');
|
||||
|
||||
// execute each callback function
|
||||
for (let id in callbackObject) {
|
||||
// pass parameters when executing
|
||||
callbackObject[id](...args);
|
||||
|
||||
// The callback function that is only subscribed once needs to be deleted
|
||||
if (id[0] === 'd') {
|
||||
delete callbackObject[id];
|
||||
}
|
||||
}
|
||||
}
|
||||
// Subscribe to events
|
||||
subscribe(eventName: string, callback: Function): ISubscribe {
|
||||
// initialize this event
|
||||
if (!this._eventObject[eventName]) {
|
||||
// Use object storage to improve the efficiency of deletion when logging out the callback function
|
||||
this._eventObject[eventName] = {};
|
||||
}
|
||||
|
||||
const id = this._callbackId++;
|
||||
|
||||
// store the callback function of the subscriber
|
||||
// callbackId needs to be incremented after use for the next callback function
|
||||
this._eventObject[eventName][id] = callback;
|
||||
|
||||
// Every time you subscribe to an event, a unique unsubscribe function is generated
|
||||
const unSubscribe = () => {
|
||||
// clear the callback function of this subscriber
|
||||
delete this._eventObject[eventName][id];
|
||||
|
||||
// If this event has no subscribers, also clear the entire event object
|
||||
if (Object.keys(this._eventObject[eventName]).length === 0) {
|
||||
delete this._eventObject[eventName];
|
||||
}
|
||||
};
|
||||
|
||||
return { unSubscribe };
|
||||
}
|
||||
|
||||
// only subscribe once
|
||||
subscribeOnce(eventName: string, callback: Function): ISubscribe {
|
||||
// initialize this event
|
||||
if (!this._eventObject[eventName]) {
|
||||
// Use object storage to improve the efficiency of deletion when logging out the callback function
|
||||
this._eventObject[eventName] = {};
|
||||
}
|
||||
|
||||
// Callback function marked as subscribe only once
|
||||
const id = 'd' + this._callbackId++;
|
||||
|
||||
// store the callback function of the subscriber
|
||||
// callbackId needs to be incremented after use for the next callback function
|
||||
this._eventObject[eventName][id] = callback;
|
||||
|
||||
// Every time you subscribe to an event, a unique unsubscribe function is generated
|
||||
const unSubscribe = () => {
|
||||
// clear the callback function of this subscriber
|
||||
delete this._eventObject[eventName][id];
|
||||
|
||||
// If this event has no subscribers, also clear the entire event object
|
||||
if (Object.keys(this._eventObject[eventName]).length === 0) {
|
||||
delete this._eventObject[eventName];
|
||||
}
|
||||
};
|
||||
|
||||
return { unSubscribe };
|
||||
}
|
||||
|
||||
// clear event
|
||||
clear(eventName: string): void {
|
||||
// If no event name is provided, all events are cleared by default
|
||||
if (!eventName) {
|
||||
this._eventObject = {};
|
||||
return;
|
||||
}
|
||||
|
||||
// clear the specified event
|
||||
delete this._eventObject[eventName];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
import * as ejs from 'ejs';
|
||||
import { IBuildJson } from '../build';
|
||||
|
||||
/**
|
||||
* Place where you need to replace the variable
|
||||
*
|
||||
* <%= projectUpperValue %>
|
||||
<%= projectValue %>
|
||||
*/
|
||||
export interface TemplateData {
|
||||
projectValue: string;
|
||||
projectUpperValue: string;
|
||||
projectName: string;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* repalce value in content
|
||||
*
|
||||
* @param content
|
||||
* @param data
|
||||
* @returns
|
||||
*/
|
||||
export function render(content: string, data: TemplateData) {
|
||||
return ejs.render(content, data);
|
||||
}
|
||||
|
||||
export function renderContent(content: string, data: IBuildJson) {
|
||||
return ejs.render(content, data);
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
export function generateRandomId(): string {
|
||||
function S4() {
|
||||
return (((1 + Math.random()) * 0x10000) | 0).toString(16).substring(1);
|
||||
}
|
||||
return new Date().getTime() + S4() + S4();
|
||||
}
|
||||
@@ -0,0 +1,68 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
/* Basic Options */
|
||||
// "incremental": true, /* Enable incremental compilation */
|
||||
"target": "es6" /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', 'ES2018', 'ES2019', 'ES2020', or 'ESNEXT'. */,
|
||||
"module": "commonjs" /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', 'es2020', or 'ESNext'. */,
|
||||
// "lib": [], /* Specify library files to be included in the compilation. */
|
||||
// "allowJs": true, /* Allow javascript files to be compiled. */
|
||||
// "checkJs": true, /* Report errors in .js files. */
|
||||
// "jsx": "preserve", /* Specify JSX code generation: 'preserve', 'react-native', or 'react'. */
|
||||
"declaration": true /* Generates corresponding '.d.ts' file. */,
|
||||
// "declarationMap": true, /* Generates a sourcemap for each corresponding '.d.ts' file. */
|
||||
"sourceMap": false /* Generates corresponding '.map' file. */,
|
||||
// "outFile": "./", /* Concatenate and emit output to single file. */
|
||||
"outDir": "lib" /* Redirect output structure to the directory. */,
|
||||
"rootDir": "src" /* Specify the root directory of input files. Use to control the output directory structure with --outDir. */,
|
||||
// "composite": true, /* Enable project compilation */
|
||||
// "tsBuildInfoFile": "./", /* Specify file to store incremental compilation information */
|
||||
// "removeComments": true, /* Do not emit comments to output. */
|
||||
// "noEmit": true, /* Do not emit outputs. */
|
||||
// "importHelpers": true, /* Import emit helpers from 'tslib'. */
|
||||
// "downlevelIteration": true, /* Provide full support for iterables in 'for-of', spread, and destructuring when targeting 'ES5' or 'ES3'. */
|
||||
// "isolatedModules": true, /* Transpile each file as a separate module (similar to 'ts.transpileModule'). */
|
||||
|
||||
/* Strict Type-Checking Options */
|
||||
"strict": true /* Enable all strict type-checking options. */,
|
||||
// "noImplicitAny": true, /* Raise error on expressions and declarations with an implied 'any' type. */
|
||||
// "strictNullChecks": true, /* Enable strict null checks. */
|
||||
// "strictFunctionTypes": true, /* Enable strict checking of function types. */
|
||||
// "strictBindCallApply": true, /* Enable strict 'bind', 'call', and 'apply' methods on functions. */
|
||||
// "strictPropertyInitialization": true, /* Enable strict checking of property initialization in classes. */
|
||||
// "noImplicitThis": true, /* Raise error on 'this' expressions with an implied 'any' type. */
|
||||
// "alwaysStrict": true, /* Parse in strict mode and emit "use strict" for each source file. */
|
||||
|
||||
/* Additional Checks */
|
||||
// "noUnusedLocals": true, /* Report errors on unused locals. */
|
||||
// "noUnusedParameters": true, /* Report errors on unused parameters. */
|
||||
// "noImplicitReturns": true, /* Report error when not all code paths in function return a value. */
|
||||
// "noFallthroughCasesInSwitch": true, /* Report errors for fallthrough cases in switch statement. */
|
||||
|
||||
/* Module Resolution Options */
|
||||
// "moduleResolution": "node", /* Specify module resolution strategy: 'node' (Node.js) or 'classic' (TypeScript pre-1.6). */
|
||||
// "baseUrl": "./", /* Base directory to resolve non-absolute module names. */
|
||||
// "paths": {}, /* A series of entries which re-map imports to lookup locations relative to the 'baseUrl'. */
|
||||
// "rootDirs": [], /* List of root folders whose combined content represents the structure of the project at runtime. */
|
||||
// "typeRoots": [], /* List of folders to include type definitions from. */
|
||||
"types": ["@types/ejs", "@types/inquirer", "@types/node", "@types/shelljs"] /* Type declaration files to be included in compilation. */,
|
||||
// "allowSyntheticDefaultImports": true, /* Allow default imports from modules with no default export. This does not affect code emit, just typechecking. */
|
||||
"esModuleInterop": true /* Enables emit interoperability between CommonJS and ES Modules via creation of namespace objects for all imports. Implies 'allowSyntheticDefaultImports'. */
|
||||
// "preserveSymlinks": true, /* Do not resolve the real path of symlinks. */
|
||||
// "allowUmdGlobalAccess": true, /* Allow accessing UMD globals from modules. */
|
||||
|
||||
/* Source Map Options */
|
||||
// "sourceRoot": "", /* Specify the location where debugger should locate TypeScript files instead of source locations. */
|
||||
// "mapRoot": "", /* Specify the location where debugger should locate map files instead of generated locations. */
|
||||
// "inlineSourceMap": true, /* Emit a single file with source maps instead of having a separate file. */
|
||||
// "inlineSources": true, /* Emit the source alongside the sourcemaps within a single file; requires '--inlineSourceMap' or '--sourceMap' to be set. */
|
||||
|
||||
/* Experimental Options */
|
||||
// "experimentalDecorators": true, /* Enables experimental support for ES7 decorators. */
|
||||
// "emitDecoratorMetadata": true, /* Enables experimental support for emitting type metadata for decorators. */
|
||||
|
||||
/* Advanced Options */
|
||||
//"forceConsistentCasingInFileNames": true /* Disallow inconsistently-cased references to the same file. */
|
||||
},
|
||||
"include": ["src/**/*"],
|
||||
"exclude": ["src/templates/**/*"]
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
# 关于
|
||||
|
||||
## 贡献者
|
||||
|
||||
## 赞助商
|
||||
|
||||
## 社区案例
|
||||
|
||||
## 开源软件申明
|
||||
|
||||
我们站在巨人的肩膀上构建新的应用,非常感谢这些开源贡献者们的无私奉献。
|
||||
|
||||
- [preact](https://preactjs.com)
|
||||
- [dayjs](https://github.com/iamkun/dayjs)
|
||||
- [numeral](https://github.com/adamwdraper/Numeral-js)
|
||||
- [reflect-metadata](https://github.com/rbuckton/reflect-metadata)
|
||||
- [es6-proxy-polyfill](https://github.com/ambit-tsai/es6-proxy-polyfill)
|
||||
- [react-colorful](https://github.com/omgovich/react-colorful)
|
||||
- [css-vars-ponyfill](https://github.com/jhildenbiddle/css-vars-ponyfill)
|
||||
- [csstype](https://github.com/frenic/csstype)
|
||||
@@ -0,0 +1,33 @@
|
||||
# 核心设计
|
||||
|
||||
## Observer
|
||||
|
||||
每一个 UniverSheet 实例都会有一个 ObserverManager 来这个实例的 Observer,ObserverManager 挂载在 context 上。
|
||||
|
||||
在核心中,Observer 是初始化内置的,直接从 ObserverManager 实例 调用即可,比如更新国际化信息的 Observer `onAfterChangeUILocaleObservable`
|
||||
|
||||
在 Plugin 基类 中,也抽象了便捷的方法来创建和销毁的 Observer
|
||||
Plugin Observer 方法
|
||||
|
||||
- addObserver: 增加 Observer,使用 addObserver 需要在插件初始化的时候手动调用,指定 Observer 名称,Plugin 基类会帮您指定 namespace 为当前插件
|
||||
- removeObserver: 销毁 Observer,此 API 会在插件销毁的时候自动在 onDestroy 中调用,插件开发者无需手动调用,如果插件开发者要手动更新 onDestroy 函数,需要使用 `super.onDestroy()` 来调用 Plugin 基类的销毁方法
|
||||
- getObserver:获取 Observer,支持在 插件中快捷获取你想要的 Observer,如果插件中的其他模块也需要获取 Observer,可以将插件实例或者核心 context 注入到其他模块中来调用 Observer
|
||||
|
||||
```js
|
||||
// 使用插件的 getObserver
|
||||
pluginInstance.getObserver('observeName');
|
||||
|
||||
// 或者
|
||||
|
||||
// 使用 context 的 ObserverManager
|
||||
this.context
|
||||
.getObserverManager()
|
||||
.getObserver('onAfterChangeFontFamilyObservable', 'styleUniverSheet')
|
||||
?.add(() => {});
|
||||
```
|
||||
|
||||
API
|
||||
|
||||
案例;设置单元格值,设置样式
|
||||
|
||||
base-sheets 引入 UI 组件库使用时,推荐分离业务逻辑和 UI,使得能够针对业务逻辑做单元测试,这些业务逻辑包括一些纯输入输出的计算、转换方法等。
|
||||
@@ -0,0 +1,250 @@
|
||||
# 前端插件化架构在 UniverSheet 3.0 的实现
|
||||
|
||||
## 需求
|
||||
|
||||
在前端开发中,当你的系统功能逐渐增多,模块间的交互就会越来越复杂,如果没有做提前设计,代码很容易变得臃肿和难以阅读。
|
||||
|
||||
这时候就需要考虑加入设计模式了,通常来说,只需要加入几种常见的设计模式,比如观察者模式、命令模式,就可以让模块间解耦,让你的系统变得更加健壮、扩展性更强。
|
||||
|
||||
UniverSheet 2.0 很少用到设计模式,扩展性不好,模块拆分不够细致,所以我们 UniverSheet 3.0 重构的时候,重点考虑了扩展性,设计了一种插件化架构,或者叫微内核架构。有了插件,扩展自己的功能就方便了,而且不用改造核心库,可以和官方保持同步。下面就来介绍下我们团队在重构 UniverSheet 时候的思考。
|
||||
|
||||
## 设计
|
||||
|
||||
我们改造的目标是抽离核心模块,构造可扩展的插件系统,支持多实例,npm 引入,增强 SDK 等。重点就是设计插件系统。
|
||||
|
||||
实现一个插件系统,主要解决 3 块内容
|
||||
|
||||
1. 插件初始化,插件的逻辑
|
||||
2. 插件管理,安装、卸载等
|
||||
3. 插件和核心通信,插件和插件通信
|
||||
|
||||
下面简要介绍 UniverSheet 的插件设计
|
||||
|
||||
## 原理
|
||||
|
||||
### 插件初始化
|
||||
|
||||
首先我们在核心构造一个`Plugin`基类,将插件要用到基础属性和方法放在这里,比如插件名称,插件的生命周期。
|
||||
|
||||
初始化即安装时调用 `onMounted` 方法,卸载时调用 `onDestroy` 方法。
|
||||
|
||||
> 为便于理解,以下部分代码经过简化,我们主要讲解下思路
|
||||
|
||||
```ts
|
||||
export abstract class Plugin {
|
||||
protected _name: string;
|
||||
|
||||
protected constructor(name: string) {
|
||||
this._name = name;
|
||||
}
|
||||
|
||||
getName(): string {
|
||||
return this._name;
|
||||
}
|
||||
|
||||
abstract onMounted(): void;
|
||||
|
||||
abstract onDestroy(): void;
|
||||
|
||||
// 其它方法
|
||||
}
|
||||
```
|
||||
|
||||
有了基类,接着就是实现一个插件,任何的插件都需要继承这个`Plugin`类,比如排序插件,需要传入插件名称,内部自行实现好初始化的时候具体插件要做的事情
|
||||
|
||||
```ts
|
||||
export class SortPlugin extends Plugin {
|
||||
constructor() {
|
||||
super('sort');
|
||||
}
|
||||
|
||||
// 初始化
|
||||
onMounted(): void {
|
||||
// 插件具体初始化逻辑
|
||||
}
|
||||
|
||||
// 卸载
|
||||
onDestroy(): void {}
|
||||
|
||||
// 其它方法
|
||||
}
|
||||
```
|
||||
|
||||
### 插件管理
|
||||
|
||||
有了具体的插件之后,需要安装插件到核心,我们先提供了 `PluginManager` 的插件管理类,专门负责插件的存储、安装、卸载。
|
||||
|
||||
思路是每个插件都存储到数组中,安装的时候,执行插件内部的初始化方法即可,卸载的时候,再执行内部的卸载方法并把插件移除掉。管理类主要是起到存储插件和调用插件内部方法的作用。
|
||||
|
||||
```ts
|
||||
export class PluginManager {
|
||||
private _plugins: Plugin[];
|
||||
|
||||
constructor() {}
|
||||
|
||||
_destroy(plugins: Plugin[]) {
|
||||
plugins.forEach((plugin: Plugin) => {
|
||||
plugin.onDestroy();
|
||||
});
|
||||
}
|
||||
|
||||
_initialize(plugins: Plugin[]) {
|
||||
plugins.forEach((plugin: Plugin) => {
|
||||
plugin.onMounted();
|
||||
});
|
||||
}
|
||||
|
||||
// 安装
|
||||
install(plugin: Plugin) {
|
||||
const { _plugins } = this;
|
||||
_plugins.push(plugin);
|
||||
this._initialize([plugin]);
|
||||
}
|
||||
|
||||
// 卸载
|
||||
uninstall(name: string) {
|
||||
const { _plugins } = this;
|
||||
const index = _plugins.findIndex((item) => item.getName() === name);
|
||||
if (index > -1) {
|
||||
const remove = _plugins.splice(index, 1);
|
||||
this._destroy(remove);
|
||||
}
|
||||
}
|
||||
|
||||
// 其它方法
|
||||
}
|
||||
```
|
||||
|
||||
我们还在`UniverSheet`实例上提供了方便安装插件的 API `installPlugin`
|
||||
|
||||
> 提示:这种包装的 API 随处可见,这让我们 API 有统一的出口,更方便使用
|
||||
|
||||
```ts
|
||||
export class UniverSheet {
|
||||
private _context: Context;
|
||||
|
||||
installPlugin(plugin: Plugin): void {
|
||||
this._context.getPluginManager().install(plugin);
|
||||
}
|
||||
|
||||
uninstallPlugin(name: string): void {
|
||||
this._context.getPluginManager().uninstall(name);
|
||||
}
|
||||
|
||||
// 其它方法
|
||||
}
|
||||
```
|
||||
|
||||
### 插件通信
|
||||
|
||||
我们有两种通信机制:全局`Context`和观察者模式。
|
||||
|
||||
关于 `Context`,这是我们设计的一个全局上下文,使用依赖注入的方式,将`Context`注入到各个插件模块,这样在插件模块中就能调用到`Context`上通用的方法了,我们扩充下 `Plugin` 类,使用我们内部实现的`IOC`,将全局 `Context` 注入进来。这样就实现了插件和核心的通信。
|
||||
|
||||
> 关于 `IOC` 的内容,参考我们的另一篇文章
|
||||
|
||||
```ts
|
||||
export abstract class Plugin {
|
||||
// 注入 Context
|
||||
@Inject('Context')
|
||||
protected _context: Context;
|
||||
protected _name: string;
|
||||
|
||||
protected constructor(name: string) {
|
||||
this._name = name;
|
||||
}
|
||||
|
||||
getName(): string {
|
||||
return this._name;
|
||||
}
|
||||
|
||||
getContext(): Context {
|
||||
return this._context;
|
||||
}
|
||||
|
||||
abstract onMounted(ctx: Context): void;
|
||||
|
||||
abstract onDestroy(): void;
|
||||
|
||||
// 其它方法
|
||||
}
|
||||
```
|
||||
|
||||
关于观察者模式,我们实现了
|
||||
|
||||
1. `Observable` 类,提供基础的观察者模式功能如增加、移除、通知
|
||||
2. `PathObservable` 类,包装单个 `Observable`,提供观察者名称
|
||||
3. `ObserverManager` 管理类,和`PluginManager`类似,专门负责`PathObservable`实例的管理
|
||||
|
||||
然后在插件实例中,提供快捷注册观察者的方法 `addObserve`,同时提供获取其它插件的 API `getPluginByName`,这样就能监听其它插件的消息了。这样实现了插件之间的通信。
|
||||
|
||||
```ts
|
||||
export abstract class Plugin<O = any> {
|
||||
@Inject('Context')
|
||||
protected _context: Context;
|
||||
protected _name: string;
|
||||
protected _observeNames: string[];
|
||||
|
||||
protected constructor(name: string) {
|
||||
this._name = name;
|
||||
this._observeNames = [];
|
||||
}
|
||||
|
||||
getContext(): Context {
|
||||
return this._context;
|
||||
}
|
||||
|
||||
getName(): string {
|
||||
return this._name;
|
||||
}
|
||||
|
||||
abstract onMounted(ctx: Context): void;
|
||||
|
||||
abstract onMapping(container: IOCContainer): void;
|
||||
|
||||
onDestroy(): void {
|
||||
this.removeObserve(...this._observeNames);
|
||||
}
|
||||
|
||||
// 移除观察者
|
||||
removeObserve(...names: string[]): void {
|
||||
const manager = this._context.getObserverManager();
|
||||
names.forEach((name) => {
|
||||
manager.removeObserver(name, this._name);
|
||||
});
|
||||
}
|
||||
|
||||
// 获取其它插件实例
|
||||
getPluginByName<T extends Plugin>(name: string): Nullable<T> {
|
||||
return this._context.getPluginManager().getPluginByName<T>(name);
|
||||
}
|
||||
|
||||
// 注册观察者
|
||||
addObserve(...names: string[]): void {
|
||||
const manager = this._context.getObserverManager();
|
||||
names.forEach((name) => {
|
||||
if (!this._observeNames.includes(name)) {
|
||||
this._observeNames.push(name);
|
||||
}
|
||||
manager.addObserver(name, this._name, new Observable());
|
||||
});
|
||||
}
|
||||
|
||||
// 获取观察者
|
||||
getObserver<T>(name: keyof O): Nullable<Observable<T>> {
|
||||
const manager = this._context.getObserverManager();
|
||||
return manager.getObserver<T, O>(name, this._name);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## 总结
|
||||
|
||||
以上就是我们在 UniverSheet 3.0 重构时候,关于插件化架构的设计和思考,项目还在不断优化和迭代,也有很多不足的地方,欢迎指出探讨。
|
||||
|
||||
最新源码请关注我们的官方 GitHub 仓库: <https://github.com/dream-num/UniverSheet>
|
||||
|
||||
## 参考
|
||||
|
||||
- [UniverSheet](https://github.com/dream-num/UniverSheet)
|
||||
- [前端进阶:跟着开源项目学习插件化架构](https://zhuanlan.zhihu.com/p/149973342)
|
||||
@@ -0,0 +1 @@
|
||||
Implementation of front-end plug-in architecture in UniverSheet 3.0
|
||||
@@ -0,0 +1,118 @@
|
||||
# 前端 IOC 依赖注入在 UniverSheet 3.0 的实现
|
||||
|
||||
## 介绍
|
||||
|
||||
在软件工程中,依赖项注入是一种技术,通过它一个对象(或静态方法)可以提供另一个对象的依赖项。依赖项是可以使用的对象(服务)。
|
||||
在理解它在编程中的含义之前,首先让我们了解一下它的总体含义,这可以帮助我们更好地理解这个概念。
|
||||
依赖是指依靠某种东西来获得支持。比如我会说我们对手机的依赖程度过高。
|
||||
|
||||
在讨论依赖注入之前,我们先理解编程中的依赖是什么意思。
|
||||
当 class A 使用 class B 的某些功能时,则表示 class A 具有 class B 依赖。
|
||||
在 Java 中,在使用其他 class 的方法之前,我们首先需要创建那个 class 的对象(即 class A 需要创建一个 class B 实例)。
|
||||
因此,将创建对象的任务转移给其他 class,并直接使用依赖项的过程,被称为“依赖项注入”。
|
||||
|
||||
## 需求
|
||||
|
||||
为什么需要使用依赖注入?
|
||||
|
||||
假设我们有一个 car class,其中包含各种对象,例如车轮、引擎等。
|
||||
这里的 car class 负责创建所有依赖对象。现在,如果我们决定将来放弃 MRFWheels,而希望使用 Yokohama 车轮,该怎么办?
|
||||
我们将需要使用新的 Yokohama 依赖关系来重新创建 car 对象。但是,当使用依赖注入(DI)时,我们可以在运行时更改车轮 wheels(因为可以在运行时而不是在编译时注入依赖项)。
|
||||
|
||||
你可以将依赖注入视为代码中的中间人,它负责创建想要的 wheels 对象,并将其提供给 car class。
|
||||
它使 car class 不需要创建车轮 wheels、电池 battery 对象等。
|
||||
|
||||
## 设计
|
||||
|
||||
组件之间依赖关系由容器在运行期决定,形象的说,即由容器动态的将某个依赖关系注入到组件之中。依赖注入的目的并非为软件系统带来更多功能,而是为了提升组件重用的频率,并为系统搭建一个灵活、可扩展的平台。通过依赖注入机制,我们只需要通过简单的配置,而无需任何代码就可指定目标需要的资源,完成自身的业务逻辑,而不需要关心具体的资源来自何处,由谁实现。
|
||||
|
||||
理解 DI 的关键是:“谁依赖谁,为什么需要依赖,谁注入谁,注入了什么”,那我们来深入分析一下:
|
||||
|
||||
- 谁依赖于谁:当然是应用程序依赖于 IoC 容器;
|
||||
- 为什么需要依赖:应用程序需要 IoC 容器来提供对象需要的外部资源;
|
||||
- 谁注入谁:很明显是 IoC 容器注入应用程序里依赖的对象;
|
||||
- 注入了什么:就是注入某个对象所需要的外部资源/依赖。
|
||||
|
||||
依赖注入明确描述了 “被注入对象依赖 IoC 容器配置依赖对象”,依赖注入是控制反转设计思想的一种实现。
|
||||
|
||||
## 原理
|
||||
|
||||
提供一个依赖管理的容器 “IOCContainer” 以及一个添加依赖项的方法 “addMapping”, 该方法接受 2 个参数 “依赖项的名称” 和 “依赖性项的 class 类型”,因为 javascript 不支持类型,所以依赖项的名称是必须的,指定依赖的名称也可以防止在 webpack 这类包管理工具中使用代码混淆,造成找不到类型的问题
|
||||
|
||||
```ts
|
||||
class IOCContainer {
|
||||
addMapping(name: string, type: Class) {
|
||||
// ...
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
我们使用一个全局的 Map 管理所有的依赖项
|
||||
|
||||
```ts
|
||||
class IOCContainer {
|
||||
Map<string, Class>
|
||||
}
|
||||
```
|
||||
|
||||
getInstance 是我们从容器中获取依赖项的方法,它接受两个参数一个是依赖项的名称,另外一个是依赖项的作用域类型,这里我们提供 2 中作用域类型,“单例作用域” 以及 “多例作用域”
|
||||
|
||||
```ts
|
||||
class IOCContainer {
|
||||
getInstance(name: string, type: Scope) {
|
||||
// ...
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
现在我们已经有了一个最简单的 IOC 容器,但是还存在一个问题现在容器并不知道依赖项之间的依赖关系,我们还需要一种机制这种机制可以让容器确定谁是依赖项谁是被依赖项
|
||||
|
||||
我们使用 @Inject 注解来确定依赖项之间的关联关系
|
||||
|
||||
```ts
|
||||
function Inject(name: string): void {
|
||||
// ...
|
||||
}
|
||||
```
|
||||
|
||||
@Inject 接收一个参数 name, 用来指定依赖项的名称。
|
||||
|
||||
### 示例
|
||||
|
||||
```ts
|
||||
function bootstrap(): IOCContainer {
|
||||
const container = new IOCContainer();
|
||||
container.addMapping('Environment', Environment);
|
||||
container.addMapping('Context', Context);
|
||||
container.addMapping('UndoManager', UndoManager);
|
||||
container.addMapping('UniverSheet', UniverSheet);
|
||||
container.addMapping('PluginManager', PluginManager);
|
||||
return container;
|
||||
}
|
||||
|
||||
class Context {
|
||||
@Inject('Environment')
|
||||
private environment: Environment;
|
||||
}
|
||||
|
||||
class UniverSheet {
|
||||
@Inject('Context')
|
||||
private context: Context;
|
||||
|
||||
static newInstance(): UniverSheet {
|
||||
return bootstrap().getInstance('UniverSheet', Scope.prototype);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
以上我们就完成了一个简单版本的 IOC 容器,下面我们分析一下这个简单的 IOC 容器还存在哪些能够优化的地方
|
||||
|
||||
## 优化
|
||||
|
||||
## 总结
|
||||
|
||||
## 参考
|
||||
|
||||
- [动手造轮子:实现一个简单的依赖注入](https://www.cnblogs.com/weihanli/p/implement-dependency-injection.html)
|
||||
- [依赖注入是什么?如何使用它](https://chinese.freecodecamp.org/news/a-quick-intro-to-dependency-injection-what-it-is-and-when-to-use-it/)
|
||||
- [什么是注入,什么时候使用它](https://blog.csdn.net/weixin_39932344/article/details/110813701)
|
||||
@@ -0,0 +1,47 @@
|
||||
# 使用 preact 创建组件库
|
||||
|
||||
## 介绍
|
||||
|
||||
### 什么是 preact
|
||||
|
||||
1. React 的 3kb 轻量化方案,可替代 react
|
||||
2. Api 几乎和 react 一致
|
||||
3. 提供兼容层 preact-compat,可以无缝使用 React 生态系统中其他组件
|
||||
|
||||
### 为什么用 preact
|
||||
|
||||
1. 出色的表现
|
||||
[Preact](https://preactjs.com/) 速度很快,而不仅仅是因为它的大小。由于简单且可预测的 diff 实现,它是目前最快的虚拟 DOM 库之一。当涉及到性能时,会自动批量更新并优化 Preact。
|
||||
<br/>
|
||||
|
||||
2. 小尺寸
|
||||
大多数 UI 框架都足够大,足以占据应用程序 JavaScript 大小的大部分。Preact 有所不同:它很小,因此您的代码是应用程序中最大的部分。这意味着更少的 JavaScript 可以下载,解析和执行-为代码留出更多时间,因此您可以构建自己定义的体验,而无需努力保持框架的可控性。
|
||||
<br/>
|
||||
|
||||
3. 便携式和嵌入式
|
||||
Preact 的占地面积很小,这意味着您可以将强大的 Virtual DOM Component 范式带到其他地方无法企及的新地方。使用 Preact 无需复杂的集成即可构建应用程序的各个部分。将 Preact 嵌入到小部件中,并应用与构建完整应用程序相同的工具和技术。
|
||||
<br/>
|
||||
|
||||
4. 兼容生态系统
|
||||
通过虚拟 DOM 组件,可以轻松共享可重用的内容-从按钮到数据提供程序的所有内容。Preact 的设计意味着您可以无缝使用 React 生态系统中可用的数千个组件。在捆绑程序中添加一个简单的 preact / compat 别名即可提供一个兼容性层,该兼容性层甚至可以在您的应用程序中使用最复杂的 React 组件。
|
||||
<br/>
|
||||
|
||||
## 需求
|
||||
|
||||
市面上的 UI 组件库虽然功能丰富,稳定性高,可以按需加载,但体积还是过大,并且风格固定。
|
||||
|
||||
UniverSheet 选用 preact 和 ts 开发 UI 组件库,创建一套拥有自己风格的轻量 UI 组件库,初步设计满足自己的需求,后续可以按照需求进行扩展。
|
||||
|
||||
## 开发
|
||||
|
||||
1. 创建组件目录
|
||||
我们以 button 组件为例,为了样式可以按需引入,以及使用者可以方便修改样式,我们把 css 拿出来单独编写,当然如果你只是为了编写一个组件供少数人使用,也可以直接写在.tsx 里,一个组件包含以下文件:
|
||||
```
|
||||
├─Button
|
||||
├─index.module.less //模块样式
|
||||
|─button.tsx //组件文件
|
||||
├─index.ts //单独打包文件
|
||||
|─button.md //组件文档
|
||||
└─test
|
||||
├─index.test.tsx //测试组件
|
||||
```
|
||||
@@ -0,0 +1,42 @@
|
||||
module.exports = {
|
||||
env: {
|
||||
browser: true,
|
||||
es2021: true,
|
||||
node: true,
|
||||
},
|
||||
parser: '@typescript-eslint/parser',
|
||||
extends: ['airbnb-typescript', 'prettier', 'eslint:recommended', 'plugin:import/recommended', 'plugin:import/typescript'],
|
||||
parserOptions: {
|
||||
ecmaVersion: 12,
|
||||
sourceType: 'module',
|
||||
// project: './tsconfig.json',
|
||||
},
|
||||
plugins: ['@typescript-eslint', 'prettier', 'import'],
|
||||
rules: {
|
||||
'prettier/prettier': [
|
||||
'error',
|
||||
{
|
||||
endOfLine: 'auto',
|
||||
},
|
||||
],
|
||||
'import/prefer-default-export': 'off',
|
||||
'import/no-extraneous-dependencies': ['error', { devDependencies: true }],
|
||||
// turn on errors for missing imports
|
||||
'import/no-unresolved': 'error',
|
||||
},
|
||||
settings: {
|
||||
'import/parsers': {
|
||||
'@typescript-eslint/parser': ['.ts', '.tsx'],
|
||||
},
|
||||
'import/resolver': {
|
||||
typescript: {
|
||||
alwaysTryTypes: true, // always try to resolve config under `<root>@config` directory even it doesn't contain any source code, like `@config/unist`
|
||||
|
||||
// Choose from one of the "project" configs below or omit to use <root>/tsconfig.json by default
|
||||
|
||||
// use <root>/path/to/folder/tsconfig.json
|
||||
project: './tsconfig.json',
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
@@ -0,0 +1,101 @@
|
||||
#ide
|
||||
*.DS_Store
|
||||
.idea
|
||||
.vscode
|
||||
|
||||
#npm
|
||||
package-lock.json
|
||||
|
||||
dist
|
||||
lib
|
||||
docs/.vuepress/dist
|
||||
|
||||
# Logs
|
||||
logs
|
||||
*.log
|
||||
npm-debug.log*
|
||||
yarn-debug.log*
|
||||
yarn-error.log*
|
||||
lerna-debug.log*
|
||||
|
||||
# Runtime config
|
||||
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
|
||||
|
||||
#lerna-changelog
|
||||
.changelog
|
||||
|
||||
|
||||
#editor workspace file
|
||||
.idea/
|
||||
|
||||
|
||||
.DS_Store
|
||||
|
||||
.history
|
||||
# examples
|
||||
|
||||
|
||||
# Production
|
||||
/build
|
||||
|
||||
# Generated files
|
||||
.docusaurus
|
||||
.cache-loader
|
||||
|
||||
# Misc
|
||||
.env.local
|
||||
.env.development.local
|
||||
.env.test.local
|
||||
.env.production.local
|
||||
@@ -0,0 +1,7 @@
|
||||
module.exports = {
|
||||
singleQuote: true,
|
||||
trailingComma: 'es5',
|
||||
tabWidth: 4,
|
||||
semi: true,
|
||||
printWidth: 180,
|
||||
};
|
||||
@@ -0,0 +1,55 @@
|
||||
# style-universheet
|
||||
|
||||
简体中文 | [English](./README.md)
|
||||
|
||||
## 介绍
|
||||
|
||||
UniverSheet Spreadsheet 插件
|
||||
|
||||
### 安装
|
||||
|
||||
```bash
|
||||
npm i @univer/preact-ts
|
||||
```
|
||||
|
||||
### 使用
|
||||
|
||||
```js
|
||||
impport {Spreadsheet} from '@univer/preact-ts'
|
||||
|
||||
const univerSheet = new UniverSheet();
|
||||
univerSheet.installPlugin(new Spreadsheet());
|
||||
```
|
||||
|
||||
## 本地开发
|
||||
|
||||
### 环境
|
||||
|
||||
- [Node.js](https://nodejs.org/en/) Version >= 10
|
||||
- [npm](https://www.npmjs.com/) Version >= 6
|
||||
|
||||
### 安装
|
||||
|
||||
```
|
||||
pnpm install
|
||||
```
|
||||
|
||||
### 开发
|
||||
|
||||
```
|
||||
# 当前目录 ./packages/preact-ts/
|
||||
npm run dev
|
||||
|
||||
# 或者项目根目录 ./
|
||||
pnpm run --filter @univer/preact-ts dev
|
||||
```
|
||||
|
||||
### 打包
|
||||
|
||||
```
|
||||
# 当前目录 ./packages/preact-ts/
|
||||
npm run build
|
||||
|
||||
# 或者根目录 ./
|
||||
pnpm run --filter @univer/preact-ts build
|
||||
```
|
||||
@@ -0,0 +1,55 @@
|
||||
# style-universheet
|
||||
|
||||
English| [简体中文](./README-zh.md)
|
||||
|
||||
## Introduction
|
||||
|
||||
UniverSheet Plugin Spreadsheet
|
||||
|
||||
### Installation
|
||||
|
||||
```bash
|
||||
npm i @univer/preact-ts
|
||||
```
|
||||
|
||||
### Usage
|
||||
|
||||
```js
|
||||
impport {Spreadsheet} from '@univer/preact-ts'
|
||||
|
||||
const univerSheet = new UniverSheet();
|
||||
univerSheet.installPlugin(new Spreadsheet());
|
||||
```
|
||||
|
||||
## Local development
|
||||
|
||||
### Requirements
|
||||
|
||||
- [Node.js](https://nodejs.org/en/) Version >= 10
|
||||
- [npm](https://www.npmjs.com/) Version >= 6
|
||||
|
||||
### Installation
|
||||
|
||||
```
|
||||
pnpm install
|
||||
```
|
||||
|
||||
### Development
|
||||
|
||||
```
|
||||
# Current directory ./packages/preact-ts/
|
||||
npm run dev
|
||||
|
||||
# Or project root directory ./
|
||||
pnpm run --filter @univer/preact-ts dev
|
||||
```
|
||||
|
||||
### Package
|
||||
|
||||
```
|
||||
# Current directory ./packages/preact-ts/
|
||||
npm run build
|
||||
|
||||
# Or root directory ./
|
||||
pnpm run --filter @univer/preact-ts build
|
||||
```
|
||||
@@ -0,0 +1,23 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<link rel="icon" type="image/svg+xml" href="favicon.svg" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>UniverSheet</title>
|
||||
<style>
|
||||
html,
|
||||
body {
|
||||
height: 100%;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div id="app" style="z-index: 1; position: fixed; font-size: 20px; color: green;"></div>
|
||||
<div id="universheet-demo-up" style="height: 100%;"></div>
|
||||
<script type="module" src="/src/main.tsx"></script>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
@@ -0,0 +1,18 @@
|
||||
/** @type {import('ts-jest/dist/types').InitialOptionsTsJest} */
|
||||
module.exports = {
|
||||
preset: 'ts-jest',
|
||||
testEnvironment: 'jsdom',
|
||||
moduleFileExtensions: ['js', 'ts', 'tsx'],
|
||||
|
||||
roots: ['<rootDir>/src'],
|
||||
testMatch: ['**/__tests__/**/*.+(ts|tsx|js)', '**/?(*.)+(spec|test).+(ts|tsx|js)'],
|
||||
transform: {
|
||||
'^.+\\.(ts|tsx)$': 'ts-jest',
|
||||
'^.+\\.tsx?$': 'babel-jest', // https://github.com/kulshekhar/ts-jest/issues/937#issuecomment-455431207
|
||||
},
|
||||
globals: {
|
||||
'ts-jest': {
|
||||
tsConfig: 'tsconfig.test.json',
|
||||
},
|
||||
},
|
||||
};
|
||||
@@ -0,0 +1,67 @@
|
||||
{
|
||||
"name": "univer-preact-ts",
|
||||
"version": "0.0.1",
|
||||
"description": "UniverSheet normal preact-ts",
|
||||
"keywords": [],
|
||||
"author": "DreamNum <msoffice2@126.com>",
|
||||
"license": "MIT",
|
||||
"main": "./src/index.ts",
|
||||
"module": "./src/index.ts",
|
||||
"types": "./src/Types/index.d.ts",
|
||||
"exports": {
|
||||
".": "./src/index.ts",
|
||||
"./*": "./src/*"
|
||||
},
|
||||
"publishConfig": {
|
||||
"main": "./lib/univer-preact-ts.umd.js",
|
||||
"module": "./lib/univer-preact-ts.es.js",
|
||||
"types": "./lib/univer-preact-ts.d.ts"
|
||||
},
|
||||
"directories": {
|
||||
"lib": "lib"
|
||||
},
|
||||
"scripts": {
|
||||
"test": "jest",
|
||||
"dev": "vite",
|
||||
"build": "tsc && vite build",
|
||||
"serve": "vite preview"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@preact/preset-vite": "2.0.0",
|
||||
"@testing-library/preact": "^2.0.1",
|
||||
"@types/jest": "^27.5.2",
|
||||
"@types/node": "^16.4.6",
|
||||
"@vitejs/plugin-legacy": "^1.5.1",
|
||||
"enzyme": "^3.11.0",
|
||||
"enzyme-adapter-preact-pure": "^3.3.0",
|
||||
"eslint": "^8.22.0",
|
||||
"eslint-config-airbnb-typescript": "^17.0.0",
|
||||
"eslint-config-prettier": "^8.3.0",
|
||||
"eslint-plugin-import": "^2.23.4",
|
||||
"eslint-plugin-jsx-a11y": "^6.5.1",
|
||||
"eslint-plugin-prettier": "^3.4.0",
|
||||
"eslint-plugin-react": "^7.28.0",
|
||||
"eslint-plugin-react-hooks": "^4.3.0",
|
||||
"identity-obj-proxy": "^3.0.0",
|
||||
"jest-dev-server": "^6.1.1",
|
||||
"jest-environment-jsdom": "^29.0.3",
|
||||
"less": "^4.1.1",
|
||||
"prettier": "^2.3.2",
|
||||
"ts-jest": "29.0.1",
|
||||
"ts-node": "^10.2.1",
|
||||
"typescript": "^4.4.1-rc",
|
||||
"vite": "^2.4.4",
|
||||
"vite-plugin-external": "1.2.3"
|
||||
},
|
||||
"dependencies": {
|
||||
"@univer/base-component": "^0.0.1",
|
||||
"@univer/base-render": "^0.0.1",
|
||||
"@univer/core": "^0.0.1",
|
||||
"@univer/sheets-plugin-alternating-colors": "^0.0.1",
|
||||
"@univer/sheets-plugin-filter": "^0.0.1",
|
||||
"@univer/base-sheets": "^0.0.1",
|
||||
"@univer/style-universheet": "^0.0.1",
|
||||
"csstype": "^3.0.11",
|
||||
"preact": "^10.5.14"
|
||||
}
|
||||
}
|
||||
+15
@@ -0,0 +1,15 @@
|
||||
/// <reference types="vite/client" />
|
||||
|
||||
export * from '../index';
|
||||
declare module '@univer/custom-build' {}
|
||||
|
||||
import JSX = preact.JSX;
|
||||
|
||||
declare module 'es6-proxy-polyfill';
|
||||
// declare module '*.less';
|
||||
|
||||
// use css module
|
||||
declare module '*.less' {
|
||||
const resource: { [key: string]: string };
|
||||
export = resource;
|
||||
}
|
||||
+2
@@ -0,0 +1,2 @@
|
||||
export * from './index';
|
||||
declare module '@univer/style-universheet' {}
|
||||
@@ -0,0 +1,35 @@
|
||||
import { IStyleConfig } from '@univer/base-component';
|
||||
import { IWorkbookConfig, UniverSheet } from '@univer/core';
|
||||
import { FilterPlugin } from '@univer/sheets-plugin-filter';
|
||||
import { SpreadsheetPlugin } from '@univer/base-sheets';
|
||||
import { StyleUniver } from '@univer/style-universheet';
|
||||
|
||||
interface IPropsCustom {
|
||||
workbookConfig?: Partial<IWorkbookConfig>;
|
||||
spreadsheetConfig?: IStyleConfig;
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize the core and all plugins
|
||||
*/
|
||||
class UniverSheetCustom {
|
||||
constructor() {}
|
||||
init(config: IPropsCustom = {}): UniverSheet {
|
||||
const univerSheetUp = UniverSheet.newInstance(config.workbookConfig);
|
||||
|
||||
univerSheetUp.installPlugin(new StyleUniver(config.spreadsheetConfig));
|
||||
univerSheetUp.installPlugin(new SpreadsheetPlugin());
|
||||
univerSheetUp.installPlugin(new FilterPlugin());
|
||||
|
||||
return univerSheetUp;
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Wrapped into a function,easy to use
|
||||
* @param config
|
||||
* @returns
|
||||
*/
|
||||
const univerSheetCustom = function (config?: IPropsCustom) {
|
||||
return new UniverSheetCustom().init(config);
|
||||
};
|
||||
export { univerSheetCustom };
|
||||
@@ -0,0 +1,30 @@
|
||||
import { univerSheetCustom } from '.';
|
||||
|
||||
const workbookConfig = {
|
||||
id: '',
|
||||
sheetOrder: [],
|
||||
socketEnable: BooleanNumber.FALSE,
|
||||
socketUrl: '',
|
||||
name: '',
|
||||
timeZone: '',
|
||||
appVersion: '',
|
||||
theme: '',
|
||||
skin: '',
|
||||
locale: '',
|
||||
creator: '',
|
||||
styles: [],
|
||||
sheets: [],
|
||||
lastModifiedBy: '',
|
||||
createdTime: '',
|
||||
modifiedTime: '',
|
||||
};
|
||||
|
||||
const spreadsheetConfig = {
|
||||
containerId: 'universheet-demo-up',
|
||||
layout: 'auto',
|
||||
};
|
||||
|
||||
const universheet = univerSheetCustom({
|
||||
workbookConfig: workbookConfig,
|
||||
spreadsheetConfig: spreadsheetConfig,
|
||||
});
|
||||
+1
@@ -0,0 +1 @@
|
||||
import JSX = preact.JSX;
|
||||
+10
@@ -0,0 +1,10 @@
|
||||
declare module 'es6-proxy-polyfill';
|
||||
// declare module '*.less';
|
||||
|
||||
// use css module
|
||||
declare module '*.less' {
|
||||
const resource: { [key: string]: string };
|
||||
export = resource;
|
||||
}
|
||||
|
||||
declare module 'enzyme';
|
||||
+1
@@ -0,0 +1 @@
|
||||
/// <reference types="vite/client" />
|
||||
@@ -0,0 +1,31 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"rootDir": "./",
|
||||
"outDir": "lib",
|
||||
"target": "ESNext",
|
||||
|
||||
"lib": ["ESNext", "DOM", "WebWorker"],
|
||||
"module": "ESNext",
|
||||
"moduleResolution": "Node", //This value is needed for Node.js.
|
||||
|
||||
"declaration": true,
|
||||
"declarationDir": "./lib",
|
||||
"declarationMap": true,
|
||||
"sourceMap": true,
|
||||
"resolveJsonModule": true,
|
||||
"strict": true,
|
||||
"allowJs": true,
|
||||
|
||||
"baseUrl": "./",
|
||||
"skipLibCheck": true,
|
||||
"esModuleInterop": true, // auto allowSyntheticDefaultImports tru
|
||||
"suppressImplicitAnyIndexErrors": true,
|
||||
"experimentalDecorators": true,
|
||||
"jsx": "preserve",
|
||||
"jsxFactory": "h",
|
||||
"jsxFragmentFactory": "Fragment",
|
||||
"strictPropertyInitialization": false,
|
||||
"types": ["jest", "node", "@types/jest"]
|
||||
},
|
||||
"include": ["src/**/*", "test/**/*.test.(ts|tsx|js)"]
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"extends": "./tsconfig.json",
|
||||
"include": ["src/**/*"],
|
||||
"compilerOptions": {
|
||||
"composite": true
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"extends": "./tsconfig.json",
|
||||
"compilerOptions": {
|
||||
"jsx": "react-jsx",
|
||||
"jsxImportSource": "preact"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
import { defineConfig } from 'vite';
|
||||
import path from 'path';
|
||||
import preact from '@preact/preset-vite';
|
||||
import legacy from '@vitejs/plugin-legacy';
|
||||
import { name, version } from './package.json';
|
||||
import createExternal from 'vite-plugin-external';
|
||||
|
||||
const resolve = (url: string) => path.resolve(__dirname, url);
|
||||
|
||||
export default defineConfig({
|
||||
build: {
|
||||
lib: {
|
||||
entry: resolve('src/index.ts'),
|
||||
name: 'UniverSheetCustomBuild',
|
||||
formats: ['es', 'umd'],
|
||||
fileName: 'univer-custom-build',
|
||||
},
|
||||
outDir: './lib',
|
||||
},
|
||||
define: {
|
||||
pkgJson: { name, version },
|
||||
},
|
||||
css: {
|
||||
modules: {
|
||||
localsConvention: 'camelCaseOnly', // dash to camelCase conversion// .apply-color -> applyColor
|
||||
generateScopedName: 'univer-[local]', // custom prefix class name
|
||||
},
|
||||
preprocessorOptions: {
|
||||
less: {
|
||||
javascriptEnabled: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
server: {
|
||||
port: 3103,
|
||||
open: true, // Automatically open the app in the browser on server start.
|
||||
},
|
||||
plugins: [
|
||||
preact(),
|
||||
// legacy({
|
||||
// targets: ['ie >= 11'],
|
||||
// additionalLegacyPolyfills: ['regenerator-runtime/runtime'],
|
||||
// }),
|
||||
createExternal({
|
||||
externals: {
|
||||
// '@univer/core': '@univer/core',
|
||||
// '@univer/style-universheet': '@univer/style-universheet',
|
||||
// preact: 'preact',
|
||||
},
|
||||
}),
|
||||
],
|
||||
});
|
||||
@@ -0,0 +1,51 @@
|
||||
module.exports = {
|
||||
env: {
|
||||
browser: true,
|
||||
es2021: true,
|
||||
node: true,
|
||||
},
|
||||
parser: '@typescript-eslint/parser',
|
||||
extends: [
|
||||
'airbnb-typescript',
|
||||
'prettier',
|
||||
'eslint:recommended',
|
||||
'plugin:import/recommended',
|
||||
'plugin:import/typescript',
|
||||
],
|
||||
parserOptions: {
|
||||
ecmaVersion: 12,
|
||||
sourceType: 'module',
|
||||
project: './tsconfig.json',
|
||||
},
|
||||
plugins: ['@typescript-eslint', 'prettier', 'import'],
|
||||
rules: {
|
||||
'prettier/prettier': [
|
||||
'error',
|
||||
{
|
||||
endOfLine: 'auto',
|
||||
},
|
||||
],
|
||||
'import/prefer-default-export': 'off',
|
||||
'import/no-extraneous-dependencies': [
|
||||
'error',
|
||||
{ devDependencies: true },
|
||||
],
|
||||
// turn on errors for missing imports
|
||||
'import/no-unresolved': 'error',
|
||||
},
|
||||
settings: {
|
||||
'import/parsers': {
|
||||
'@typescript-eslint/parser': ['.ts', '.tsx'],
|
||||
},
|
||||
'import/resolver': {
|
||||
typescript: {
|
||||
alwaysTryTypes: true, // always try to resolve config under `<root>@config` directory even it doesn't contain any source code, like `@config/unist`
|
||||
|
||||
// Choose from one of the "project" configs below or omit to use <root>/tsconfig.json by default
|
||||
|
||||
// use <root>/path/to/folder/tsconfig.json
|
||||
project: './tsconfig.json',
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
@@ -0,0 +1,101 @@
|
||||
#ide
|
||||
*.DS_Store
|
||||
.idea
|
||||
.vscode
|
||||
|
||||
#npm
|
||||
package-lock.json
|
||||
|
||||
dist
|
||||
lib
|
||||
docs/.vuepress/dist
|
||||
|
||||
# Logs
|
||||
logs
|
||||
*.log
|
||||
npm-debug.log*
|
||||
yarn-debug.log*
|
||||
yarn-error.log*
|
||||
lerna-debug.log*
|
||||
|
||||
# Runtime config
|
||||
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
|
||||
|
||||
#lerna-changelog
|
||||
.changelog
|
||||
|
||||
|
||||
#editor workspace file
|
||||
.idea/
|
||||
|
||||
|
||||
.DS_Store
|
||||
|
||||
.history
|
||||
# examples
|
||||
|
||||
|
||||
# Production
|
||||
/build
|
||||
|
||||
# Generated files
|
||||
.docusaurus
|
||||
.cache-loader
|
||||
|
||||
# Misc
|
||||
.env.local
|
||||
.env.development.local
|
||||
.env.test.local
|
||||
.env.production.local
|
||||
@@ -0,0 +1,6 @@
|
||||
module.exports = {
|
||||
singleQuote: true,
|
||||
trailingComma: 'es5',
|
||||
tabWidth: 4,
|
||||
semi: true,
|
||||
};
|
||||
@@ -0,0 +1,31 @@
|
||||
# univer-vanilla-ts
|
||||
|
||||
简体中文 | [English](./README.md)
|
||||
|
||||
## 介绍
|
||||
|
||||
UniverSheet原生ts项目案例
|
||||
|
||||
## 用法
|
||||
|
||||
### 环境
|
||||
|
||||
- [Node.js](https://nodejs.org/en/) Version >= 10
|
||||
|
||||
### 安装
|
||||
|
||||
```
|
||||
npm i
|
||||
```
|
||||
|
||||
### 开发
|
||||
|
||||
```
|
||||
npm run dev
|
||||
```
|
||||
|
||||
### 打包
|
||||
|
||||
```
|
||||
npm run build
|
||||
```
|
||||
@@ -0,0 +1,31 @@
|
||||
# univer-vanilla-ts
|
||||
|
||||
English| [简体中文](./README-zh.md)
|
||||
|
||||
## Introduction
|
||||
|
||||
UniverSheet vanilla ts project case
|
||||
|
||||
## Usage
|
||||
|
||||
### Requirements
|
||||
|
||||
- [Node.js](https://nodejs.org/en/) Version >= 10
|
||||
|
||||
### Installation
|
||||
|
||||
```
|
||||
npm i
|
||||
```
|
||||
|
||||
### Development
|
||||
|
||||
```
|
||||
npm run dev
|
||||
```
|
||||
|
||||
### Package
|
||||
|
||||
```
|
||||
npm run build
|
||||
```
|
||||
@@ -0,0 +1,21 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<link rel="icon" type="image/svg+xml" href="favicon.svg" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>UniverSheet</title>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div id="universheet-demo-up"></div>
|
||||
<!-- <br />
|
||||
<hr />
|
||||
<br /> -->
|
||||
<div id="universheet-demo-down"></div>
|
||||
<div id='app'></div>
|
||||
<script type="module" src="/src/main.tsx"></script>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
@@ -0,0 +1,47 @@
|
||||
{
|
||||
"name": "univer-vanilla-ts",
|
||||
"version": "0.0.1",
|
||||
"description": "UniverSheet vanilla ts demo project",
|
||||
"keywords": [],
|
||||
"author": "DreamNum <msoffice2@126.com>",
|
||||
"license": "MIT",
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"test": "echo \"Error: run tests from root\" && exit 1",
|
||||
"dev": "vite",
|
||||
"build": "tsc && vite build",
|
||||
"serve": "vite preview"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@preact/preset-vite": "^2.1.0",
|
||||
"@types/jest": "^27.5.2",
|
||||
"@types/node": "^16.4.6",
|
||||
"@vitejs/plugin-legacy": "^1.5.1",
|
||||
"debug": "^4.3.3",
|
||||
"enzyme": "^3.11.0",
|
||||
"enzyme-adapter-preact-pure": "^3.3.0",
|
||||
"eslint": "^8.22.0",
|
||||
"eslint-config-airbnb-typescript": "^17.0.0",
|
||||
"eslint-config-prettier": "^8.3.0",
|
||||
"eslint-plugin-import": "^2.23.4",
|
||||
"eslint-plugin-jsx-a11y": "^6.5.1",
|
||||
"eslint-plugin-prettier": "^3.4.0",
|
||||
"eslint-plugin-react": "^7.28.0",
|
||||
"eslint-plugin-react-hooks":"^4.3.0",
|
||||
"identity-obj-proxy": "^3.0.0",
|
||||
"jest-dev-server": "^6.1.1",
|
||||
"jest-environment-jsdom": "^29.0.3",
|
||||
"less": "^4.1.1",
|
||||
"prettier": "^2.3.2",
|
||||
"typescript": "^4.4.1-rc",
|
||||
"vite": "^2.4.4",
|
||||
"vite-plugin-external": "1.2.3"
|
||||
},
|
||||
"dependencies": {
|
||||
"@univer/base-component": "^0.0.1",
|
||||
"@univer/core": "^0.0.1",
|
||||
"@univer/style-universheet": "^0.0.1",
|
||||
"csstype": "^3.0.11",
|
||||
"preact": "^10.5.14"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
export function App() {
|
||||
return (
|
||||
<>
|
||||
<div>按钮</div>
|
||||
</>
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
#universheet-demo-up {
|
||||
width: 100%;
|
||||
height: 50vh;
|
||||
}
|
||||
#universheet-demo-down {
|
||||
width: 100%;
|
||||
height: 40vh;
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
}
|
||||
@@ -0,0 +1,74 @@
|
||||
// import { UniverSheet } from '@univer/core';
|
||||
// import {
|
||||
// ForceCalculationTypes,
|
||||
// IDefaultFormat,
|
||||
// IWorkbookData,
|
||||
// IWorkbookProperties,
|
||||
// RecalculationInterval,
|
||||
// } from '@univer/core';
|
||||
|
||||
// import { StyleUniver } from '@univer/style-universheet';
|
||||
// import './assets/css/style.less'
|
||||
|
||||
// const defaultDefaultFormat: IDefaultFormat = {};
|
||||
// const defaultWorkbookProperties: IWorkbookProperties = {
|
||||
// name: 'universheet', // File name
|
||||
// creator: '', // Create user
|
||||
// lastmodifiedby: '', // Edit user
|
||||
// createdTime: '',
|
||||
// modifiedTime: '',
|
||||
// company: '梦数科技',
|
||||
// appversion: '3.0.0', // Excel version, Is it necessary?
|
||||
// Locale: 'zh',
|
||||
// timeZone: 'UTC/GMT +8',
|
||||
// defaultFormat: defaultDefaultFormat,
|
||||
// forceCalculation: ForceCalculationTypes.ON,
|
||||
// autoRecalculation: RecalculationInterval.HOUR,
|
||||
// maxIterations: 1,
|
||||
// };
|
||||
// const defaultWorkbookData: IWorkbookData = {
|
||||
// properties: defaultWorkbookProperties,
|
||||
// data: [],
|
||||
// pluginMetaData: {},
|
||||
// userMetaData: {}, // 用户自定义数据
|
||||
// spreadsheetUrl: '',
|
||||
// spreadsheetKey: '',
|
||||
// };
|
||||
|
||||
|
||||
|
||||
// const uiDefaultConfigUp = {
|
||||
// containerId: 'universheet-demo-up',
|
||||
// layout: 'auto'
|
||||
// }
|
||||
// const uiDefaultConfigDown = {
|
||||
// containerId: 'universheet-demo-down',
|
||||
// layout: {
|
||||
// outerLeft: false,
|
||||
|
||||
// outerRight: true,
|
||||
|
||||
// innerLeft: false,
|
||||
|
||||
// innerRight: false,
|
||||
// }
|
||||
// }
|
||||
// // univerSheetUp.installPlugin(new StyleUniver(uiDefaultConfigUp))
|
||||
// // univerSheetDown.installPlugin(new StyleUniver(uiDefaultConfigDown))
|
||||
|
||||
// const univerSheetUp = new UniverSheet(defaultWorkbookData, {
|
||||
// plugins: [
|
||||
// new StyleUniver(uiDefaultConfigUp)
|
||||
// ]
|
||||
// });
|
||||
// const univerSheetDown = new UniverSheet(defaultWorkbookData, {
|
||||
// plugins: [
|
||||
// new StyleUniver(uiDefaultConfigDown)
|
||||
// ]
|
||||
// });
|
||||
|
||||
|
||||
import { render } from 'preact'
|
||||
import { App } from './app'
|
||||
|
||||
render(<App />, document.getElementById('app')!)
|
||||
+1
@@ -0,0 +1 @@
|
||||
import JSX = preact.JSX;
|
||||
+8
@@ -0,0 +1,8 @@
|
||||
// declare module '*.less';
|
||||
|
||||
// use css module
|
||||
declare module '*.less' {
|
||||
const resource: { [key: string]: string };
|
||||
export = resource;
|
||||
}
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
/// <reference types="vite/client" />
|
||||
@@ -0,0 +1,27 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"rootDir": "./",
|
||||
"outDir": "lib",
|
||||
"target": "ESNext",
|
||||
|
||||
"lib": ["ESNext", "DOM", "WebWorker"],
|
||||
"module": "ESNext",
|
||||
"moduleResolution": "Node", //This value is needed for Node.js.
|
||||
|
||||
"declaration": true,
|
||||
"declarationDir": "./lib",
|
||||
"declarationMap": true,
|
||||
"sourceMap": true,
|
||||
"resolveJsonModule": true,
|
||||
"strict": true,
|
||||
"allowJs": true,
|
||||
|
||||
"baseUrl": "./",
|
||||
"skipLibCheck": true,
|
||||
"esModuleInterop": true, // auto allowSyntheticDefaultImports true
|
||||
"jsx": "preserve",
|
||||
"jsxFactory": "h",
|
||||
"jsxFragmentFactory": "Fragment"
|
||||
},
|
||||
"include": ["src/**/*", "test/**/*.test.(ts|tsx|js)"]
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"extends": "./tsconfig.json",
|
||||
"include": ["src/**/*"],
|
||||
"compilerOptions": {
|
||||
"composite": true
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
import { defineConfig } from 'vite';
|
||||
import path from 'path';
|
||||
import legacy from '@vitejs/plugin-legacy';
|
||||
import { name, version } from './package.json';
|
||||
import preact from '@preact/preset-vite';
|
||||
|
||||
const resolve = (url: string) => path.resolve(__dirname, url);
|
||||
|
||||
export default defineConfig({
|
||||
build: {
|
||||
// lib: {
|
||||
// entry: resolve('src/index.ts'),
|
||||
// name: 'BaseWebUI',
|
||||
// formats: ['es', 'umd'],
|
||||
// fileName: 'index',
|
||||
// },
|
||||
// outDir: './lib',
|
||||
},
|
||||
define: {
|
||||
pkgJson: { name, version },
|
||||
},
|
||||
esbuild: {
|
||||
// jsxFactory: 'DOMcreateElement',
|
||||
// jsxFragment: 'DOMcreateFragment',
|
||||
// jsxInject: `import { DOMcreateElement, DOMcreateFragment } from '@/dom-helper/jsxFactory';`,
|
||||
},
|
||||
resolve: {
|
||||
alias: {
|
||||
'@': path.resolve(__dirname, 'src'),
|
||||
},
|
||||
},
|
||||
css: {
|
||||
modules: {
|
||||
localsConvention: 'camelCaseOnly', // dash to camelCase conversion// .apply-color -> applyColor
|
||||
},
|
||||
},
|
||||
server: {
|
||||
port: 3101,
|
||||
open: true, // Automatically open the app in the browser on server start.
|
||||
},
|
||||
plugins: [
|
||||
preact(),
|
||||
legacy({
|
||||
targets: ['ie >= 11'],
|
||||
additionalLegacyPolyfills: ['regenerator-runtime/runtime'],
|
||||
}),
|
||||
|
||||
// babel(),
|
||||
// babel({ babelHelpers: 'bundled' }),
|
||||
],
|
||||
});
|
||||
@@ -0,0 +1,67 @@
|
||||
{
|
||||
"name": "univer",
|
||||
"version": "1.0.0-pre-alpha",
|
||||
"description": "Univer,Luckysheet 2.0 upgrade version",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"test": "node scripts/test",
|
||||
"test:ui": "pnpm run --filter @univer/style-universheet test",
|
||||
"test:e2e": "pnpm run --filter @univer/base-sheets test:play",
|
||||
"dev": "node scripts/dev",
|
||||
"api": "node scripts/api",
|
||||
"lighthouse-dev": "start /B node scripts/dev && lighthouse http://127.0.0.1:3103 --output html --output-path ./report.html",
|
||||
"build": "node scripts/build.js",
|
||||
"build:customd": "cd cli/src/templates/univer-custom-build && npm run build:d",
|
||||
"clean": "npm cache clean --force && pnpm dlx rimraf node_modules **/node_modules/ package-lock.json yarn.lock pnpm-lock.yaml && pnpm install && pnpm dlx playwright install",
|
||||
"node-server": "node scripts/server.js",
|
||||
"univer-cli": "cd cli && npm run cli",
|
||||
"postinstall": "node scripts/postinstall.js",
|
||||
"prepare": "husky install",
|
||||
"lint": "lint-staged"
|
||||
},
|
||||
"author": "DreamNum <msoffice2@126.com>",
|
||||
"license": "MIT",
|
||||
"devDependencies": {
|
||||
"@changesets/cli": "^2.22.0",
|
||||
"@microsoft/api-documenter": "^7.18.1",
|
||||
"@microsoft/api-extractor": "7.25.0",
|
||||
"@playwright/test": "^1.18.1",
|
||||
"@types/jest": "28.1.8",
|
||||
"@types/node": "^13.11.1",
|
||||
"@types/numeral": "^2.0.2",
|
||||
"cross-env": "^7.0.3",
|
||||
"eslint": "8.22.0",
|
||||
"eslint-config-airbnb-base": "15.0.0",
|
||||
"eslint-plugin-import": "2.26.0",
|
||||
"eslint-config-airbnb-typescript": "17.0.0",
|
||||
"@typescript-eslint/eslint-plugin": "5.38.1",
|
||||
"@typescript-eslint/parser": "5.38.1",
|
||||
"eslint-plugin-unused-imports": "2.0.0",
|
||||
"eslint-config-prettier": "^8.3.0",
|
||||
"eslint-import-resolver-typescript": "^2.7.1",
|
||||
"eslint-plugin-import-newlines": "1.2.3",
|
||||
"eslint-plugin-jsx-a11y": "^6.5.1",
|
||||
"eslint-plugin-prettier": "^3.4.0",
|
||||
"eslint-plugin-react": "^7.28.0",
|
||||
"eslint-plugin-react-hooks": "^4.3.0",
|
||||
"execa": "^4.1.0",
|
||||
"find-process": "^1.4.7",
|
||||
"husky": "^8.0.1",
|
||||
"jest": "29.0.0",
|
||||
"lighthouse": "^9.4.0",
|
||||
"lint-staged": "^13.0.3",
|
||||
"nodemon": "^2.0.3",
|
||||
"prettier": "^2.3.2",
|
||||
"rimraf": "^3.0.2",
|
||||
"tree-kill": "^1.2.2",
|
||||
"ts-jest": "29.0.1",
|
||||
"ts-node": "^10.2.1",
|
||||
"typescript": "^4.4.1-rc"
|
||||
},
|
||||
"lint-staged": {
|
||||
"./packages/**/*.ts?(x)": [
|
||||
"eslint --fix",
|
||||
"git add"
|
||||
]
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user