Skip to content

Commit

Permalink
Merge branch 'dev'
Browse files Browse the repository at this point in the history
  • Loading branch information
hmydgz committed Jun 18, 2024
2 parents a214093 + 8361145 commit 09a6efd
Show file tree
Hide file tree
Showing 5 changed files with 207 additions and 59 deletions.
95 changes: 56 additions & 39 deletions .github/workflows/build.adtion.yml
Original file line number Diff line number Diff line change
@@ -1,39 +1,56 @@
# name: Build

# on:
# push:
# tags:
# - "v*"
# branches:
# - main

# jobs:
# build:
# runs-on: ubuntu-latest
# steps:
# - name: Checkout
# uses: actions/checkout@v3

# - name: 安装 Node.js
# uses: actions/setup-node@v3
# with:
# node-version: 18
# registry-url: https://registry.npmjs.org/

# - name: 安装依赖
# run: npm i

# - name: 安装 vsce
# run: npm install -g vsce

# # - name: 编译
# # run: vsce package -o dist.vsix

# # - name: 上传
# # uses: actions/upload-artifact@v3
# # with:
# # name: code-coverage-report
# # path: dist.vsix

# - name: 编译上传
# run: vsce publish -p ${{ secrets.VSCODE_PUBLISHER_TOKEN }}
name: Build

on:
push:
tags:
- "v*"

jobs:
build:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v3
with:
ref: main

- name: 安装 Node.js
uses: actions/setup-node@v3
with:
node-version: 18
registry-url: https://registry.npmjs.org/

- name: 安装依赖
run: npm i

- name: 安装 vsce
run: npm install -g vsce

- name: 获取版本号
id: get_tag
run: |
TAG_NAME=${GITHUB_REF#refs/tags/}
VERSION=${TAG_NAME#v}
echo "VERSION=$VERSION" >> $GITHUB_ENV
- name: 更新 npm 版本号
run: npm version $VERSION --no-git-tag-version
env:
VERSION: ${{ env.VERSION }}

- name: Configure git
run: |
git config --global user.name 'github-actions[bot]'
git config --global user.email 'github-actions[bot]@users.noreply.github.com'
- name: Commit changes
run: |
git add package.json
git commit -m "CI Update version to $VERSION"
git push
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
VERSION: ${{ env.VERSION }}

- name: 编译上传
run: vsce publish -p ${{ secrets.VSCODE_PUBLISHER_TOKEN }}
50 changes: 50 additions & 0 deletions .github/workflows/ci-test.action.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
name: CI test

on:
push:
tags:
- test-*
# branches:
# - ci-test

jobs:
build:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v3
with:
ref: ci-test

# - name: 安装 Node.js
# uses: actions/setup-node@v3
# with:
# node-version: 18
# registry-url: https://registry.npmjs.org/

# - name: 获取版本号
# id: get_tag
# run: |
# TAG_NAME=${GITHUB_REF#refs/tags/}
# VERSION=${TAG_NAME#v}
# echo "VERSION=$VERSION" >> $GITHUB_ENV

# - name: 更新 NPM 版本号
# run: npm version $VERSION --no-git-tag-version
# env:
# VERSION: ${{ env.VERSION }}

- name: Configure git
run: |
git config --global user.name 'github-actions[bot]'
git config --global user.email 'github-actions[bot]@users.noreply.github.com'
- name: Commit changes
run: |
git checkout ci-test
# git add package.json
# git commit -m "Update version to $VERSION"
# git push
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
VERSION: ${{ env.VERSION }}
89 changes: 75 additions & 14 deletions src/project/app/nest.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,15 @@ import { joinPath } from '../../utils';
type FilePath = string
type ModuleName = string

/**
* 默认导出
*/
const DEFAULT_KEY = '__DEFAULT__'
/**
* 匿名变量
*/
const ANONYMOUS_KEY = '__ANONYMOUS__'

export namespace Nest {
export type Controller = Omit<ControllerOptions, 'version'> & {
version?: string[]
Expand Down Expand Up @@ -224,6 +233,8 @@ export namespace Nest {
})
}

const routerModules = <ImportVarInfo[]>[]

const traverseRouters = (routeNode: ts.Node, __prefix: string) => {
if (routeNode.kind === ts.SyntaxKind.ArrayLiteralExpression) {
const arr = routeNode as ts.ArrayLiteralExpression
Expand All @@ -238,6 +249,7 @@ export namespace Nest {
if (_module) {
const _filePath = this.project.pathResolver(_moduleInfo.path, _module.path)
module.importModules.push(this.findModule(Object.assign({}, _module, { path: _filePath }), prefix))
routerModules.push(_module)
}
} else if (obj.children) {
traverseRouters(obj.children, _path ? joinPath(__prefix, _path) : __prefix)
Expand All @@ -248,6 +260,7 @@ export namespace Nest {
if (_module) {
const _filePath = this.project.pathResolver(_moduleInfo.path, _module.path)
module.importModules.push(this.findModule(Object.assign({}, _module, { path: _filePath }), __prefix))
routerModules.push(_module)
}
}
})
Expand Down Expand Up @@ -276,7 +289,9 @@ export namespace Nest {
}
})

_importModules.forEach(v => module.importModules.push(this.findModule(v)))
_importModules // 过滤使用路由模块进行注册的模块
.filter(v => routerModules.every(_v => (v.name ?? '') !== (_v.name ?? '')))
.forEach(v => module.importModules.push(this.findModule(v)))
_controllers.forEach(v => module.controllers.push(this.findController(v)))

if (!this.moduleMap.has(_moduleInfo.path)) this.moduleMap.set(_moduleInfo.path, {})
Expand All @@ -294,29 +309,75 @@ export namespace Nest {
const ast = this.getAST(_moduleInfo.path)
const controller: Controller = { mappings: [], filePath: _moduleInfo.path }

const extendsClassNameMap: Map<string, string> = new Map()
const importVarMap = this.importVarMap.get(_moduleInfo.path)!
const classMap = new Map<string, ts.Node>()

const handleClassDeclaration = (node: ts.Node) => {
const classNode = node as ts.ClassDeclaration
// 可能是匿名类
const name = classNode.name ? AST.getIdentifierName(classNode.name as ts.Identifier) : ANONYMOUS_KEY
const { isDefault, isExport, decorators } = AST.filterDecorator(classNode.modifiers!)
classMap.set(isDefault ? DEFAULT_KEY : name, node)
// 仅目标类需要继续读取信息
if (!isExport || _moduleInfo.isDefault !== isDefault || (!_moduleInfo.isDefault && _moduleInfo.name !== name)) return
// 有 Controller 装饰器
if (decorators.hasOwnProperty('Controller')) {
const options = NestDecorator.Controller.getArgs(decorators.Controller)
Object.assign(controller, options)
controller.mappings.push(...NestDecorator.RequsetMapping.getMapping(classNode, ast, _moduleInfo.path))
}

// 继承的类,子类不管有没有 Controller 装饰器都需要加上继承的 Mapping
classNode.heritageClauses?.forEach(v => {
// TODO: 类只有单继承,可以链式继承(之后再实现链式继承)
extendsClassNameMap.set(name, AST.getIdentifierName(v.types[0].expression as ts.Identifier))
})
}

AST.traverse(ast, (node, next) => {
switch (node.kind) {
case ts.SyntaxKind.ImportDeclaration:
this.saveImportVar(node as ts.ImportDeclaration)
break
case ts.SyntaxKind.ClassDeclaration: {
const classNode = node as ts.ClassDeclaration
const name = AST.getIdentifierName(classNode.name as ts.Identifier)
const { isDefault, isExport, decorators } = AST.filterDecorator(classNode.modifiers!)
if (!isExport || _moduleInfo.isDefault !== isDefault || (!_moduleInfo.isDefault && _moduleInfo.name !== name)) return
// 找到指定 Controller
if (decorators.hasOwnProperty('Controller')) {
const options = NestDecorator.Controller.getArgs(decorators.Controller)
Object.assign(controller, options)
controller.mappings = NestDecorator.RequsetMapping.getMapping(classNode, ast)
}
case ts.SyntaxKind.ClassDeclaration: { // 类声明
handleClassDeclaration(node)
} break
default:
next()
break
}
})

if (extendsClassNameMap.size) { // 处理继承
const className = _moduleInfo.isDefault ? DEFAULT_KEY : _moduleInfo.name!
// 从入参的目标类上开始找父类
const parentName = extendsClassNameMap.get(className)!
if (classMap.has(parentName)) { // 在当前文件中
const parentClassNode = classMap.get(parentName) as ts.ClassDeclaration
const { decorators } = AST.filterDecorator(parentClassNode.modifiers!)
if (decorators.hasOwnProperty('Controller')) { // 父类是 Controller
const options = NestDecorator.Controller.getArgs(decorators.Controller)
if (!controller.path && options.path) {
controller.path = Array.isArray(options.path) ? options.path : [options.path]
}
controller.mappings.push(...NestDecorator.RequsetMapping.getMapping(parentClassNode, ast, _moduleInfo.path))
controller.mappings = NestDecorator.RequsetMapping.mergeMapping(
controller.mappings,
NestDecorator.RequsetMapping.getMapping(
classMap.get(className)! as ts.ClassDeclaration,
ast,
_moduleInfo.path
)
)
} else { // TODO 父类不是 Controller,需要看整个继承链,先不管

}
} else if (importVarMap[parentName]) { // TODO 从其他地方导入的

}
}

if (!this.controllerMap.has(_moduleInfo.path)) this.controllerMap.set(_moduleInfo.path, {})
this.controllerMap.get(_moduleInfo.path)![_moduleInfo.name || 'DefaultExportModule'] = controller

Expand Down Expand Up @@ -359,15 +420,15 @@ export namespace Nest {
mapping.path.forEach(path => {
let _path = joinPath(prefix, path)
if (!_path.endsWith('/')) _path += '/'
const { version, ...rest } = mapping
const { version, filePath, ...rest } = mapping
const _versions = [...new Set([...version, ...(_controller.version ?? [])])]
if (!_versions.length) _versions.push('')
_versions.forEach(_version => {
paths.push({
...rest,
version: _version,
path: _path,
filePath: _controller.filePath
filePath: filePath || _controller.filePath,
})
})
})
Expand Down
2 changes: 1 addition & 1 deletion src/project/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -232,7 +232,7 @@ export class Project {
createApp(
'main',
path.resolve(configPath, '../', config.sourceRoot || 'src'),
config.entryFile ||'main'
config.entryFile || 'main'
)
}
}
Expand Down
30 changes: 25 additions & 5 deletions src/utils/ast.ts
Original file line number Diff line number Diff line change
Expand Up @@ -179,19 +179,20 @@ export namespace NestDecorator {
export const ReqMethodSet = new Set(['Get', 'Post', 'Put', 'Delete', 'Patch', 'All', 'Options', 'Head', 'Search'])

export type Mapping = {
method: Methods,
path: string[],
version: string[],
method: Methods
path: string[]
version: string[]
fn: ts.MethodDeclaration
fnName: string
filePath?: string
className: string
line: {
start: ts.LineAndCharacter,
start: ts.LineAndCharacter
end: ts.LineAndCharacter
}
}

export const getMapping = (classNode: ts.ClassDeclaration, ast: ts.SourceFile) => {
export const getMapping = (classNode: ts.ClassDeclaration, ast: ts.SourceFile, filePath: string) => {
const mappings: Mapping[] = []
const className = AST.getIdentifierName(classNode.name!) || ''
classNode.members.forEach(_member => {
Expand All @@ -214,6 +215,7 @@ export namespace NestDecorator {
method: key as Methods,
path: args.length ? AST.getStringList(args[0]) : [''],
version,
filePath,
fn: member,
className,
fnName: AST.getIdentifierName(member.name as ts.Identifier),
Expand All @@ -226,5 +228,23 @@ export namespace NestDecorator {

return mappings
}

/**
* 处理继承的合并 mapping , 子类覆盖父类的同名方法 mapping
*/
export const mergeMapping = (parentMappings: Mapping[], childMappings: Mapping[]) => {
const mappings: Mapping[] = [...parentMappings]

childMappings.forEach(v => {
const _index = mappings.findIndex(_v => _v.fnName === v.fnName)
if (_index === -1) {
mappings.push(v)
} else {
mappings[_index] = v
}
})

return mappings
}
}
}

0 comments on commit 09a6efd

Please sign in to comment.