├── .editorconfig ├── .eslintignore ├── .eslintrc.json ├── .github ├── ISSUE_TEMPLATE │ ├── BUG_REPORT.md │ ├── FEATURE_REQUEST.md │ └── SUPPORT_QUESTION.md ├── lock.yml ├── pull_request_template.md └── workflows │ └── nodejs.yml ├── .gitignore ├── .huskyrc ├── .npmignore ├── AUTHORS ├── CONTRIBUTING.md ├── LICENSE ├── README.md ├── README_en.md ├── assets └── logo.png ├── benchmarks ├── README.md ├── daze-with-1000-routes.js ├── daze-without-routes.js ├── express-with-1000-routes.js ├── express-without-routes.js ├── koa-with-1000-routes.js └── koa-without-routes.js ├── commitlint.config.js ├── example ├── daze ├── src │ ├── app │ │ ├── agent.ts │ │ ├── example.controller.ts │ │ ├── example.entity.ts │ │ └── schedule.ts │ ├── config │ │ ├── app.dev.ts │ │ ├── app.ts │ │ ├── cache.ts │ │ ├── database.ts │ │ ├── proxy.ts │ │ └── redis.ts │ ├── example.provider.ts │ └── index.ts └── tsconfig.json ├── jest.config.js ├── lerna.json ├── package-lock.json ├── package.json ├── packages ├── cli │ ├── CHANGELOG.md │ ├── __tests__ │ │ └── nill.spec.ts │ ├── g.d.ts │ ├── jest.config.js │ ├── package-lock.json │ ├── package.json │ ├── src │ │ ├── actions │ │ │ ├── build.ts │ │ │ ├── create.ts │ │ │ ├── dev.ts │ │ │ ├── index.ts │ │ │ ├── make.ts │ │ │ ├── routes.ts │ │ │ └── tpl-action.abstract.ts │ │ ├── bin │ │ │ └── daze.ts │ │ ├── commands │ │ │ ├── build.ts │ │ │ ├── create.ts │ │ │ ├── dev.ts │ │ │ ├── index.ts │ │ │ ├── make.ts │ │ │ └── routes.ts │ │ ├── config.interface.ts │ │ ├── defaultTsConfig.json │ │ ├── index.ts │ │ └── lib │ │ │ ├── config.ts │ │ │ ├── constants.ts │ │ │ ├── index.ts │ │ │ ├── init.ts │ │ │ ├── printer.ts │ │ │ ├── question.ts │ │ │ ├── render.ts │ │ │ ├── runner │ │ │ ├── index.ts │ │ │ ├── npm.ts │ │ │ ├── pnpm.ts │ │ │ ├── runner.ts │ │ │ └── yarn.ts │ │ │ └── ts_compile.ts │ ├── template │ │ └── application │ │ │ ├── .gitignore │ │ │ ├── daze │ │ │ ├── package.json │ │ │ ├── public │ │ │ └── .keep │ │ │ ├── src │ │ │ ├── app │ │ │ │ └── example.controller.ts │ │ │ ├── config │ │ │ │ ├── app.ts │ │ │ │ ├── cache.ts │ │ │ │ ├── cookie.ts │ │ │ │ ├── database.ts │ │ │ │ ├── logger.ts │ │ │ │ ├── redis.ts │ │ │ │ └── session.ts │ │ │ └── index.ts │ │ │ ├── tsconfig.json │ │ │ └── views │ │ │ └── hello.html │ └── tsconfig.json ├── create-app │ ├── CHANGELOG.md │ ├── README.md │ ├── jest.config.js │ ├── package.json │ ├── src │ │ └── create.ts │ └── tsconfig.json ├── framework │ ├── .npmignore │ ├── CHANGELOG.md │ ├── README.md │ ├── README_en.md │ ├── __tests__ │ │ ├── common │ │ │ ├── assets │ │ │ │ └── example.txt │ │ │ └── context.ts │ │ ├── daze │ │ │ ├── logs │ │ │ │ └── .keep │ │ │ ├── src │ │ │ │ ├── app │ │ │ │ │ ├── component │ │ │ │ │ │ ├── InjectComponent.ts │ │ │ │ │ │ └── TestLogger.ts │ │ │ │ │ ├── controller │ │ │ │ │ │ ├── autoinject.ts │ │ │ │ │ │ ├── cross.ts │ │ │ │ │ │ ├── csrf.ts │ │ │ │ │ │ ├── dto │ │ │ │ │ │ │ └── daze.dto.ts │ │ │ │ │ │ ├── example.ts │ │ │ │ │ │ ├── injectable.ts │ │ │ │ │ │ ├── middleware.ts │ │ │ │ │ │ ├── redirect.ts │ │ │ │ │ │ └── routes.ts │ │ │ │ │ ├── entities │ │ │ │ │ │ ├── comment.ts │ │ │ │ │ │ ├── profile.ts │ │ │ │ │ │ ├── role.ts │ │ │ │ │ │ └── user.ts │ │ │ │ │ ├── middleware │ │ │ │ │ │ ├── example-1.ts │ │ │ │ │ │ ├── example-2.ts │ │ │ │ │ │ └── example-order.ts │ │ │ │ │ └── service │ │ │ │ │ │ ├── example.ts │ │ │ │ │ │ └── injectable.ts │ │ │ │ ├── config │ │ │ │ │ ├── app.test.ts │ │ │ │ │ ├── app.ts │ │ │ │ │ ├── cookie.ts │ │ │ │ │ ├── custom.test.ts │ │ │ │ │ ├── custom.ts │ │ │ │ │ ├── database.ts │ │ │ │ │ ├── daze.ts │ │ │ │ │ ├── logger.ts │ │ │ │ │ └── session.ts │ │ │ │ ├── logs │ │ │ │ └── provider │ │ │ │ │ ├── app.ts │ │ │ │ │ └── test-logger-provider.ts │ │ │ └── views │ │ │ │ └── hello.html │ │ ├── features │ │ │ ├── current │ │ │ │ ├── app │ │ │ │ │ └── test.ts │ │ │ │ ├── config │ │ │ │ │ └── app.ts │ │ │ │ └── current.spec.ts │ │ │ └── index.spec.ts │ │ └── src │ │ │ ├── cluster │ │ │ ├── helpers.spec.ts │ │ │ └── worker.spec.ts │ │ │ ├── config │ │ │ └── index.spec.ts │ │ │ ├── container │ │ │ └── index.spec.ts │ │ │ ├── cookie │ │ │ └── index.spec.ts │ │ │ ├── database │ │ │ ├── builder.spec.ts │ │ │ ├── database.spec.ts │ │ │ └── init.ts │ │ │ ├── decorators │ │ │ ├── component.spec.ts │ │ │ ├── factory │ │ │ │ └── create-inject-decorator.spec.ts │ │ │ ├── ignore.spec.ts │ │ │ ├── inject.spec.ts │ │ │ ├── injectable.spec.ts │ │ │ ├── multiton.spec.ts │ │ │ ├── rest.spec.ts │ │ │ ├── route.spec.ts │ │ │ ├── validates │ │ │ │ └── index.spec.ts │ │ │ └── verb.spec.ts │ │ │ ├── errors │ │ │ ├── handle-error.spec.ts │ │ │ ├── http-error.spec.ts │ │ │ ├── illegal-argument-error.spec.ts │ │ │ ├── not-found-http-error.spec.ts │ │ │ └── validate-http-error.spec.ts │ │ │ ├── foundation │ │ │ └── middlewares │ │ │ │ ├── cross.spec.ts │ │ │ │ └── csrf.spec.ts │ │ │ ├── loader │ │ │ └── index.spec.ts │ │ │ ├── logger │ │ │ └── index.spec.ts │ │ │ ├── middleware │ │ │ └── index.spec.ts │ │ │ ├── model │ │ │ ├── init.ts │ │ │ └── model.spec.ts │ │ │ ├── pipeline │ │ │ └── index.spec.ts │ │ │ ├── request │ │ │ ├── index.spec.ts │ │ │ └── utils │ │ │ │ └── parse-body.spec.ts │ │ │ ├── resource │ │ │ ├── app │ │ │ │ ├── test.controller.ts │ │ │ │ ├── test.resource.ts │ │ │ │ └── wrap.resource.ts │ │ │ └── resource.spec.ts │ │ │ ├── response │ │ │ ├── index.spec.ts │ │ │ ├── redirect.spec.ts │ │ │ └── statusable.spec.ts │ │ │ ├── router │ │ │ └── routes.spec.ts │ │ │ ├── session │ │ │ └── helper.spec.ts │ │ │ ├── utils │ │ │ ├── message.spec.ts │ │ │ └── utils.spec.ts │ │ │ ├── validate │ │ │ ├── app │ │ │ │ ├── test.controller.ts │ │ │ │ └── test.validator.ts │ │ │ ├── feature.spec.ts │ │ │ ├── validate.spec.ts │ │ │ └── validators.spec.ts │ │ │ └── view │ │ │ └── index.spec.ts │ ├── jest.config.js │ ├── package.json │ ├── src │ │ ├── base │ │ │ ├── entity.ts │ │ │ ├── index.ts │ │ │ ├── pivot-entity.ts │ │ │ ├── resource.ts │ │ │ └── validator.ts │ │ ├── cluster │ │ │ ├── const.ts │ │ │ ├── helpers.ts │ │ │ ├── index.ts │ │ │ ├── master.ts │ │ │ └── worker.ts │ │ ├── config │ │ │ ├── config.ts │ │ │ └── index.ts │ │ ├── container │ │ │ └── index.ts │ │ ├── controller │ │ │ ├── controller-service.ts │ │ │ └── index.ts │ │ ├── decorators │ │ │ ├── autowired.ts │ │ │ ├── component-type.ts │ │ │ ├── contexts-http.ts │ │ │ ├── create-decorator.ts │ │ │ ├── cross-origin.ts │ │ │ ├── csrf.ts │ │ │ ├── disbale.ts │ │ │ ├── encrypt.ts │ │ │ ├── factory │ │ │ │ └── decorator-factory.ts │ │ │ ├── http-code.ts │ │ │ ├── ignore.ts │ │ │ ├── index.ts │ │ │ ├── inject.ts │ │ │ ├── model │ │ │ │ ├── column.ts │ │ │ │ ├── index.ts │ │ │ │ └── relation.ts │ │ │ ├── multiton.ts │ │ │ ├── order.ts │ │ │ ├── provider │ │ │ │ ├── index.ts │ │ │ │ ├── provide-on-config.ts │ │ │ │ ├── provide-on-missing.ts │ │ │ │ ├── provide-on.ts │ │ │ │ ├── provide.ts │ │ │ │ └── provider.ts │ │ │ ├── rest.ts │ │ │ ├── schedule │ │ │ │ ├── corntab.ts │ │ │ │ └── index.ts │ │ │ ├── singleton.ts │ │ │ ├── stereotype │ │ │ │ ├── agent.ts │ │ │ │ ├── component.ts │ │ │ │ ├── controller.ts │ │ │ │ ├── entity.ts │ │ │ │ ├── index.ts │ │ │ │ ├── injectable.ts │ │ │ │ ├── job.ts │ │ │ │ ├── middleware.ts │ │ │ │ ├── resourcer.ts │ │ │ │ ├── schedule.ts │ │ │ │ ├── service.ts │ │ │ │ └── validator.ts │ │ │ ├── use │ │ │ │ ├── index.ts │ │ │ │ ├── interface.ts │ │ │ │ └── use-middleware.ts │ │ │ ├── validates │ │ │ │ ├── factory.ts │ │ │ │ └── index.ts │ │ │ └── verb.ts │ │ ├── errors │ │ │ ├── handle.ts │ │ │ ├── http-error.ts │ │ │ ├── illegal-argument-error.ts │ │ │ ├── not-found-http-error.ts │ │ │ ├── validate-http-error.ts │ │ │ └── views │ │ │ │ └── errors │ │ │ │ ├── 401.njk │ │ │ │ ├── 404.njk │ │ │ │ ├── 500.njk │ │ │ │ ├── 503.njk │ │ │ │ ├── error.njk │ │ │ │ └── layout.njk │ │ ├── foundation │ │ │ ├── application.ts │ │ │ ├── auto-providers │ │ │ │ ├── common.provider.ts │ │ │ │ ├── depends │ │ │ │ │ ├── cache.provider.ts │ │ │ │ │ ├── database.provider.ts │ │ │ │ │ ├── index.ts │ │ │ │ │ ├── logger.provider.ts │ │ │ │ │ ├── mailer.provider.ts │ │ │ │ │ ├── messenger.provider.ts │ │ │ │ │ ├── proxy.provider.ts │ │ │ │ │ ├── redis.provider.ts │ │ │ │ │ ├── router.provider.ts │ │ │ │ │ ├── schedule.provider.ts │ │ │ │ │ ├── server.provider.ts │ │ │ │ │ ├── stereotype.provider.ts │ │ │ │ │ └── template-engine.provider.ts │ │ │ │ ├── index.ts │ │ │ │ └── worker.provider.ts │ │ │ └── buildin-app │ │ │ │ ├── agents │ │ │ │ └── schedule.ts │ │ │ │ └── middlewares │ │ │ │ ├── cors.ts │ │ │ │ ├── proxy.ts │ │ │ │ └── verify-csrf-token.ts │ │ ├── helpers.ts │ │ ├── http │ │ │ ├── cookie │ │ │ │ └── index.ts │ │ │ ├── middleware │ │ │ │ ├── index.ts │ │ │ │ └── middleware-service.ts │ │ │ ├── proxy │ │ │ │ ├── index.ts │ │ │ │ └── proxy.ts │ │ │ ├── request │ │ │ │ ├── index.ts │ │ │ │ └── utils │ │ │ │ │ └── parse-body.ts │ │ │ ├── response │ │ │ │ ├── index.ts │ │ │ │ ├── manager.ts │ │ │ │ ├── redirect.ts │ │ │ │ └── statusable.ts │ │ │ ├── router │ │ │ │ ├── dispatcher.ts │ │ │ │ ├── helpers.ts │ │ │ │ ├── index.ts │ │ │ │ ├── node.ts │ │ │ │ ├── route.ts │ │ │ │ └── trie.ts │ │ │ ├── server │ │ │ │ ├── index.ts │ │ │ │ └── server.ts │ │ │ └── session │ │ │ │ ├── index.ts │ │ │ │ └── stores │ │ │ │ └── redis.ts │ │ ├── index.ts │ │ ├── interfaces │ │ │ ├── agent.interface.ts │ │ │ ├── external │ │ │ │ └── https-options.ts │ │ │ ├── index.ts │ │ │ ├── middleware.interface.ts │ │ │ ├── provider.interface.ts │ │ │ └── resource.interface.ts │ │ ├── loader │ │ │ ├── index.ts │ │ │ └── loader.ts │ │ ├── messenger │ │ │ ├── index.ts │ │ │ └── messenger.ts │ │ ├── pagination │ │ │ ├── index.ts │ │ │ └── paginator.ts │ │ ├── pipeline │ │ │ └── index.ts │ │ ├── provider │ │ │ ├── index.ts │ │ │ └── provider.ts │ │ ├── resource │ │ │ ├── index.ts │ │ │ └── resource.ts │ │ ├── supports │ │ │ ├── cache │ │ │ │ ├── cache.ts │ │ │ │ ├── config.interface.ts │ │ │ │ ├── index.ts │ │ │ │ └── store │ │ │ │ │ ├── fs.ts │ │ │ │ │ ├── index.ts │ │ │ │ │ ├── memory.ts │ │ │ │ │ ├── redis.ts │ │ │ │ │ └── store.ts │ │ │ ├── database │ │ │ │ ├── actuator │ │ │ │ │ ├── actuator.ts │ │ │ │ │ ├── index.ts │ │ │ │ │ ├── mysql-actuator.ts │ │ │ │ │ └── mysql-tansaction-actuator.ts │ │ │ │ ├── builder │ │ │ │ │ ├── builder.ts │ │ │ │ │ ├── index.ts │ │ │ │ │ └── join.ts │ │ │ │ ├── connector │ │ │ │ │ ├── connector.ts │ │ │ │ │ └── mysql-connector.ts │ │ │ │ ├── database.ts │ │ │ │ ├── index.ts │ │ │ │ ├── manager │ │ │ │ │ ├── index.ts │ │ │ │ │ ├── manager.ts │ │ │ │ │ └── mysql-manager.ts │ │ │ │ └── parser │ │ │ │ │ ├── index.ts │ │ │ │ │ ├── mysql-parser.ts │ │ │ │ │ └── parser.ts │ │ │ ├── logger │ │ │ │ ├── cluster.ts │ │ │ │ ├── consts.ts │ │ │ │ ├── index.ts │ │ │ │ └── logger.ts │ │ │ ├── mailer │ │ │ │ ├── builder.ts │ │ │ │ ├── connector.ts │ │ │ │ ├── index.ts │ │ │ │ ├── mailer.ts │ │ │ │ └── manager.ts │ │ │ ├── orm │ │ │ │ ├── base-model.ts │ │ │ │ ├── builder.ts │ │ │ │ ├── index.ts │ │ │ │ ├── model.ts │ │ │ │ ├── pivot-model.ts │ │ │ │ ├── relations │ │ │ │ │ ├── belongs-to-many.ts │ │ │ │ │ ├── belongs-to.ts │ │ │ │ │ ├── has-many.ts │ │ │ │ │ ├── has-one.ts │ │ │ │ │ ├── has-relations.abstract.ts │ │ │ │ │ └── index.ts │ │ │ │ └── repository.ts │ │ │ ├── redis │ │ │ │ ├── config.interface.ts │ │ │ │ ├── connector.ts │ │ │ │ ├── index.ts │ │ │ │ └── redis.ts │ │ │ ├── schedule │ │ │ │ ├── corn-parser.ts │ │ │ │ ├── index.ts │ │ │ │ ├── matcher.ts │ │ │ │ ├── schedule-service.ts │ │ │ │ ├── scheduler.ts │ │ │ │ └── task.ts │ │ │ └── template-engine │ │ │ │ ├── index.ts │ │ │ │ └── template.ts │ │ ├── symbol.ts │ │ ├── utils │ │ │ ├── defered.ts │ │ │ ├── encrypt.ts │ │ │ ├── fake-base-class.ts │ │ │ ├── index.ts │ │ │ ├── message.ts │ │ │ ├── str.ts │ │ │ └── tool.ts │ │ ├── validate │ │ │ ├── index.ts │ │ │ ├── validate.ts │ │ │ └── validators.ts │ │ └── view │ │ │ ├── factory.ts │ │ │ └── index.ts │ ├── tsconfig.json │ └── vendors.d.ts └── trace-page │ ├── .npmignore │ ├── CHANGELOG.md │ ├── README.md │ ├── __tests__ │ └── index.spec.ts │ ├── global.d.ts │ ├── images.d.ts │ ├── index.ts │ ├── jest.config.js │ ├── package.json │ ├── template │ ├── images │ │ └── logo.svg │ ├── index.html │ ├── index.ts │ ├── js │ │ ├── prettify.js │ │ └── zepto.min.js │ └── less │ │ ├── code.less │ │ └── index.less │ ├── tsconfig-for-webpack-config.json │ ├── tsconfig.json │ └── webpack.config.ts ├── scripts └── build.sh ├── tools └── benchmarks │ └── benchmarks.ts └── tsconfig.json /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | indent_style = space 5 | indent_size = 2 6 | charset = utf-8 7 | trim_trailing_whitespace = false 8 | insert_final_newline = false -------------------------------------------------------------------------------- /.eslintignore: -------------------------------------------------------------------------------- 1 | benchmarks 2 | *.json -------------------------------------------------------------------------------- /.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": [ 3 | "plugin:@typescript-eslint/recommended" 4 | ], 5 | "plugins": [ 6 | "@typescript-eslint" 7 | ], 8 | "parser": "@typescript-eslint/parser", 9 | "parserOptions": { 10 | "ecmaVersion": 2018, 11 | "sourceType": "module" 12 | }, 13 | "rules": { 14 | "semi": [ 15 | "error", 16 | "always" 17 | ], 18 | "@typescript-eslint/no-this-alias": "off", 19 | "@typescript-eslint/explicit-function-return-type": "off", 20 | "@typescript-eslint/no-explicit-any": "off", 21 | "@typescript-eslint/explicit-member-accessibility": "off", 22 | "@typescript-eslint/indent": [ 23 | "error", 24 | 2 25 | ] 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/BUG_REPORT.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: "\U0001F41B Bug Report" 3 | about: "If something isn't working as expected \U0001F914." 4 | title: '' 5 | labels: 'type: potential issue :broken_heart:,needs triage' 6 | assignees: '' 7 | 8 | --- 9 | 10 | ## Bug Report 11 | 12 | ## Current behavior 13 | 14 | 15 | ## Input Code 16 | 17 | 18 | ```ts 19 | const your = (code) => here; 20 | ``` 21 | 22 | ## Expected behavior 23 | 24 | 25 | ## Possible Solution 26 | 27 | 28 | ## Environment 29 | 30 |
31 |   
32 |     Daze version: X.Y.Z
33 |     
34 |     
35 |     For Tooling issues:
36 |     - Node version: XX  
37 |     - Platform:  
38 | 
39 |     Others:
40 |     
41 |   
42 | 
43 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/FEATURE_REQUEST.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: "\U0001F680 Feature Request" 3 | about: "I have a suggestion \U0001F63B!" 4 | title: '' 5 | labels: 'type: enhancement :wolf:,needs triage' 6 | assignees: '' 7 | 8 | --- 9 | 10 | ## Feature Request 11 | 12 | ## Is your feature request related to a problem? Please describe. 13 | 14 | 15 | ## Describe the solution you'd like 16 | 17 | 18 | ## Teachability, Documentation, Adoption, Migration Strategy 19 | 20 | 21 | ## What is the motivation / use case for changing the behavior? 22 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/SUPPORT_QUESTION.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: "\U0001F917 Support Question" 3 | about: "I have a question \U0001F4AC" 4 | title: '' 5 | labels: 'type: question 🙌,needs triage' 6 | assignees: '' 7 | 8 | --- 9 | 10 | -------------------------------------------------------------------------------- /.github/lock.yml: -------------------------------------------------------------------------------- 1 | # Number of days of inactivity before a closed issue or pull request is locked 2 | daysUntilLock: 90 3 | 4 | # Skip issues and pull requests created before a given timestamp. Timestamp must 5 | # follow ISO 8601 (`YYYY-MM-DD`). Set to `false` to disable 6 | skipCreatedBefore: false 7 | 8 | # Issues and pull requests with these labels will be ignored. Set to `[]` to disable 9 | exemptLabels: [] 10 | 11 | # Label to add before locking, such as `outdated`. Set to `false` to disable 12 | lockLabel: false 13 | 14 | # Comment to post before locking. Set to `false` to disable 15 | lockComment: > 16 | This thread has been automatically locked since there has not been 17 | any recent activity after it was closed. Please open a new issue for 18 | related bugs. 19 | # Assign `resolved` as the reason for locking. Set to `false` to disable 20 | setLockReason: true 21 | 22 | # Limit to only `issues` or `pulls` 23 | # only: issues 24 | 25 | # Optionally, specify configuration settings just for `issues` or `pulls` 26 | # issues: 27 | # exemptLabels: 28 | # - help-wanted 29 | # lockLabel: outdated 30 | 31 | # pulls: 32 | # daysUntilLock: 30 33 | 34 | # Repository to extend settings from 35 | # _extends: repo -------------------------------------------------------------------------------- /.github/pull_request_template.md: -------------------------------------------------------------------------------- 1 | ## Feature Request 2 | 3 | ## Is your feature request related to a problem? Please describe. 4 | 5 | 6 | ## Describe the solution you'd like 7 | 8 | 9 | ## Teachability, Documentation, Adoption, Migration Strategy 10 | 11 | 12 | ## What is the motivation / use case for changing the behavior? 13 | 14 | -------------------------------------------------------------------------------- /.github/workflows/nodejs.yml: -------------------------------------------------------------------------------- 1 | name: Node CI 2 | 3 | on: 4 | push: 5 | branches: 6 | - master 7 | pull_request: 8 | branches: 9 | - master 10 | 11 | jobs: 12 | test: 13 | 14 | runs-on: ubuntu-latest 15 | 16 | strategy: 17 | matrix: 18 | node-version: [14, 16] 19 | 20 | # container: node:12 21 | 22 | services: 23 | mysql: 24 | image: mysql:5.7 25 | ports: 26 | - 3306:3306 27 | env: 28 | MYSQL_ROOT_PASSWORD: root 29 | MYSQL_DATABASE: daze 30 | options: --health-cmd="mysqladmin ping" --health-interval=10s --health-timeout=5s --health-retries=3 31 | 32 | steps: 33 | - name: Checkout 34 | uses: actions/checkout@v1 35 | with: 36 | fetch-depth: 1 37 | - name: Setup Node.js 38 | uses: actions/setup-node@v3 39 | with: 40 | node-version: ${{ matrix.node }} 41 | - name: Dependences Install 42 | run: | 43 | npm install 44 | npm install codecov 45 | ./node_modules/.bin/lerna bootstrap 46 | - name: Run Test 47 | run: | 48 | npm run test:coverage 49 | - name: Codecov 50 | run: | 51 | ./node_modules/.bin/codecov -t ${{ secrets.CODECOV_TOKEN }} 52 | 53 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # dependencies 2 | node_modules/ 3 | 4 | # IDE 5 | /.idea 6 | /.awcache 7 | /.vscode 8 | *.code-workspace 9 | 10 | # dist 11 | packages/*/dist 12 | 13 | 14 | # logs 15 | logs/*.log 16 | **/logs/**.log 17 | 18 | # misc 19 | .DS_Store 20 | lerna-debug.log 21 | npm-debug.log 22 | yarn-error.log 23 | packages/*/__debug__ 24 | .clinic 25 | 26 | # test 27 | packages/*/coverage 28 | 29 | # future and deprecated 30 | FUTURE_* 31 | DEPRECATED_* 32 | 33 | # dev example 34 | __example__ 35 | example/dist -------------------------------------------------------------------------------- /.huskyrc: -------------------------------------------------------------------------------- 1 | { 2 | "hooks": { 3 | "commit-msg": "commitlint -E HUSKY_GIT_PARAMS" 4 | } 5 | } -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | src 3 | coverage 4 | __tests__ 5 | __debug__ 6 | .idea 7 | .vscode 8 | logs 9 | -------------------------------------------------------------------------------- /AUTHORS: -------------------------------------------------------------------------------- 1 | czewail 2 | yinggaozhen 3 | IceMimosa -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT LICENSE 2 | 3 | Copyright (c) 2018-present Chan Zewail, chanzewail@gmail.com 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining 6 | a copy of this software and associated documentation files (the 7 | "Software"), to deal in the Software without restriction, including 8 | without limitation the rights to use, copy, modify, merge, publish, 9 | distribute, sublicense, and/or sell copies of the Software, and to 10 | permit persons to whom the Software is furnished to do so, subject to 11 | the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be 14 | included in all copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 17 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 18 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 19 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 20 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 21 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 22 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -------------------------------------------------------------------------------- /README_en.md: -------------------------------------------------------------------------------- 1 | 2 | [![GitHub issues](https://img.shields.io/github/issues/dazejs/daze.svg)](https://github.com/dazejs/daze/issues) 3 | [![npm](https://img.shields.io/npm/v/@dazejs/framework.svg)](https://www.npmjs.com/package/@dazejs/framework) 4 | [![npm](https://img.shields.io/npm/dm/@dazejs/framework.svg)](https://www.npmjs.com/package/@dazejs/framework) 5 | [![actions](https://github.com/dazejs/daze/workflows/Node%20CI/badge.svg)](https://github.com/dazejs/daze/actions) 6 | [![codecov](https://codecov.io/gh/dazejs/daze/branch/master/graph/badge.svg)](https://codecov.io/gh/dazejs/daze) 7 | [![Codacy Badge](https://api.codacy.com/project/badge/Grade/09d6f0f7a58d406c9c9b8ec4abaab2a6)](https://www.codacy.com/manual/dazejs/daze?utm_source=github.com&utm_medium=referral&utm_content=dazejs/daze&utm_campaign=Badge_Grade) 8 | [![GitHub license](https://img.shields.io/github/license/dazejs/daze.svg)](https://github.com/dazejs/daze/blob/master/LICENSE) 9 | 10 |
11 | 12 | 13 | 14 |

Daze.js

15 |

Web framwork for Node.js

16 |
17 | 18 | English | [中文](README_zh.md) 19 | 20 | 21 | Visit [https://dazejs.org/](https://dazejs.org/) to learn more 22 | 23 | ## Introduction 24 | 25 | `Daze.js` is an efficient, highly extensible and powerful `Node.js` server-side Web development daze. 26 | 27 | 28 | ## Getting Started 29 | 30 | #### Install cli tool 31 | ```bash 32 | $ npm install -g @dazejs/cli 33 | ``` 34 | 35 | #### Create application 36 | 37 | ```bash 38 | $ daze create example 39 | $ cd example 40 | $ npm start 41 | ``` 42 | 43 | visit `http://localhost:8080` to preview 44 | 45 | ## Docs & Community 46 | 47 | - [Documentations](https://dazejs.org/) 48 | 49 | ## Benchmarks 50 | The benchmark compares a number of other frameworks, mainly with no routes and with 1000 routes defined, see [benchmarks](benchmarks/README.md) 51 | 52 | ## License 53 | 54 | Daze.js is [MIT licensed](https://github.com/dazejs/daze/blob/master/LICENSE) 55 | 56 | -------------------------------------------------------------------------------- /assets/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dazejs/daze/e9d67d915a33c70cb5cdd731fc585a48a5872a5a/assets/logo.png -------------------------------------------------------------------------------- /benchmarks/README.md: -------------------------------------------------------------------------------- 1 | # Benchmarks 2 | 3 | ### daze-without-routes 4 | 5 | | Stat | Avg | Stdev | Min | 6 | | --------- | -------- | ------- | ------- | 7 | | Req/Sec | 64801.46 | 4141.42 | 51921 | 8 | | Bytes/Sec | 9.39 MB | 4.04 KB | 50.7 KB | 9 | 10 | 11 | ### express-without-routes 12 | 13 | | Stat | Avg | Stdev | Min | 14 | | --------- | -------- | ------- | -------- | 15 | | Req/Sec | 33246.55 | 3611.47 | 22052 | 16 | | Bytes/Sec | 6.82 MB | 3.53 KB | 21.54 KB | 17 | 18 | 19 | ### koa-without-routes 20 | 21 | | Stat | Avg | Stdev | Min | 22 | | --------- | -------- | ------- | -------- | 23 | | Req/Sec | 60670.55 | 4490.95 | 48478 | 24 | | Bytes/Sec | 8.79 MB | 4.39 KB | 47.34 KB | 25 | 26 | 27 | ### daze-with-1000-routes 28 | 29 | | Stat | Avg | Stdev | Min | 30 | | --------- | -------- | ------- | -------- | 31 | | Req/Sec | 39210.91 | 3903.57 | 26911 | 32 | | Bytes/Sec | 5.68 MB | 3.81 KB | 26.28 KB | 33 | 34 | 35 | ### express-with-1000-routes 36 | 37 | | Stat | Avg | Stdev | Min | 38 | | --------- | -------- | ------- | ------- | 39 | | Req/Sec | 11745.64 | 1323.05 | 7712 | 40 | | Bytes/Sec | 2.41 MB | 1.29 KB | 7.53 KB | 41 | 42 | 43 | ### koa-with-1000-routes 44 | 45 | | Stat | Avg | Stdev | Min | 46 | | --------- | ------- | ------ | ------- | 47 | | Req/Sec | 8803.28 | 758.07 | 6684 | 48 | | Bytes/Sec | 1.28 MB | 758 B | 6.53 KB | 49 | 50 | -------------------------------------------------------------------------------- /benchmarks/daze-with-1000-routes.js: -------------------------------------------------------------------------------- 1 | const { Application, BaseController, BaseProvider, Response } = require('../packages/framework/dist') 2 | 3 | const app = new Application(__dirname) 4 | 5 | class Hello extends BaseController { 6 | index() { 7 | return 'Hello World' 8 | } 9 | } 10 | 11 | app.multiton(Hello, Hello) 12 | 13 | class RoutesProvider extends BaseProvider { 14 | launch() { 15 | const router = this.app.get('router') 16 | for (let index1 = 0; index1 < 10; index1++) { 17 | for (let index2 = 0; index2 < 10; index2++) { 18 | for (let index3 = 0; index3 < 10; index3++) { 19 | const url = `/uuid${index1}/uuid${index2}/uuid${index3}` 20 | router.register(url, ['GET'], Hello, 'index', []) 21 | } 22 | } 23 | } 24 | } 25 | } 26 | 27 | app.disableBodyParser() 28 | 29 | app.disableSession() 30 | 31 | app.register(new RoutesProvider(app)) 32 | 33 | app.run(3000) 34 | 35 | 36 | -------------------------------------------------------------------------------- /benchmarks/daze-without-routes.js: -------------------------------------------------------------------------------- 1 | const { Application, Controller, BaseProvider, Response } = require('../packages/framework/dist') 2 | 3 | const app = new Application(__dirname) 4 | 5 | 6 | class RoutesProvider extends BaseProvider { 7 | launch() { 8 | this.app.get('middleware').register(() => (new Response()).OK('Hello World')) 9 | } 10 | } 11 | 12 | app.disableBodyParser() 13 | 14 | app.disableSession() 15 | 16 | app.register(new RoutesProvider(app)) 17 | 18 | app.run(3000) 19 | 20 | 21 | -------------------------------------------------------------------------------- /benchmarks/express-with-1000-routes.js: -------------------------------------------------------------------------------- 1 | const express = require('express'); 2 | const app = express(); 3 | 4 | const controller = (req, res) => { 5 | res.send('Hello World') 6 | } 7 | 8 | for (let index1 = 1; index1 <= 10; index1++) { 9 | for (let index2 = 1; index2 <= 10; index2++) { 10 | for (let index3 = 1; index3 <= 10; index3++) { 11 | const url = `/uuid${index1}/uuid${index2}/uuid${index3}` 12 | app.get(url, controller) 13 | } 14 | } 15 | } 16 | 17 | 18 | app.listen(3000); -------------------------------------------------------------------------------- /benchmarks/express-without-routes.js: -------------------------------------------------------------------------------- 1 | const express = require('express'); 2 | const app = express(); 3 | 4 | // app.get('/hello', function (req, res) { 5 | // res.send('Hello World'); 6 | // }); 7 | 8 | const controller = (req, res) => { 9 | res.send('Hello World') 10 | } 11 | 12 | app.use(controller) 13 | 14 | // for (let index1 = 1; index1 <= 10; index1++) { 15 | // for (let index2 = 1; index2 <= 10; index2++) { 16 | // for (let index3 = 1; index3 <= 10; index3++) { 17 | // const url = `/uuid${index1}/uuid${index2}/uuid${index3}` 18 | // app.get(url, controller) 19 | // app.post(url, controller) 20 | // app.put(url, controller) 21 | // app.delete(url, controller) 22 | // app.patch(url, controller) 23 | // } 24 | // } 25 | // } 26 | 27 | app.listen(3000); -------------------------------------------------------------------------------- /benchmarks/koa-with-1000-routes.js: -------------------------------------------------------------------------------- 1 | 2 | const Koa = require('koa'); 3 | const Router = require('koa-router') 4 | 5 | const app = new Koa() 6 | 7 | const router = new Router() 8 | 9 | const controller = (ctx, next) => { 10 | ctx.body = 'Hello World' 11 | } 12 | 13 | for (let index1 = 1; index1 <= 10; index1++) { 14 | for (let index2 = 1; index2 <= 10; index2++) { 15 | for (let index3 = 1; index3 <= 10; index3++) { 16 | const url = `/uuid${index1}/uuid${index2}/uuid${index3}` 17 | router.get(url, controller) 18 | } 19 | } 20 | } 21 | 22 | app.use(router.routes(), router.allowedMethods()) 23 | 24 | app.listen(3000) -------------------------------------------------------------------------------- /benchmarks/koa-without-routes.js: -------------------------------------------------------------------------------- 1 | 2 | const Koa = require('koa'); 3 | 4 | const app = new Koa() 5 | 6 | 7 | const controller = (ctx, next) => { 8 | ctx.body = 'Hello World' 9 | } 10 | 11 | app.use(controller) 12 | 13 | app.listen(3000) 14 | -------------------------------------------------------------------------------- /commitlint.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | extends: ['@commitlint/config-conventional'] 3 | }; 4 | -------------------------------------------------------------------------------- /example/daze: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | // eslint-disable-next-line @typescript-eslint/no-var-requires 3 | const daze = require('../packages/cli/dist'); 4 | 5 | daze.terminate(process.argv); 6 | -------------------------------------------------------------------------------- /example/src/app/agent.ts: -------------------------------------------------------------------------------- 1 | import { Agent, AgentInterface } from '../../../packages/framework/dist'; 2 | 3 | @Agent() 4 | export default class ExampleAgent implements AgentInterface { 5 | resolve() { 6 | // console.log(1111111);setInterval(() => { 7 | // console.log(12312312312); 8 | // }, 1000); 9 | // setTimeout(() => { 10 | // process.exit(1); 11 | // }, 3000); 12 | } 13 | } -------------------------------------------------------------------------------- /example/src/app/example.controller.ts: -------------------------------------------------------------------------------- 1 | import { app, Autowired, Controller, http, Logger } from '../../../packages/framework/dist'; 2 | 3 | @Controller() 4 | export class Example { 5 | @Autowired 6 | logger: Logger; 7 | // @Get() 8 | // async index(request: Request, @Query('name') anme = '') { 9 | // return new View('hello', { 10 | // name: anme || 'daze' 11 | // }); 12 | // } 13 | 14 | @http.Get('set') 15 | async set() { 16 | return 'set'; 17 | } 18 | 19 | @http.Get('/route') 20 | async route() { 21 | console.dir(app().get('router'), { 22 | customInspect: true, 23 | depth: 7 24 | }); 25 | return 'route'; 26 | } 27 | 28 | @http.Get('/del-route') 29 | async delroute() { 30 | app().get('router').unRegistry('/set', ['GET'], {}); 31 | return 'route'; 32 | } 33 | } -------------------------------------------------------------------------------- /example/src/app/example.entity.ts: -------------------------------------------------------------------------------- 1 | import { Entity, BaseEntity, AutoIncrementPrimaryColumn, Column, CreateTimestampColumn, UpdateTimestampColumn } from '../../../packages/framework/dist'; 2 | 3 | @Entity('packages') 4 | export class ExampleEntity extends BaseEntity { 5 | @AutoIncrementPrimaryColumn() 6 | id: number; 7 | 8 | @Column() 9 | author: string; 10 | 11 | @Column() 12 | name: string; 13 | 14 | @Column() 15 | description: string; 16 | 17 | @CreateTimestampColumn('datetime') 18 | created_at: number; 19 | 20 | @UpdateTimestampColumn('datetime') 21 | updated_at: number; 22 | } -------------------------------------------------------------------------------- /example/src/app/schedule.ts: -------------------------------------------------------------------------------- 1 | // import { Schedule, Corntab } from '../../../packages/framework/dist'; 2 | 3 | 4 | // @Schedule() 5 | export class ExampleSchedule { 6 | // @Corntab.everyFifteenSeconds() 7 | myname() { 8 | console.log('runrunrun======'); 9 | } 10 | 11 | myass() { 12 | console.log('assassin'); 13 | } 14 | } -------------------------------------------------------------------------------- /example/src/config/app.dev.ts: -------------------------------------------------------------------------------- 1 | export default { 2 | cluster: false, 3 | }; -------------------------------------------------------------------------------- /example/src/config/app.ts: -------------------------------------------------------------------------------- 1 | 2 | import { ExampleProvider } from '../example.provider'; 3 | 4 | export default { 5 | cluster: true, 6 | workers: 2, 7 | sticky: false, 8 | baseUrl: '/example', 9 | 10 | public: true, 11 | publicPrefix: '', 12 | ssrDevPort: 9988, 13 | providers: [ 14 | ExampleProvider, 15 | ] 16 | }; -------------------------------------------------------------------------------- /example/src/config/cache.ts: -------------------------------------------------------------------------------- 1 | 2 | export default { 3 | /** 4 | * 默认使用的存储器 5 | * 可选:memory | redis | fs 6 | */ 7 | store: 'fs' 8 | 9 | }; -------------------------------------------------------------------------------- /example/src/config/database.ts: -------------------------------------------------------------------------------- 1 | 2 | export default { 3 | default: { 4 | type: 'mysql', 5 | host: '127.0.0.1', 6 | user: 'root', 7 | password: 'root', 8 | port: 3306, 9 | database: 'yxnpm' 10 | } 11 | }; -------------------------------------------------------------------------------- /example/src/config/proxy.ts: -------------------------------------------------------------------------------- 1 | export default { 2 | '/xhr/*': { 3 | target: 'https://baidu.com', 4 | // only: ['/xhr/set'], 5 | rewrite: (p: string) => { 6 | return p.replace('/xhr', ''); 7 | } 8 | } 9 | }; -------------------------------------------------------------------------------- /example/src/config/redis.ts: -------------------------------------------------------------------------------- 1 | 2 | export default { 3 | /** 4 | * 默认 Redis 连接 5 | */ 6 | default: { 7 | host: 'localhost', 8 | port: 6379 9 | }, 10 | 11 | /** 12 | * 缓存专用默认 reids 连接 13 | * 未定义的情况下,默认使用 default 连接 14 | */ 15 | // cache: { 16 | // host: 'localhost', 17 | // port: 6379 18 | // }, 19 | 20 | /** 21 | * 任务调度专用默认 reids 连接 22 | * 未定义的情况下,默认使用 default 连接 23 | */ 24 | // schedule: { 25 | // host: 'localhost', 26 | // port: 6379 27 | // }, 28 | }; -------------------------------------------------------------------------------- /example/src/example.provider.ts: -------------------------------------------------------------------------------- 1 | import { Provider, AppendMaster, AppendAgent, Autowired, Application } from '../../packages/framework/dist'; 2 | 3 | @Provider() 4 | @AppendMaster() 5 | @AppendAgent() 6 | export class ExampleProvider { 7 | @Autowired 8 | app: Application; 9 | 10 | launch() { 11 | // console.dir(this.app.get('router'), { 12 | // customInspect: true, 13 | // depth: 7 14 | // }); 15 | } 16 | } -------------------------------------------------------------------------------- /example/src/index.ts: -------------------------------------------------------------------------------- 1 | import { Application } from '../../packages/framework/dist'; 2 | 3 | const app = new Application(); 4 | 5 | app.run(8080); 6 | -------------------------------------------------------------------------------- /example/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es2017", 4 | "module": "commonjs", 5 | "baseUrl": "./", 6 | "outDir": "dist", 7 | "lib": [ 8 | "esnext" 9 | ], 10 | "allowJs": false, 11 | "declaration": true, 12 | "sourceMap": true, 13 | "removeComments": true, 14 | "strict": true, 15 | "noImplicitAny": true, 16 | "strictNullChecks": true, 17 | "strictFunctionTypes": true, 18 | "strictPropertyInitialization": false, 19 | "noImplicitThis": true, 20 | "alwaysStrict": true, 21 | "noUnusedLocals": true, 22 | "noUnusedParameters": true, 23 | "noImplicitReturns": true, 24 | "moduleResolution": "node", 25 | "allowSyntheticDefaultImports": true, 26 | "esModuleInterop": true, 27 | "experimentalDecorators": true, 28 | "emitDecoratorMetadata": true, 29 | "skipLibCheck": true, 30 | "preserveSymlinks": true 31 | }, 32 | "include": [ 33 | "src/**/*.ts" 34 | ], 35 | "exclude": [ 36 | "node_modules" 37 | ] 38 | } -------------------------------------------------------------------------------- /lerna.json: -------------------------------------------------------------------------------- 1 | { 2 | "packages": [ 3 | "packages/*" 4 | ], 5 | "command": { 6 | "bootstrap": { 7 | "hoist": true, 8 | "noCi": true, 9 | "npmClientArgs": [ 10 | "--no-package-lock" 11 | ] 12 | }, 13 | "version": { 14 | "message": "chore(release): publish" 15 | }, 16 | "publish": { 17 | "ignoreChanges": [ 18 | "*.md" 19 | ], 20 | "allowBranch": "master", 21 | "exact": true, 22 | "conventionalCommits": true 23 | } 24 | }, 25 | "version": "independent" 26 | } 27 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "root", 3 | "private": true, 4 | "scripts": { 5 | "dev": "lerna run dev --parallel --stream", 6 | "dev:trace-page": "lerna run --scope @dazejs/trace-page dev", 7 | "install": "lerna bootstrap", 8 | "build": "sh scripts/build.sh", 9 | "publish": "npm run build && lerna publish", 10 | "next": "npm run build && lerna publish --dist-tag next", 11 | "bootstrap": "lerna bootstrap", 12 | "test": "lerna run test --stream", 13 | "test:coverage": "lerna run test:coverage --stream", 14 | "benchmarks": "ts-node tools/benchmarks/benchmarks.ts", 15 | "commitlint": "commitlint -e $GIT_PARAMS" 16 | }, 17 | "devDependencies": { 18 | "@commitlint/cli": "8.3.5", 19 | "@commitlint/config-conventional": "8.2.0", 20 | "@types/debug": "4.1.5", 21 | "@types/express": "4.17.1", 22 | "@types/jest": "25.1.4", 23 | "@types/koa": "2.11.2", 24 | "@types/koa-router": "7.4.0", 25 | "@types/node": "14.0.26", 26 | "@types/supertest": "2.0.8", 27 | "@types/type-is": "1.6.3", 28 | "@types/uuid": "7.0.2", 29 | "@types/validator": "12.0.1", 30 | "@typescript-eslint/eslint-plugin": "5.46.0", 31 | "@typescript-eslint/parser": "5.46.0", 32 | "autocannon": "4.6.0", 33 | "copyfiles": "2.2.0", 34 | "cross-env": "6.0.0", 35 | "eslint": "8.29.0", 36 | "eslint-config-airbnb-base": "15.0.0", 37 | "eslint-plugin-import": "2.26.0", 38 | "express": "4.17.1", 39 | "filesize": "6.1.0", 40 | "husky": "4.2.5", 41 | "jest": "29.3.1", 42 | "koa": "2.11.0", 43 | "koa-router": "8.0.8", 44 | "lerna": "6.4.0", 45 | "markdown-table": "2.0.0", 46 | "rimraf": "3.0.2", 47 | "supertest": "4.0.2", 48 | "ts-jest": "29.0.3", 49 | "ts-node": "10.9.1", 50 | "typescript": "4.9.4" 51 | }, 52 | "dependencies": { 53 | "reflect-metadata": "0.1.13" 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /packages/cli/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Change Log 2 | 3 | All notable changes to this project will be documented in this file. 4 | See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. 5 | 6 | ## [1.0.2](https://github.com/dazejs/daze/compare/@dazejs/cli@1.0.1...@dazejs/cli@1.0.2) (2025-02-19) 7 | 8 | **Note:** Version bump only for package @dazejs/cli 9 | 10 | 11 | 12 | 13 | 14 | ## [1.0.1](https://github.com/dazejs/daze/compare/@dazejs/cli@1.0.0-alpha.0...@dazejs/cli@1.0.1) (2023-01-10) 15 | 16 | **Note:** Version bump only for package @dazejs/cli 17 | 18 | 19 | 20 | 21 | 22 | # [1.0.0](https://github.com/dazejs/daze/compare/@dazejs/cli@1.0.0-alpha.0...@dazejs/cli@1.0.0) (2023-01-10) 23 | 24 | **Note:** Version bump only for package @dazejs/cli 25 | 26 | 27 | 28 | 29 | 30 | # 1.0.0-alpha.0 (2023-01-09) 31 | 32 | **Note:** Version bump only for package @dazejs/cli 33 | -------------------------------------------------------------------------------- /packages/cli/__tests__/nill.spec.ts: -------------------------------------------------------------------------------- 1 | 2 | describe('nill', () => { 3 | it('nill', () => { 4 | expect(1).toBe(1) 5 | }) 6 | }) -------------------------------------------------------------------------------- /packages/cli/g.d.ts: -------------------------------------------------------------------------------- 1 | declare module 'ascii-table' { 2 | const x: any; 3 | export = x; 4 | } 5 | declare module 'ts-node/register' { 6 | const x: any; 7 | export = x; 8 | } -------------------------------------------------------------------------------- /packages/cli/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@dazejs/cli", 3 | "version": "1.0.2", 4 | "description": "Node 服务端 WEB 框架", 5 | "main": "dist/index.js", 6 | "bin": { 7 | "daze": "dist/bin/daze.js" 8 | }, 9 | "scripts": { 10 | "copy": "copyfiles -u 1 src/**/*.njk dist && copyfiles -u 1 src/*.json dist", 11 | "clean": "rimraf dist/*", 12 | "build": "npm run clean && npm run copy && tsc", 13 | "test": "node -v", 14 | "test:coverage": "node -v", 15 | "dev": "npm run clean && npm run copy && tsc -w" 16 | }, 17 | "keywords": [], 18 | "author": "", 19 | "license": "UNLICENSE", 20 | "dependencies": { 21 | "@dazejs/framework": "5.0.2", 22 | "ascii-table": "^0.0.9", 23 | "chalk": "^4.1.0", 24 | "chokidar": "^3.5.3", 25 | "commander": "^7.2.0", 26 | "concurrently": "^6.2.0", 27 | "fs-extra": "^9.1.0", 28 | "glob": "^7.1.6", 29 | "inquirer": "^8.0.0", 30 | "node-fetch": "^2.6.1", 31 | "nodemon": "^2.0.7", 32 | "nunjucks": "^3.2.3", 33 | "ora": "^5.4.0", 34 | "pluralize": "^8.0.0", 35 | "reflect-metadata": "0.1.13", 36 | "table": "^6.7.1", 37 | "ts-node": "^10.0.0", 38 | "typescript": "^4.9.4" 39 | }, 40 | "devDependencies": { 41 | "@types/concurrently": "^6.2.0", 42 | "@types/fs-extra": "^9.0.11", 43 | "@types/inquirer": "^7.3.1", 44 | "@types/node-fetch": "^2.5.10", 45 | "@types/nodemon": "^1.19.0", 46 | "@types/pluralize": "0.0.29" 47 | }, 48 | "gitHead": "4d87844d5c3483689a94a63ac992c98ab9ff1224" 49 | } 50 | -------------------------------------------------------------------------------- /packages/cli/src/actions/build.ts: -------------------------------------------------------------------------------- 1 | import { Application } from '@dazejs/framework'; 2 | import chalk from 'chalk'; 3 | import fs from 'fs'; 4 | import path from 'path'; 5 | import { DAZE_SERVER_PREFIX } from '../lib/constants'; 6 | import { TsCompile } from '../lib/ts_compile'; 7 | 8 | const cwd = process.cwd(); 9 | 10 | /** 11 | * 开发模式 Action 12 | */ 13 | export class BuildAction { 14 | 15 | /** 16 | * 默认的 tsconfig 文件路径 17 | */ 18 | private defaultTsConfigPath = path.join(__dirname, '../defaultTsConfig.json'); 19 | 20 | /** 21 | * 项目自定义的 tsconfig 文件路径 22 | */ 23 | private customTsConfigPath = path.join(cwd, './tsconfig.json'); 24 | 25 | /** 26 | * 项目自定义的 client 特殊 tsconfig 文件路径 27 | */ 28 | // private _customClientTsConfigPath = path.join(fePath, './tsconfig.json') 29 | 30 | /** 31 | * 项目自定义的 server 特殊 tsconfig 文件路径 32 | */ 33 | private customServerTsConfigPath = path.join(cwd, './src', './tsconfig.json'); 34 | 35 | 36 | /** 37 | * Action Hook 38 | */ 39 | public async resolve(_destination: any) { 40 | const app = new Application({ 41 | rootPath: path.join(cwd, './src') 42 | }); 43 | await app.initializeForCli(); 44 | 45 | this.resolveServer(); 46 | } 47 | 48 | 49 | /** 50 | * 启动服务端测开发模式 51 | */ 52 | private resolveServer() { 53 | if (fs.existsSync(path.join(cwd, './src'))) { 54 | console.log(DAZE_SERVER_PREFIX, '准备编译服务端代码...'); 55 | if (fs.existsSync(this.customServerTsConfigPath)) { 56 | this._compile(this.customServerTsConfigPath); 57 | } else { 58 | if (fs.existsSync(this.customTsConfigPath)) { 59 | this._compile(this.customTsConfigPath); 60 | } else { 61 | this._compile(this.defaultTsConfigPath); 62 | } 63 | } 64 | } 65 | } 66 | 67 | private async _compile(configPath: string) { 68 | 69 | const tsCompile = new TsCompile(); 70 | 71 | tsCompile.compile(configPath, (config) => { 72 | console.log(DAZE_SERVER_PREFIX, '编译成功'); 73 | console.log(DAZE_SERVER_PREFIX, '输出目录: ', chalk.green(config.options.outDir)); 74 | }); 75 | } 76 | } -------------------------------------------------------------------------------- /packages/cli/src/actions/create.ts: -------------------------------------------------------------------------------- 1 | import { Render, Question, Printer } from '../lib'; 2 | import { TPLActionAbstract } from './tpl-action.abstract'; 3 | import { NpmRunner, YarnRunner, PNpmRunner} from '../lib/runner'; 4 | 5 | export class CreateAction extends TPLActionAbstract { 6 | 7 | async resolve(name: string) { 8 | const answer = await new Question() 9 | .packageManager() 10 | .ask(); 11 | 12 | const renderer = new Render(); 13 | 14 | renderer.source(this._source); 15 | renderer.destination(name); 16 | 17 | await renderer.apply(); 18 | 19 | if (answer.packageManager === 'npm') { 20 | await new NpmRunner() 21 | .directory(name) 22 | .run('install'); 23 | } else if (answer.packageManager === 'yarn') { 24 | await new YarnRunner() 25 | .directory(name) 26 | .run('install'); 27 | } else if (answer.packageManager === 'pnpm') { 28 | await new PNpmRunner() 29 | .directory(name) 30 | .run('install'); 31 | } 32 | 33 | Printer.power(); 34 | } 35 | } -------------------------------------------------------------------------------- /packages/cli/src/actions/index.ts: -------------------------------------------------------------------------------- 1 | export * from './tpl-action.abstract'; 2 | export * from './create'; 3 | export * from './make'; 4 | export * from './routes'; 5 | export * from './build'; 6 | export * from './dev'; -------------------------------------------------------------------------------- /packages/cli/src/actions/make.ts: -------------------------------------------------------------------------------- 1 | import { TPLActionAbstract } from './tpl-action.abstract'; 2 | // import { Command } from 'commander'; 3 | import { Render } from '../lib'; 4 | import pluralize from 'pluralize'; 5 | import chalk from 'chalk'; 6 | 7 | 8 | export class MakeAction extends TPLActionAbstract { 9 | 10 | getFilename(name: string) { 11 | return `${name}.ts`; 12 | } 13 | 14 | 15 | async resolve(name: string, destination: Record) { 16 | const renderer = new Render(); 17 | 18 | renderer.source(this._source); 19 | renderer.destination(destination.path ?? pluralize.plural(this._source)); 20 | 21 | renderer.assign({ 22 | name, 23 | }); 24 | 25 | const distname = this.getFilename(name); 26 | 27 | switch(this._source) { 28 | case 'controller': 29 | if (destination.rest) { 30 | await renderer.make('rest.tpl', distname); 31 | } else { 32 | await renderer.make('controller.tpl', distname); 33 | } 34 | break; 35 | case 'service': 36 | await renderer.make('service.tpl', distname); 37 | break; 38 | case 'schedule': 39 | await renderer.make('schedule.tpl', distname); 40 | break; 41 | case 'middleware': 42 | await renderer.make('middleware.tpl', distname); 43 | break; 44 | default: 45 | console.log( 46 | chalk.red(`不支持该模板`) 47 | ); 48 | process.exit(1); 49 | } 50 | } 51 | } -------------------------------------------------------------------------------- /packages/cli/src/actions/tpl-action.abstract.ts: -------------------------------------------------------------------------------- 1 | import { SourceType } from '../lib/render'; 2 | 3 | export abstract class TPLActionAbstract { 4 | protected _source: SourceType; 5 | 6 | abstract resolve(name: string, destination: Record): any 7 | source(_source: SourceType) { 8 | this._source = _source; 9 | return this; 10 | } 11 | } -------------------------------------------------------------------------------- /packages/cli/src/bin/daze.ts: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | import { init } from '../lib/init'; 4 | 5 | init(); -------------------------------------------------------------------------------- /packages/cli/src/commands/build.ts: -------------------------------------------------------------------------------- 1 | import commander from 'commander'; 2 | import { BuildAction } from '../actions'; 3 | 4 | export class BuildCommand { 5 | 6 | private program: commander.Command; 7 | 8 | constructor(program: commander.Command) { 9 | this.program = program; 10 | } 11 | 12 | resolve(action: BuildAction) { 13 | this.program 14 | .command('build') 15 | .alias('b') 16 | .description('编译应用程序.') 17 | .option('--env ', '环境变量') 18 | .action(async (destination: any) => { 19 | if (destination.env) { 20 | process.env.DAZE_ENV = destination.env; 21 | } 22 | process.env.NODE_ENV = process.env.DAZE_ENV; 23 | action.resolve(destination); 24 | }); 25 | } 26 | } -------------------------------------------------------------------------------- /packages/cli/src/commands/create.ts: -------------------------------------------------------------------------------- 1 | import * as commander from 'commander'; 2 | import { TPLActionAbstract } from '../actions'; 3 | 4 | 5 | export class CreateCommand { 6 | 7 | private program: commander.Command; 8 | 9 | constructor(program: commander.Command) { 10 | this.program = program; 11 | } 12 | 13 | resolve(action: TPLActionAbstract) { 14 | this.program 15 | .command('create [name]') 16 | .alias('c') 17 | .description('创建应用程序.') 18 | .action(async (name = '', destination: any) => { 19 | await action.source('application').resolve(name, destination); 20 | }); 21 | } 22 | } -------------------------------------------------------------------------------- /packages/cli/src/commands/dev.ts: -------------------------------------------------------------------------------- 1 | import commander from 'commander'; 2 | import { DevAction } from '../actions'; 3 | 4 | /** 5 | * 开发模式命令声明 6 | */ 7 | export class DevCommand { 8 | /** 9 | * Command 10 | */ 11 | private program: commander.Command; 12 | 13 | /** 14 | * constructor 15 | * @param program 16 | */ 17 | constructor(program: commander.Command) { 18 | this.program = program; 19 | } 20 | 21 | /** 22 | * 命令的实现 23 | * @param action 24 | */ 25 | resolve(action: DevAction) { 26 | this.program 27 | .command('dev') 28 | .alias('d') 29 | .description('应用程序开发模式.') 30 | .option('--inspect [hostport]', '启动服务端调试模式') 31 | .option('--debug', '启动 debug 模式') 32 | .action(async (destination: any) => { 33 | if (!process.env.DAZE_ENV) { 34 | process.env.DAZE_ENV = 'dev'; 35 | } 36 | action.resolve(destination); 37 | }); 38 | } 39 | } -------------------------------------------------------------------------------- /packages/cli/src/commands/index.ts: -------------------------------------------------------------------------------- 1 | export * from './create'; 2 | export * from './make'; 3 | export * from './routes'; 4 | export * from './build'; 5 | export * from './dev'; -------------------------------------------------------------------------------- /packages/cli/src/commands/make.ts: -------------------------------------------------------------------------------- 1 | import * as commander from 'commander'; 2 | import { TPLActionAbstract } from '../actions'; 3 | 4 | 5 | export class MakeCommand { 6 | 7 | private program: commander.Command; 8 | 9 | constructor(program: commander.Command) { 10 | this.program = program; 11 | } 12 | 13 | resolve(action: TPLActionAbstract) { 14 | this.program 15 | .command('make:controller [name]') 16 | .alias('mc') 17 | .description('创建 Controller 模板文件.') 18 | .option('-r, --rest', '使用 Rest 风格') 19 | .option('-p, --path ', '控制器所在目录, 默认 [controllers]') 20 | .action(async (name = '', destination: Record) => { 21 | await action.source('controller').resolve(name, destination); 22 | }); 23 | 24 | this.program 25 | .command('make:service [name]') 26 | .alias('ms') 27 | .description('创建 Service 模板文件.') 28 | .action(async (name = '', destination: any) => { 29 | await action.source('service').resolve(name, destination); 30 | }); 31 | 32 | this.program 33 | .command('make:schedule [name]') 34 | .alias('mskd') 35 | .description('创建 Schedule 模板文件.') 36 | .action(async (name = '', destination: any) => { 37 | await action.source('schedule').resolve(name, destination); 38 | }); 39 | 40 | this.program 41 | .command('make:middleware [name]') 42 | .alias('mm') 43 | .description('创建 Middleware 模板文件.') 44 | .action(async (name = '', destination: any) => { 45 | await action.source('middleware').resolve(name, destination); 46 | }); 47 | 48 | this.program 49 | .command('make:entity [name]') 50 | .alias('mm') 51 | .description('创建 Entity 模板文件.') 52 | .action(async (name = '', destination: any) => { 53 | await action.source('entity').resolve(name, destination); 54 | }); 55 | 56 | } 57 | } -------------------------------------------------------------------------------- /packages/cli/src/commands/routes.ts: -------------------------------------------------------------------------------- 1 | import * as commander from 'commander'; 2 | import { RoutesAction } from '../actions'; 3 | 4 | 5 | export class RoutesCommand { 6 | 7 | private program: commander.Command; 8 | 9 | constructor(program: commander.Command) { 10 | this.program = program; 11 | } 12 | 13 | resolve(action: RoutesAction) { 14 | this.program 15 | .command('routes') 16 | .alias('r') 17 | .description('输出项目路由信息.') 18 | .action(async () => { 19 | await action.resolve(); 20 | }); 21 | } 22 | } -------------------------------------------------------------------------------- /packages/cli/src/config.interface.ts: -------------------------------------------------------------------------------- 1 | 2 | 3 | interface NativeTigerConfigInterface { 4 | [key: string]: any 5 | } 6 | 7 | export type TigerConfigInterface = NativeTigerConfigInterface -------------------------------------------------------------------------------- /packages/cli/src/defaultTsConfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es2017", 4 | "lib": [ 5 | "esnext" 6 | ], 7 | "baseUrl": "./", 8 | "outDir": "dist", 9 | "module": "commonjs", 10 | "allowJs": false, 11 | "declaration": true, 12 | "sourceMap": true, 13 | "removeComments": true, 14 | "strict": true, 15 | "noImplicitAny": true, 16 | "strictNullChecks": true, 17 | "strictFunctionTypes": true, 18 | "strictPropertyInitialization": false, 19 | "noImplicitThis": true, 20 | "alwaysStrict": true, 21 | "noUnusedLocals": true, 22 | "noUnusedParameters": true, 23 | "noImplicitReturns": true, 24 | "moduleResolution": "node", 25 | "allowSyntheticDefaultImports": true, 26 | "esModuleInterop": true, 27 | "experimentalDecorators": true, 28 | "emitDecoratorMetadata": true, 29 | "skipLibCheck": true, 30 | "preserveSymlinks": true 31 | }, 32 | "include": [ 33 | "src" 34 | ], 35 | "exclude": [ 36 | "node_modules" 37 | ] 38 | } -------------------------------------------------------------------------------- /packages/cli/src/index.ts: -------------------------------------------------------------------------------- 1 | import { CreateAction, MakeAction } from './actions'; 2 | import { SourceType } from './lib/render'; 3 | import { init } from './lib/init'; 4 | 5 | export * from './config.interface'; 6 | 7 | export function terminate(argv: string[]) { 8 | init(argv); 9 | } 10 | 11 | /** 12 | * 创建应用 13 | * @param name 14 | */ 15 | export function create(name: string) { 16 | new CreateAction().source('application').resolve(name); 17 | } 18 | 19 | /** 20 | * 创建模块模板文件 21 | * @param name 22 | * @param type 23 | * @param options 24 | */ 25 | export function make(name: string, type: SourceType, options: any) { 26 | new MakeAction().source(type).resolve(name, options); 27 | } -------------------------------------------------------------------------------- /packages/cli/src/lib/config.ts: -------------------------------------------------------------------------------- 1 | /* eslint-disable @typescript-eslint/no-var-requires */ 2 | import fs from 'fs'; 3 | import path from 'path'; 4 | 5 | /** 6 | * 注入默认值 7 | * @param target 8 | */ 9 | function resolveDefaultValues(target: Record = {}) { 10 | target.dynamic = target.dynamic ?? true; 11 | return target; 12 | } 13 | 14 | /** 15 | * 加载用户自定义配置 16 | * tiger.config.ts 17 | * @returns 18 | */ 19 | export async function loadCustomConfig() { 20 | const cwd = process.cwd(); 21 | const ts = path.resolve(cwd, 'tiger.config.ts'); 22 | const js = path.resolve(cwd, 'tiger.config.js'); 23 | let deflector: any; 24 | if (fs.existsSync(ts)) { 25 | deflector = (await import(ts)).default; 26 | } else if (fs.existsSync(js)) { 27 | deflector = (await import(js)).default; 28 | } 29 | // 未找到文件 30 | if (!deflector) return resolveDefaultValues(); 31 | // 定义的类格式 32 | if (typeof deflector === 'function') { 33 | return resolveDefaultValues(new deflector()); 34 | } 35 | // 对象格式 36 | return resolveDefaultValues(deflector); 37 | 38 | } -------------------------------------------------------------------------------- /packages/cli/src/lib/constants.ts: -------------------------------------------------------------------------------- 1 | import chalk from 'chalk'; 2 | 3 | export const DAZE_SERVER_PREFIX = chalk.yellow('[DAZE][Server]'); 4 | export const DAZE_CLIENT_PREFIX = chalk.greenBright('[DAZE][Client]'); -------------------------------------------------------------------------------- /packages/cli/src/lib/index.ts: -------------------------------------------------------------------------------- 1 | export * from './render'; 2 | export * from './question'; 3 | export * from './printer'; 4 | export * from './ts_compile'; 5 | export * from './constants'; -------------------------------------------------------------------------------- /packages/cli/src/lib/init.ts: -------------------------------------------------------------------------------- 1 | import { Command } from 'commander'; 2 | import { CreateCommand, MakeCommand, RoutesCommand, BuildCommand, DevCommand } from '../commands'; 3 | import { CreateAction, MakeAction, RoutesAction, BuildAction, DevAction } from '../actions'; 4 | 5 | export function init(argv?: string[]) { 6 | 7 | const program = new Command(); 8 | 9 | program 10 | // eslint-disable-next-line @typescript-eslint/no-var-requires 11 | .version(require('../../package.json').version, '-v, --version'); 12 | 13 | new CreateCommand(program) 14 | .resolve( 15 | new CreateAction() 16 | ); 17 | 18 | new MakeCommand(program) 19 | .resolve( 20 | new MakeAction() 21 | ); 22 | 23 | new RoutesCommand(program) 24 | .resolve( 25 | new RoutesAction() 26 | ); 27 | 28 | new DevCommand(program) 29 | .resolve( 30 | new DevAction() 31 | ); 32 | 33 | new BuildCommand(program) 34 | .resolve( 35 | new BuildAction() 36 | ); 37 | 38 | program.parse(argv??process.argv); 39 | } -------------------------------------------------------------------------------- /packages/cli/src/lib/printer.ts: -------------------------------------------------------------------------------- 1 | export class Printer { 2 | static power() { 3 | console.log(''); 4 | } 5 | } -------------------------------------------------------------------------------- /packages/cli/src/lib/question.ts: -------------------------------------------------------------------------------- 1 | import inquirer from 'inquirer'; 2 | 3 | export class Question { 4 | private inquirer = inquirer; 5 | 6 | private promptList: inquirer.QuestionCollection[] = []; 7 | 8 | projectType() { 9 | return this; 10 | } 11 | 12 | packageManager() { 13 | this.promptList.push({ 14 | type: 'list', 15 | name: 'packageManager', 16 | message: '选择包管理工具', 17 | choices: [{ 18 | name: 'npm', 19 | value: 'npm', 20 | }, { 21 | name: 'yarn', 22 | value: 'yarn' 23 | }, { 24 | name: 'pnpm', 25 | value: 'pnpm' 26 | }, { 27 | name: '自行安装依赖', 28 | value: 'disable' 29 | }] 30 | }); 31 | return this; 32 | } 33 | async ask() { 34 | return this.inquirer.prompt(this.promptList); 35 | } 36 | } -------------------------------------------------------------------------------- /packages/cli/src/lib/runner/index.ts: -------------------------------------------------------------------------------- 1 | export * from './npm'; 2 | export * from './yarn'; 3 | export * from './pnpm'; -------------------------------------------------------------------------------- /packages/cli/src/lib/runner/npm.ts: -------------------------------------------------------------------------------- 1 | import { Runner } from './runner'; 2 | 3 | export class NpmRunner extends Runner { 4 | constructor() { 5 | super('npm'); 6 | } 7 | } -------------------------------------------------------------------------------- /packages/cli/src/lib/runner/pnpm.ts: -------------------------------------------------------------------------------- 1 | import { Runner } from './runner'; 2 | 3 | export class PNpmRunner extends Runner { 4 | constructor() { 5 | super('pnpm'); 6 | } 7 | } -------------------------------------------------------------------------------- /packages/cli/src/lib/runner/runner.ts: -------------------------------------------------------------------------------- 1 | import { ChildProcess, spawn, SpawnOptions } from 'child_process'; 2 | import chalk from 'chalk'; 3 | import * as path from 'path'; 4 | 5 | type RunnerBinary = 'npm' | 'yarn' | 'pnpm' 6 | 7 | export class Runner { 8 | 9 | private binary: RunnerBinary; 10 | private _directory = ''; 11 | 12 | constructor(binary: RunnerBinary) { 13 | this.binary = binary; 14 | } 15 | 16 | directory(directory: string) { 17 | this._directory = directory; 18 | return this; 19 | } 20 | 21 | async run(...args: string[]) { 22 | return new Promise((resolve, reject) => { 23 | const options: SpawnOptions = { 24 | cwd: path.join(process.cwd(), this._directory), 25 | stdio: 'inherit', 26 | shell: true, 27 | }; 28 | const child: ChildProcess = spawn('npx', [this.binary, ...args], options); 29 | child.on('close', code => { 30 | if (code === 0) { 31 | resolve(null); 32 | } else { 33 | console.error( 34 | chalk.red( 35 | `\nFailed to execute command: npx ${this.binary} ${args.join(' ')}`, 36 | ), 37 | ); 38 | reject(); 39 | } 40 | }); 41 | }); 42 | } 43 | } -------------------------------------------------------------------------------- /packages/cli/src/lib/runner/yarn.ts: -------------------------------------------------------------------------------- 1 | import { Runner } from './runner'; 2 | 3 | export class YarnRunner extends Runner { 4 | constructor() { 5 | super('yarn'); 6 | } 7 | } -------------------------------------------------------------------------------- /packages/cli/template/application/.gitignore: -------------------------------------------------------------------------------- 1 | # dependencies 2 | node_modules/ 3 | 4 | # IDE 5 | /.idea 6 | /.awcache 7 | /.vscode 8 | *.code-workspace 9 | 10 | 11 | # logs 12 | logs/*.log 13 | **/logs/**.log 14 | 15 | # misc 16 | .DS_Store 17 | lerna-debug.log 18 | npm-debug.log 19 | yarn-error.log 20 | packages/*/__debug__ 21 | .clinic 22 | 23 | # custom 24 | /dist -------------------------------------------------------------------------------- /packages/cli/template/application/daze: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | // eslint-disable-next-line @typescript-eslint/no-var-requires 3 | const daze = require('@dazejs/cli'); 4 | 5 | daze.terminate(process.argv); 6 | -------------------------------------------------------------------------------- /packages/cli/template/application/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "private": true, 3 | "scripts": { 4 | "dev": "daze dev", 5 | "build": "daze build" 6 | }, 7 | "keywords": [], 8 | "author": "", 9 | "license": "UNLICENSE", 10 | "dependencies": { 11 | {% for pkg, version in depensMap %} 12 | "{{ pkg }}": "{{ version }}"{% if loop.last %}{% else %},{% endif %} 13 | 14 | {% endfor %} 15 | }, 16 | "devDependencies": { 17 | {% for pkg, version in devDepensMap %} 18 | "{{ pkg }}": "{{ version }}"{% if loop.last %}{% else %},{% endif %} 19 | 20 | {% endfor %} 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /packages/cli/template/application/public/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dazejs/daze/e9d67d915a33c70cb5cdd731fc585a48a5872a5a/packages/cli/template/application/public/.keep -------------------------------------------------------------------------------- /packages/cli/template/application/src/app/example.controller.ts: -------------------------------------------------------------------------------- 1 | import { view, Controller, Get } from '@dazejs/framework'; 2 | 3 | @Controller() 4 | export class Example { 5 | @Get() 6 | index() { 7 | return view('hello.html') 8 | } 9 | } -------------------------------------------------------------------------------- /packages/cli/template/application/src/config/app.ts: -------------------------------------------------------------------------------- 1 | export default { 2 | /** 3 | * debug mode 4 | * 5 | * Be sure to turn debug off in a production environment 6 | */ 7 | debug: true, 8 | 9 | /** 10 | * static server with public path 11 | * 12 | * public - enabled or disabled public static resource request 13 | * 14 | * public_prefix - public resource request root dir 15 | */ 16 | public: true, 17 | 18 | publicPrefix: '/assets', 19 | 20 | 21 | /** 22 | * Turn on compression 23 | * 24 | * compress - enable compression 25 | * 26 | * threshold - The compression threshold 27 | */ 28 | compress: true, 29 | 30 | threshold: 1024, 31 | 32 | /** 33 | * View config 34 | * 35 | * view_extension - The view defaults to the HTML suffix 36 | */ 37 | 38 | viewExtension: 'html', 39 | 40 | /** 41 | * Cluster 42 | * 43 | * enable - enable or disable cluster mode 44 | * 45 | * workers - Number of work processes, set to 0 by default using CPU cores 46 | * 47 | * sticky - ticky session 48 | */ 49 | 50 | cluster: false, 51 | 52 | workers: 0, 53 | 54 | sticky: false, 55 | 56 | /** 57 | * template 58 | */ 59 | httpErrorTemplate: { 60 | /* ex: 404: 'errors/404.njk', root path: /views */ 61 | }, 62 | 63 | providers: [], 64 | }; -------------------------------------------------------------------------------- /packages/cli/template/application/src/config/cache.ts: -------------------------------------------------------------------------------- 1 | 2 | export default { 3 | /** 4 | * 默认使用的存储器 5 | * 可选:memory | redis | fs 6 | */ 7 | store: 'fs' 8 | } -------------------------------------------------------------------------------- /packages/cli/template/application/src/config/cookie.ts: -------------------------------------------------------------------------------- 1 | export default { 2 | /** 浏览器的最长保存时间。是一个从服务器当前时刻开始的毫秒数。 */ 3 | maxAge: 0, 4 | 5 | /** 失效时间,如果设置了 maxAge,expires 将会被覆盖。 */ 6 | expires: '', 7 | 8 | /** 生效的 URL 路径,默认设置在根路径上(/) */ 9 | path: '/', 10 | 11 | /** 设置是否对 Cookie 进行签名 */ 12 | signed: false, 13 | 14 | /** 生效的域名 */ 15 | domain: '', 16 | 17 | /** 是否可以被 js 访问,默认为 true,不允许被 js 访问 */ 18 | httpOnly: true, 19 | 20 | /** 设置 key 相同的键值对如何处理,如果设置为 true,则后设置的值会覆盖前面设置的,否则将会发送两个 set-cookie 响应头 */ 21 | overwrite: false, 22 | 23 | /** 设置只在 HTTPS 连接上传输 */ 24 | secure: false, 25 | }; -------------------------------------------------------------------------------- /packages/cli/template/application/src/config/database.ts: -------------------------------------------------------------------------------- 1 | export default { 2 | default: { 3 | type: 'mysql', 4 | host: '127.0.0.1', 5 | user: 'root', 6 | password: 'root', 7 | port: 3306, 8 | database: 'daze' 9 | }, 10 | }; -------------------------------------------------------------------------------- /packages/cli/template/application/src/config/logger.ts: -------------------------------------------------------------------------------- 1 | import path from 'path'; 2 | 3 | export default { 4 | default: 'console', 5 | channels: { 6 | compose: { 7 | driver: 'compose', 8 | channels: ['console', 'dailyFile'], 9 | }, 10 | console: { 11 | driver: 'console', 12 | }, 13 | dailyFile: { 14 | driver: 'dailyFile', 15 | filename: 'common-%DATE%.log', 16 | dirname: path.resolve(__dirname, '../../logs'), 17 | }, 18 | }, 19 | }; -------------------------------------------------------------------------------- /packages/cli/template/application/src/config/redis.ts: -------------------------------------------------------------------------------- 1 | 2 | export default { 3 | /** 4 | * 默认 Redis 连接 5 | */ 6 | default: { 7 | host: 'localhost', 8 | port: 6379 9 | }, 10 | 11 | /** 12 | * 缓存专用默认 reids 连接 13 | * 未定义的情况下,默认使用 default 连接 14 | */ 15 | // cache: { 16 | // host: 'localhost', 17 | // port: 6379 18 | // }, 19 | 20 | /** 21 | * 任务调度专用默认 reids 连接 22 | * 未定义的情况下,默认使用 default 连接 23 | */ 24 | // schedule: { 25 | // host: 'localhost', 26 | // port: 6379 27 | // }, 28 | } -------------------------------------------------------------------------------- /packages/cli/template/application/src/config/session.ts: -------------------------------------------------------------------------------- 1 | export default { 2 | 3 | /** 4 | * =============================================== 5 | * Session Store 6 | * =============================================== 7 | * Supported: cookie | redis 8 | */ 9 | store: 'cookie', 10 | /** 11 | * =============================================== 12 | * Cookie Session Key 13 | * =============================================== 14 | */ 15 | key: 'dazejs:sess', 16 | 17 | /** 18 | * =============================================== 19 | * Renew Session 20 | * =============================================== 21 | * Should renew session expried time when true 22 | */ 23 | renew: false, 24 | 25 | /** 26 | * =============================================== 27 | * Session MaxAge 28 | * =============================================== 29 | */ 30 | maxAge: 8640000, 31 | 32 | /** 33 | * =============================================== 34 | * HttpOnly Session Cookie 35 | * =============================================== 36 | */ 37 | httpOnly: true, 38 | 39 | /** 40 | * =============================================== 41 | * Signed Session 42 | * =============================================== 43 | */ 44 | signed: true, 45 | 46 | /** 47 | * =============================================== 48 | * Session auto commit 49 | * =============================================== 50 | */ 51 | autoCommit: true, 52 | 53 | /** 54 | * =============================================== 55 | * Redis Store Connection 56 | * =============================================== 57 | */ 58 | connection: 'session', 59 | }; -------------------------------------------------------------------------------- /packages/cli/template/application/src/index.ts: -------------------------------------------------------------------------------- 1 | import { Application } from '@dazejs/framework' 2 | 3 | const app = new Application() 4 | 5 | app.run() -------------------------------------------------------------------------------- /packages/cli/template/application/views/hello.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Daze.js 8 | 33 | 34 | 35 |
36 |
37 | Hello, Daze.js! 38 |
39 |
40 | 41 | -------------------------------------------------------------------------------- /packages/cli/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.json", 3 | "compilerOptions": { 4 | "baseUrl": "./", 5 | "outDir": "dist", 6 | "module": "commonjs" 7 | }, 8 | "include": [ 9 | "src", 10 | "g.d.ts" 11 | ], 12 | "exclude": [ 13 | "node_modules" 14 | ] 15 | } -------------------------------------------------------------------------------- /packages/create-app/README.md: -------------------------------------------------------------------------------- 1 | # `create` 2 | 3 | > TODO: description 4 | 5 | ## Usage 6 | 7 | ``` 8 | const create = require('create'); 9 | 10 | // TODO: DEMONSTRATE API 11 | ``` 12 | -------------------------------------------------------------------------------- /packages/create-app/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@dazejs/create-app", 3 | "version": "1.0.2", 4 | "description": "create dazejs app", 5 | "author": "czewail ", 6 | "homepage": "", 7 | "license": "UNLICENSE", 8 | "files": [ 9 | "lib" 10 | ], 11 | "bin": { 12 | "create-app": "dist/create.js" 13 | }, 14 | "scripts": { 15 | "clean": "rimraf dist/*", 16 | "build": "npm run clean && tsc", 17 | "test": "node -v", 18 | "test:coverage": "node -v", 19 | "dev": "npm run clean && tsc -w" 20 | }, 21 | "dependencies": { 22 | "@dazejs/cli": "1.0.2", 23 | "chalk": "^4.1.1", 24 | "commander": "^7.2.0" 25 | }, 26 | "gitHead": "4d87844d5c3483689a94a63ac992c98ab9ff1224" 27 | } 28 | -------------------------------------------------------------------------------- /packages/create-app/src/create.ts: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | import { create } from '@dazejs/cli'; 4 | import { Command } from 'commander'; 5 | import chalk from 'chalk'; 6 | 7 | // eslint-disable-next-line @typescript-eslint/no-var-requires 8 | const packageJson = require('../package.json'); 9 | 10 | 11 | const program = new Command(packageJson.name); 12 | 13 | program 14 | .version(packageJson.version, '-v, --version') 15 | .arguments('') 16 | .usage(`${chalk.green('')}`) 17 | .action(name => { 18 | create(name); 19 | }); 20 | 21 | program.parse(process.argv); 22 | 23 | -------------------------------------------------------------------------------- /packages/create-app/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.json", 3 | "compilerOptions": { 4 | "baseUrl": "./", 5 | "outDir": "dist", 6 | "module": "commonjs" 7 | }, 8 | "include": [ 9 | "src", 10 | ], 11 | "exclude": [ 12 | "node_modules" 13 | ] 14 | } -------------------------------------------------------------------------------- /packages/framework/.npmignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | coverage 3 | __tests__ 4 | __debug__ 5 | .idea 6 | .vscode 7 | logs 8 | -------------------------------------------------------------------------------- /packages/framework/__tests__/common/assets/example.txt: -------------------------------------------------------------------------------- 1 | example -------------------------------------------------------------------------------- /packages/framework/__tests__/common/context.ts: -------------------------------------------------------------------------------- 1 | 2 | import Stream from 'stream'; 3 | import { IncomingMessage, ServerResponse } from 'http'; 4 | 5 | export function context(_req?: object, _res?: object) { 6 | const socket = new Stream.Duplex(); 7 | const req = Object.assign({ headers: {}, socket }, Stream.Readable.prototype, _req) as IncomingMessage; 8 | const res = Object.assign({ _headers: {}, socket }, Stream.Writable.prototype, _res) as unknown as ServerResponse; 9 | // eslint-disable-next-line 10 | // @ts-ignore 11 | req.socket.remoteAddress = req.socket.remoteAddress || '127.0.0.1'; 12 | return { req, res }; 13 | } -------------------------------------------------------------------------------- /packages/framework/__tests__/daze/logs/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dazejs/daze/e9d67d915a33c70cb5cdd731fc585a48a5872a5a/packages/framework/__tests__/daze/logs/.keep -------------------------------------------------------------------------------- /packages/framework/__tests__/daze/src/app/component/InjectComponent.ts: -------------------------------------------------------------------------------- 1 | import { Component, Injectable } from '../../../../../src'; 2 | 3 | @Component() 4 | @Injectable 5 | export class InjectComponent { 6 | 7 | } 8 | -------------------------------------------------------------------------------- /packages/framework/__tests__/daze/src/app/component/TestLogger.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Test for Logger 3 | */ 4 | export class TestLogger { 5 | private readonly props: any; 6 | 7 | constructor(props: any) { 8 | this.props = props; 9 | } 10 | 11 | log(l: any): string { 12 | return `TestLogger(${this.props}) => ${l}`; 13 | } 14 | 15 | } 16 | 17 | export class TestLogger2 { 18 | private readonly props: any; 19 | 20 | constructor(props: any) { 21 | this.props = props; 22 | } 23 | 24 | log(l: any): string { 25 | return `TestLogger2(${this.props}) => ${l}`; 26 | } 27 | 28 | } -------------------------------------------------------------------------------- /packages/framework/__tests__/daze/src/app/controller/autoinject.ts: -------------------------------------------------------------------------------- 1 | import { 2 | Controller, Get 3 | } from '../../../../../src'; 4 | import ExampleService from '../service/example'; 5 | 6 | @Controller('autoinject') 7 | export default class { 8 | @Get() 9 | index(example: ExampleService) { 10 | return example.sayHello(); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /packages/framework/__tests__/daze/src/app/controller/cross.ts: -------------------------------------------------------------------------------- 1 | import { 2 | CrossOrigin, Controller, Post, 3 | } from '../../../../../src'; 4 | 5 | @Controller('cross') 6 | export default class { 7 | @Post() 8 | @CrossOrigin() 9 | store() { 10 | return 'hello'; 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /packages/framework/__tests__/daze/src/app/controller/csrf.ts: -------------------------------------------------------------------------------- 1 | import { 2 | Controller, Post, Get, Csrf, 3 | } from '../../../../../src'; 4 | 5 | @Controller('/csrf') 6 | export default class { 7 | @Post() 8 | @Csrf() 9 | store() { 10 | return 'hello'; 11 | } 12 | 13 | @Get('/get') 14 | @Csrf() 15 | show() { 16 | return 'hello'; 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /packages/framework/__tests__/daze/src/app/controller/dto/daze.dto.ts: -------------------------------------------------------------------------------- 1 | 2 | export class DazeDto { 3 | readonly id: number; 4 | readonly name: string; 5 | readonly age: number; 6 | } 7 | -------------------------------------------------------------------------------- /packages/framework/__tests__/daze/src/app/controller/example.ts: -------------------------------------------------------------------------------- 1 | import { 2 | Controller, Get, Autowired, Post, request, View 3 | } from '../../../../../src'; 4 | import ExampleService from '../service/example'; 5 | 6 | 7 | @Controller('/example') 8 | export default class { 9 | @Autowired 10 | exampleService: ExampleService; 11 | 12 | @Get('/template') 13 | template() { 14 | return new View('hello', { 15 | name: 'dazejs' 16 | }); 17 | } 18 | 19 | @Get() 20 | index() { 21 | return this.exampleService.sayHello(); 22 | } 23 | 24 | @Post('post') 25 | store() { 26 | return { 27 | body: request().body, 28 | files: request().files, 29 | }; 30 | } 31 | 32 | @Get('/null') 33 | sayNull() { 34 | return null; 35 | } 36 | 37 | @Get('/number') 38 | sayNumber(): number { 39 | return 0; 40 | } 41 | 42 | @Get('/boolean') 43 | sayBoolean(): boolean { 44 | return true; 45 | } 46 | 47 | } 48 | -------------------------------------------------------------------------------- /packages/framework/__tests__/daze/src/app/controller/injectable.ts: -------------------------------------------------------------------------------- 1 | import { 2 | Controller, Get, Query, Params, Body, Header, Post 3 | } from '../../../../../src'; 4 | import { DazeDto } from "./dto/daze.dto"; 5 | 6 | @Controller('/injectable') 7 | export default class { 8 | @Get() 9 | index(@Query('id') id: number) { 10 | return id || 'hello world'; 11 | } 12 | 13 | @Get('name') 14 | getName(@Query('id') id: number, @Query('name') name: string) { 15 | return `${id}:${name}` || 'hello world'; 16 | } 17 | 18 | @Get('name/default') 19 | getNameDefault(@Query('name', "daze") name: string) { 20 | return name; 21 | } 22 | 23 | @Get('params') 24 | getParams(@Params() params: any) { 25 | return params; 26 | } 27 | 28 | @Post('body') 29 | getDazeBody(@Body() dto: DazeDto): DazeDto { 30 | return dto; 31 | } 32 | 33 | @Post('body2') 34 | getDazeBody2(@Body('key2.key1') dto: DazeDto): DazeDto { 35 | return dto; 36 | } 37 | 38 | @Get('header') 39 | getHeader(@Header('my-header') host: string) { 40 | return host; 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /packages/framework/__tests__/daze/src/app/controller/middleware.ts: -------------------------------------------------------------------------------- 1 | import { 2 | Controller, Get, UseMiddleware 3 | } from '../../../../../src'; 4 | import { Example1 } from '../middleware/example-1'; 5 | import { Example2 } from '../middleware/example-2'; 6 | 7 | @Controller('/middleware') 8 | @UseMiddleware(Example2) 9 | export class MiddlewareController { 10 | @Get('/example1') 11 | @UseMiddleware(Example1) 12 | store() { 13 | return 'Hello Dazejs'; 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /packages/framework/__tests__/daze/src/app/controller/redirect.ts: -------------------------------------------------------------------------------- 1 | import { 2 | Controller, Get, Redirect 3 | } from '../../../../../src'; 4 | 5 | 6 | @Controller('/redirect') 7 | export default class { 8 | @Get() 9 | show() { 10 | return new Redirect().go('https://www.google.com'); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /packages/framework/__tests__/daze/src/app/controller/routes.ts: -------------------------------------------------------------------------------- 1 | import { 2 | Controller, Get, 3 | } from '../../../../../src'; 4 | 5 | @Controller('routes') 6 | export default class { 7 | @Get('*') 8 | all1() { 9 | return 'all1'; 10 | } 11 | 12 | @Get('all2') 13 | all2() { 14 | return 'all2'; 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /packages/framework/__tests__/daze/src/app/entities/comment.ts: -------------------------------------------------------------------------------- 1 | import { BaseEntity, AutoIncrementPrimaryColumn, Column, BelongsTo, Entity } from '../../../../../src'; 2 | import User from './user'; 3 | 4 | @Entity('comments') 5 | export default class extends BaseEntity { 6 | @AutoIncrementPrimaryColumn() 7 | id: number; 8 | 9 | @Column() 10 | user_id: number; 11 | 12 | @Column() 13 | comment: string; 14 | 15 | @BelongsTo(() => User) 16 | user: User; 17 | } -------------------------------------------------------------------------------- /packages/framework/__tests__/daze/src/app/entities/profile.ts: -------------------------------------------------------------------------------- 1 | import { BaseEntity, AutoIncrementPrimaryColumn, Column, BelongsTo, Entity } from '../../../../../src'; 2 | import User from './user'; 3 | 4 | @Entity('profiles') 5 | export default class extends BaseEntity { 6 | @AutoIncrementPrimaryColumn() 7 | id: number; 8 | 9 | @Column() 10 | user_id: number; 11 | 12 | @Column() 13 | motto: string; 14 | 15 | @BelongsTo(() => User) 16 | user: User; 17 | } -------------------------------------------------------------------------------- /packages/framework/__tests__/daze/src/app/entities/role.ts: -------------------------------------------------------------------------------- 1 | import { BaseEntity, AutoIncrementPrimaryColumn, Column, BelongsToMany, Entity } from '../../../../../src'; 2 | import User from './user'; 3 | 4 | 5 | @Entity('roles') 6 | export default class extends BaseEntity { 7 | @AutoIncrementPrimaryColumn() 8 | id: number; 9 | 10 | @Column() 11 | description: string; 12 | 13 | @BelongsToMany(() => User) 14 | users: User[]; 15 | } -------------------------------------------------------------------------------- /packages/framework/__tests__/daze/src/app/entities/user.ts: -------------------------------------------------------------------------------- 1 | import { BaseEntity, AutoIncrementPrimaryColumn, Column, BelongsToMany, HasOne, Entity, HasMany } from '../../../../../src'; 2 | import Profile from './profile'; 3 | import Comment from './comment'; 4 | import Role from './role'; 5 | 6 | @Entity('users') 7 | export default class extends BaseEntity { 8 | @AutoIncrementPrimaryColumn() 9 | id: number; 10 | 11 | @Column() 12 | name: string; 13 | 14 | @Column() 15 | age: number; 16 | 17 | @Column() 18 | description: string; 19 | 20 | @HasOne(() => Profile) 21 | profile: Profile; 22 | 23 | @HasMany(() => Comment) 24 | comments: Comment[]; 25 | 26 | @BelongsToMany(() => Role) 27 | roles: Role[]; 28 | } -------------------------------------------------------------------------------- /packages/framework/__tests__/daze/src/app/middleware/example-1.ts: -------------------------------------------------------------------------------- 1 | import { Request, Next, Middleware, Response } from '../../../../../src'; 2 | 3 | @Middleware() 4 | export class Example1 { 5 | resolve(request: Request, next: Next) { 6 | if (request.getQuery('name') === 'example1') { 7 | return new Response().success('Hello Example1'); 8 | } 9 | return next(); 10 | } 11 | } -------------------------------------------------------------------------------- /packages/framework/__tests__/daze/src/app/middleware/example-2.ts: -------------------------------------------------------------------------------- 1 | import { Request, Next, Middleware, Response } from '../../../../../src'; 2 | 3 | @Middleware() 4 | export class Example2 { 5 | resolve(request: Request, next: Next) { 6 | if (request.getQuery('name') === 'example2') { 7 | return new Response().success('Hello Example2'); 8 | } 9 | return next(); 10 | } 11 | } -------------------------------------------------------------------------------- /packages/framework/__tests__/daze/src/app/middleware/example-order.ts: -------------------------------------------------------------------------------- 1 | import { Order, Middleware } from '../../../../../src'; 2 | 3 | @Middleware() 4 | export class ExampleMiddlewareOrder { 5 | resolve(): any | Promise { 6 | return 'ExampleMiddlewareOrder'; 7 | } 8 | } 9 | 10 | @Order(0) 11 | @Middleware() 12 | export class ExampleMiddlewareOrder0 { 13 | resolve(): any | Promise { 14 | return 'ExampleMiddlewareOrder0'; 15 | } 16 | } 17 | 18 | @Order(1) 19 | @Middleware() 20 | export class ExampleMiddlewareOrder1 { 21 | resolve(): any | Promise { 22 | return 'ExampleMiddlewareOrder1'; 23 | } 24 | } 25 | 26 | @Order(Number.MAX_SAFE_INTEGER) 27 | @Middleware() 28 | export class ExampleMiddlewareOrderMax { 29 | resolve(): any | Promise { 30 | return 'ExampleMiddlewareOrderMax'; 31 | } 32 | } 33 | 34 | @Order(Number.MIN_SAFE_INTEGER) 35 | @Middleware() 36 | export class ExampleMiddlewareOrderMin { 37 | resolve(): any | Promise { 38 | return 'ExampleMiddlewareOrderMin'; 39 | } 40 | } 41 | 42 | @Order(Number.MAX_SAFE_INTEGER + 1) 43 | @Middleware() 44 | export class ExampleMiddlewareOrderMax1 { 45 | resolve(): any | Promise { 46 | return 'ExampleMiddlewareOrderMax1'; 47 | } 48 | } -------------------------------------------------------------------------------- /packages/framework/__tests__/daze/src/app/service/example.ts: -------------------------------------------------------------------------------- 1 | import { Service } from '../../../../../src'; 2 | 3 | @Service('example-service') 4 | export default class { 5 | sayHello() { 6 | return 'Hello Dazejs'; 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /packages/framework/__tests__/daze/src/app/service/injectable.ts: -------------------------------------------------------------------------------- 1 | import { Query, Service } from '../../../../../src'; 2 | 3 | 4 | @Service('injectable-service') 5 | export default class { 6 | sayId( 7 | @Query('id') id: number 8 | ) { 9 | return id ?? 'Hello Dazejs'; 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /packages/framework/__tests__/daze/src/config/app.test.ts: -------------------------------------------------------------------------------- 1 | export default { 2 | name: 'dazejs', 3 | }; 4 | -------------------------------------------------------------------------------- /packages/framework/__tests__/daze/src/config/app.ts: -------------------------------------------------------------------------------- 1 | import { TestLoggerProvider } from '../provider/test-logger-provider'; 2 | export default { 3 | port: 0, 4 | proxy: false, 5 | cluster: false, 6 | workers: 0, 7 | sticky: false, 8 | viewExtension: 'html', 9 | providers: [ 10 | TestLoggerProvider 11 | ] 12 | }; 13 | -------------------------------------------------------------------------------- /packages/framework/__tests__/daze/src/config/cookie.ts: -------------------------------------------------------------------------------- 1 | export default { 2 | /** 浏览器的最长保存时间。是一个从服务器当前时刻开始的毫秒数。 */ 3 | maxAge: 0, 4 | 5 | /** 失效时间,如果设置了 maxAge,expires 将会被覆盖。 */ 6 | expires: '', 7 | 8 | /** 生效的 URL 路径,默认设置在根路径上(/) */ 9 | path: '/', 10 | 11 | /** 设置是否对 Cookie 进行签名 */ 12 | signed: true, 13 | 14 | /** 生效的域名 */ 15 | domain: '', 16 | 17 | /** 是否可以被 js 访问,默认为 true,不允许被 js 访问 */ 18 | httpOnly: true, 19 | 20 | /** 设置 key 相同的键值对如何处理,如果设置为 true,则后设置的值会覆盖前面设置的,否则将会发送两个 set-cookie 响应头 */ 21 | overwrite: false, 22 | 23 | /** 设置只在 HTTPS 连接上传输 */ 24 | secure: false, 25 | }; 26 | -------------------------------------------------------------------------------- /packages/framework/__tests__/daze/src/config/custom.test.ts: -------------------------------------------------------------------------------- 1 | export default () => { 2 | // 3 | }; 4 | -------------------------------------------------------------------------------- /packages/framework/__tests__/daze/src/config/custom.ts: -------------------------------------------------------------------------------- 1 | 2 | export default { 3 | a: { 4 | b: { 5 | c: 'c', 6 | }, 7 | }, 8 | }; 9 | -------------------------------------------------------------------------------- /packages/framework/__tests__/daze/src/config/database.ts: -------------------------------------------------------------------------------- 1 | export default { 2 | default: { 3 | type: 'mysql', 4 | host: 'localhost', 5 | user: 'root', 6 | password: 'root', 7 | port: 3306, 8 | database: 'daze' 9 | }, 10 | session: { 11 | type: 'redis', 12 | host: '127.0.0.1', 13 | port: 6379 14 | } 15 | }; 16 | -------------------------------------------------------------------------------- /packages/framework/__tests__/daze/src/config/daze.ts: -------------------------------------------------------------------------------- 1 | export default { 2 | redis: { 3 | host: '127.0.0.1', 4 | port: 6379, 5 | } 6 | }; 7 | -------------------------------------------------------------------------------- /packages/framework/__tests__/daze/src/config/logger.ts: -------------------------------------------------------------------------------- 1 | import path from 'path'; 2 | import fs from 'fs'; 3 | 4 | export default { 5 | default: 'console', 6 | channels: { 7 | compose: { 8 | driver: 'compose', 9 | channels: ['console', 'dailyFile'], 10 | }, 11 | console: { 12 | driver: 'console', 13 | }, 14 | console3: { 15 | driver: 'console3', 16 | }, 17 | file: { 18 | driver: 'file', 19 | filename: path.resolve(__dirname, '../logs'), 20 | }, 21 | http: { 22 | driver: 'http', 23 | }, 24 | stream: { 25 | driver: 'stream', 26 | stream: fs.createWriteStream('/dev/null'), 27 | }, 28 | dailyFile: { 29 | driver: 'dailyFile', 30 | filename: 'common-%DATE%.log', 31 | dirname: path.resolve(__dirname, '../../logs'), 32 | }, 33 | }, 34 | }; 35 | -------------------------------------------------------------------------------- /packages/framework/__tests__/daze/src/config/session.ts: -------------------------------------------------------------------------------- 1 | export default { 2 | 3 | /** 4 | * =============================================== 5 | * Session Store 6 | * =============================================== 7 | * Supported: cookie | redis 8 | */ 9 | store: 'cookie', 10 | /** 11 | * =============================================== 12 | * Cookie Session Key 13 | * =============================================== 14 | */ 15 | key: 'dazejs:sess', 16 | 17 | /** 18 | * =============================================== 19 | * Renew Session 20 | * =============================================== 21 | * Should renew session expried time when true 22 | */ 23 | renew: false, 24 | 25 | /** 26 | * =============================================== 27 | * Session MaxAge 28 | * =============================================== 29 | */ 30 | maxAge: 8640000, 31 | 32 | /** 33 | * =============================================== 34 | * HttpOnly Session Cookie 35 | * =============================================== 36 | */ 37 | httpOnly: true, 38 | 39 | /** 40 | * =============================================== 41 | * Signed Session 42 | * =============================================== 43 | */ 44 | signed: true, 45 | 46 | /** 47 | * =============================================== 48 | * Session auto commit 49 | * =============================================== 50 | */ 51 | autoCommit: true, 52 | 53 | /** 54 | * =============================================== 55 | * Redis Store Connection 56 | * =============================================== 57 | */ 58 | connection: 'session', 59 | }; 60 | -------------------------------------------------------------------------------- /packages/framework/__tests__/daze/src/logs: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dazejs/daze/e9d67d915a33c70cb5cdd731fc585a48a5872a5a/packages/framework/__tests__/daze/src/logs -------------------------------------------------------------------------------- /packages/framework/__tests__/daze/src/provider/app.ts: -------------------------------------------------------------------------------- 1 | 2 | import { Provider } from '../../../../src'; 3 | 4 | @Provider() 5 | export default class { 6 | 7 | } 8 | -------------------------------------------------------------------------------- /packages/framework/__tests__/daze/src/provider/test-logger-provider.ts: -------------------------------------------------------------------------------- 1 | import { Depends, Provide, ProvideOn, ProvideOnMissing } from "../../../../src/decorators"; 2 | import { config } from "../../../../src"; 3 | import { TestLogger, TestLogger2 } from "../app/component/TestLogger"; 4 | 5 | @Depends() 6 | export class TestLoggerProvider { 7 | @Provide() 8 | @ProvideOnMissing('testLogger') 9 | testLogger() { 10 | return new TestLogger(config("custom.a.b.c", 'testConfig')); 11 | } 12 | 13 | @Provide() 14 | @ProvideOn("not-exists") 15 | testLogger2() { 16 | return new TestLogger2(config("custom.a.b.c1", "testConfig2")); 17 | } 18 | } -------------------------------------------------------------------------------- /packages/framework/__tests__/daze/views/hello.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Daze.js 8 | 33 | 34 | 35 |
36 |
37 | Hello, {{name}}! 38 |
39 |
40 | 41 | -------------------------------------------------------------------------------- /packages/framework/__tests__/features/current/app/test.ts: -------------------------------------------------------------------------------- 1 | import { Get, Controller } from '../../../../src'; 2 | 3 | @Controller('/features/current') 4 | export class App { 5 | @Get() 6 | index() { 7 | return 'hello current'; 8 | } 9 | } -------------------------------------------------------------------------------- /packages/framework/__tests__/features/current/config/app.ts: -------------------------------------------------------------------------------- 1 | export default { 2 | cluster: false 3 | }; -------------------------------------------------------------------------------- /packages/framework/__tests__/features/current/current.spec.ts: -------------------------------------------------------------------------------- 1 | import request from 'supertest'; 2 | import { Application } from '../../../src'; 3 | 4 | const app = new Application(); 5 | 6 | 7 | beforeAll(() => app.run(7677), 10); 8 | afterAll(() => app.close(), 10); 9 | 10 | 11 | it('should work base', async () => { 12 | await request((app as any)._server).get('/features/current').expect(200, 'hello current'); 13 | }); 14 | -------------------------------------------------------------------------------- /packages/framework/__tests__/features/index.spec.ts: -------------------------------------------------------------------------------- 1 | import path from 'path'; 2 | import request from 'supertest'; 3 | import { Application } from '../../src'; 4 | 5 | const app = new Application({ 6 | rootPath: path.resolve(__dirname, '../daze/src') 7 | }); 8 | 9 | 10 | beforeAll(() => app.run(7676)); 11 | afterAll(() => app.close()); 12 | 13 | 14 | it('should work base', async () => { 15 | await request((app as any)._server).get('/example').expect(200, 'Hello Dazejs'); 16 | await request((app as any)._server).get('/example/template').expect(200); 17 | await request((app as any)._server).get('/example/null').expect(204, ''); 18 | await request((app as any)._server).get('/example/number').expect(200, '0'); 19 | await request((app as any)._server).get('/example/boolean').expect(200, 'true'); 20 | }); 21 | -------------------------------------------------------------------------------- /packages/framework/__tests__/src/cluster/worker.spec.ts: -------------------------------------------------------------------------------- 1 | import 'reflect-metadata'; 2 | import { Worker } from '../../../src/cluster/worker'; 3 | import * as http from 'http'; 4 | import request from 'supertest'; 5 | 6 | describe('Worker Process', () => { 7 | it('should run with createServer', async () => { 8 | const worker = new Worker({ 9 | port: 0, 10 | sticky: false, 11 | createServer: (...args) => { 12 | const server = http.createServer((_req, res) => { 13 | res.end('cluster'); 14 | }); 15 | return server.listen(...args); 16 | } 17 | }); 18 | const server = await worker.run(); 19 | const res = await request(server).get('/'); 20 | expect(res.text).toBe('cluster'); 21 | server.close(); 22 | }); 23 | }); -------------------------------------------------------------------------------- /packages/framework/__tests__/src/database/init.ts: -------------------------------------------------------------------------------- 1 | import * as mysql from 'mysql2'; 2 | 3 | async function dropTable(connection: mysql.Connection, table: string) { 4 | await new Promise((resolve, reject) => { 5 | connection.query(`DROP TABLE \`${table}\``, (err) => { 6 | if (err) { 7 | if (err.code === 'ER_BAD_TABLE_ERROR') { 8 | return resolve(true); 9 | } else { 10 | console.error('[DROP ERROR] - ', err.message); 11 | return reject(err); 12 | } 13 | } 14 | return resolve(true); 15 | }); 16 | }); 17 | } 18 | 19 | async function createTable(connection: mysql.Connection, sql: string) { 20 | await new Promise((resolve, reject) => { 21 | connection.query(sql, (err) => { 22 | if (err) { 23 | console.error('[CREATE ERROR] - ', err.message); 24 | return reject(err); 25 | } 26 | return resolve(true); 27 | }); 28 | }); 29 | } 30 | 31 | 32 | export async function initDb() { 33 | const connection = mysql.createConnection({ 34 | host: 'localhost', 35 | user: 'root', 36 | password: 'root', 37 | database: 'daze', 38 | port: 3306 39 | }); 40 | 41 | connection.connect(); 42 | 43 | // 删除 users 表 44 | await dropTable(connection, 'users'); 45 | // 删除 comments 表 46 | await dropTable(connection, 'comments'); 47 | // 创建 users 表 48 | await createTable(connection, `CREATE TABLE \`users\` ( 49 | \`id\` int(11) unsigned NOT NULL AUTO_INCREMENT, 50 | \`name\` varchar(255) NOT NULL DEFAULT '', 51 | \`age\` int(11) NOT NULL, 52 | \`description\` varchar(255) DEFAULT NULL, 53 | PRIMARY KEY (\`id\`) 54 | ) ENGINE=InnoDB DEFAULT CHARSET=utf8;`); 55 | // 创建 comments 表 56 | await createTable(connection, `CREATE TABLE \`comments\` ( 57 | \`id\` int(11) unsigned NOT NULL AUTO_INCREMENT, 58 | \`user_id\` int(11) NOT NULL, 59 | \`comment\` varchar(11) NOT NULL DEFAULT '', 60 | PRIMARY KEY (\`id\`) 61 | ) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8;`); 62 | 63 | connection.end(); 64 | } -------------------------------------------------------------------------------- /packages/framework/__tests__/src/decorators/component.spec.ts: -------------------------------------------------------------------------------- 1 | import 'reflect-metadata'; 2 | import { Component } from '../../../src/decorators/stereotype/component'; 3 | 4 | describe('Component Decorator', () => { 5 | it('should patch injectable and name in Component', () => { 6 | @Component('example') 7 | class Example { } 8 | expect(Reflect.getMetadata('name', Example)).toBe('example'); 9 | }); 10 | }); 11 | -------------------------------------------------------------------------------- /packages/framework/__tests__/src/decorators/factory/create-inject-decorator.spec.ts: -------------------------------------------------------------------------------- 1 | import 'reflect-metadata'; 2 | import { decoratorFactory } from '../../../../src/decorators/factory/decorator-factory'; 3 | import * as symbols from '../../../../src/symbol'; 4 | 5 | describe('Descrators/factory/create-inject-decorator', () => { 6 | describe('patchClass', () => { 7 | it('should patch injectable and types in constructor', () => { 8 | @decoratorFactory('request', ['a', 'b']) 9 | class Klass { 10 | testname: string; 11 | constructor() { 12 | this.testname = ''; 13 | } 14 | } 15 | expect(Reflect.getMetadata(symbols.INJECTABLE, Klass)).toBeTruthy(); 16 | expect(Reflect.getMetadata(symbols.INJECTTYPE_METADATA, Klass)).toEqual([ 17 | { 18 | abstract: 'request', 19 | params: ['a', 'b'], 20 | handler: undefined 21 | } 22 | ]); 23 | }); 24 | }); 25 | 26 | describe('patchProperty', () => { 27 | it('should patch injectable and types in property', () => { 28 | class Klass { 29 | @decoratorFactory('request', ['a', 'b']) 30 | testname = ''; 31 | } 32 | expect(Reflect.getMetadata(symbols.INJECTABLE, Klass)).toBeTruthy(); 33 | expect(Reflect.getMetadata(symbols.INJECTTYPE_METADATA, Klass, 'testname')).toEqual([ 34 | { 35 | abstract: 'request', 36 | params: ['a', 'b'], 37 | handler: undefined 38 | } 39 | ]); 40 | }); 41 | }); 42 | 43 | describe('patchMethod', () => { 44 | it('should patch injectable and types in method', () => { 45 | class Klass { 46 | @decoratorFactory('request', ['a', 'b']) 47 | index() { 48 | // 49 | } 50 | } 51 | expect(Reflect.getMetadata(symbols.INJECTABLE, Klass)).toBeTruthy(); 52 | expect(Reflect.getMetadata(symbols.INJECTTYPE_METADATA, Klass, 'index')).toEqual([ 53 | { 54 | abstract: 'request', 55 | params: ['a', 'b'], 56 | handler: undefined 57 | } 58 | ]); 59 | }); 60 | }); 61 | }); 62 | -------------------------------------------------------------------------------- /packages/framework/__tests__/src/decorators/ignore.spec.ts: -------------------------------------------------------------------------------- 1 | import 'reflect-metadata'; 2 | import { Ignore } from '../../../src/decorators/ignore'; 3 | 4 | describe('Ignore Decorator', () => { 5 | it('should patch Ignore by @Ignore', () => { 6 | @Ignore 7 | class Example { } 8 | expect(Reflect.getMetadata('ignore', Example)).toBeTruthy(); 9 | }); 10 | }); 11 | -------------------------------------------------------------------------------- /packages/framework/__tests__/src/decorators/inject.spec.ts: -------------------------------------------------------------------------------- 1 | import 'reflect-metadata'; 2 | import * as path from 'path'; 3 | import { Application, Inject } from '../../../src'; 4 | // import { InjectComponent } from '../../daze/src/app/component/InjectComponent'; 5 | 6 | const app = new Application( 7 | { 8 | rootPath: path.resolve(__dirname, '../../daze/src') 9 | } 10 | ); 11 | 12 | beforeAll(() => app.initialize()); 13 | 14 | 15 | describe('@Inject', () => { 16 | it('should inject with class prop', () => { 17 | app.singleton('example1', () => 'hello example1', true); 18 | class Example1 { 19 | @Inject('example1') example1: string; 20 | } 21 | app.singleton(Example1, Example1); 22 | expect(app.get(Example1).example1).toBe('hello example1'); 23 | }); 24 | }); 25 | -------------------------------------------------------------------------------- /packages/framework/__tests__/src/decorators/injectable.spec.ts: -------------------------------------------------------------------------------- 1 | import 'reflect-metadata'; 2 | import { Injectable } from '../../../src/decorators/stereotype/injectable'; 3 | import * as symbols from '../../../src/symbol'; 4 | 5 | describe('Injectable Decorator', () => { 6 | it('should patch Injectable by @Injectable', () => { 7 | @Injectable 8 | class Example { } 9 | expect(Reflect.getMetadata(symbols.INJECTABLE, Example)).toBeTruthy(); 10 | }); 11 | }); 12 | -------------------------------------------------------------------------------- /packages/framework/__tests__/src/decorators/multiton.spec.ts: -------------------------------------------------------------------------------- 1 | import 'reflect-metadata'; 2 | import { Multiton } from '../../../src/decorators/multiton'; 3 | import { MULTITON } from '../../../src/symbol'; 4 | 5 | describe('Multiton Decorator', () => { 6 | it('should patch Multiton flag in Multiton', () => { 7 | @Multiton 8 | class Example { 9 | 10 | } 11 | expect(Reflect.getMetadata(MULTITON, Example)).toBeTruthy(); 12 | }); 13 | }); 14 | -------------------------------------------------------------------------------- /packages/framework/__tests__/src/decorators/rest.spec.ts: -------------------------------------------------------------------------------- 1 | import 'reflect-metadata'; 2 | import { Rest } from '../../../src'; 3 | 4 | describe('Rest Decorator', () => { 5 | it('should patch rest routes and prefix by @Rest', () => { 6 | @Rest('example') 7 | class Example { } 8 | expect(Reflect.getMetadata('routes', Example)).toEqual({ 9 | index: [{ uri: '/', method: 'get' }], 10 | create: [{ uri: '/create', method: 'get' }], 11 | show: [{ uri: '/:id', method: 'get' }], 12 | store: [{ uri: '/', method: 'post' }], 13 | edit: [{ uri: '/:id/edit', method: 'get' }], 14 | update: [{ uri: '/:id', method: 'put' }], 15 | destroy: [{ uri: '/:id', method: 'delete' }], 16 | }); 17 | expect(Reflect.getMetadata('prefixs', Example)).toEqual(['/example']); 18 | }); 19 | }); 20 | -------------------------------------------------------------------------------- /packages/framework/__tests__/src/decorators/route.spec.ts: -------------------------------------------------------------------------------- 1 | import 'reflect-metadata'; 2 | import { Controller } from '../../../src'; 3 | 4 | describe('Controller Decorator', () => { 5 | it('should patch type and prefix in Controller', () => { 6 | @Controller('example') 7 | class Example { } 8 | expect(Reflect.getMetadata('prefixs', Example)).toEqual(['/example']); 9 | }); 10 | }); 11 | -------------------------------------------------------------------------------- /packages/framework/__tests__/src/errors/handle-error.spec.ts: -------------------------------------------------------------------------------- 1 | import { ErrorHandler } from '../../../src/errors/handle'; 2 | import { HttpError } from '../../../src/errors/http-error'; 3 | import { Application } from '../../../src'; 4 | import * as path from 'path'; 5 | 6 | const app = new Application({ 7 | rootPath: path.resolve(__dirname, '../../daze/src') 8 | }); 9 | 10 | beforeAll(() => app.initialize()); 11 | 12 | describe('handle error', () => { 13 | it('report shoud do nothing with http-error', () => { 14 | const fn = jest.fn(); 15 | const handler = new ErrorHandler(new HttpError()); 16 | app.on('error', fn); 17 | handler.report(); 18 | expect(fn).not.toBeCalled(); 19 | }); 20 | 21 | it ('report should emit app error with other error', () => { 22 | const fn = jest.fn(); 23 | const handler = new ErrorHandler(new Error()); 24 | app.on('error', fn); 25 | handler.report(); 26 | expect(fn).toBeCalled(); 27 | }); 28 | }); -------------------------------------------------------------------------------- /packages/framework/__tests__/src/errors/http-error.spec.ts: -------------------------------------------------------------------------------- 1 | import { HttpError } from '../../../src/errors/http-error'; 2 | 3 | describe('src/errors/http-error', () => { 4 | it('http-error', () => { 5 | const err = new HttpError(500, 'error'); 6 | expect(err).toBeInstanceOf(Error); 7 | expect(err.code).toBe(500); 8 | }); 9 | }); 10 | -------------------------------------------------------------------------------- /packages/framework/__tests__/src/errors/illegal-argument-error.spec.ts: -------------------------------------------------------------------------------- 1 | import { IllegalArgumentError } from '../../../src/errors/illegal-argument-error'; 2 | 3 | describe('src/errors/illegal-argument-error', () => { 4 | it('illegal-argument-error', () => { 5 | const err = new IllegalArgumentError('error'); 6 | expect(err).toBeInstanceOf(Error); 7 | expect(err.message).toBe('error'); 8 | }); 9 | 10 | it('should return default message error: Illegal Argument', () => { 11 | const err = new IllegalArgumentError(); 12 | expect(err.message).toBe('Illegal Argument'); 13 | }); 14 | }); 15 | -------------------------------------------------------------------------------- /packages/framework/__tests__/src/errors/not-found-http-error.spec.ts: -------------------------------------------------------------------------------- 1 | import { HttpError } from '../../../src/errors/http-error'; 2 | import { NotFoundHttpError } from '../../../src/errors/not-found-http-error'; 3 | 4 | describe('src/errors/not-found-http-error', () => { 5 | it('not-found-http-error', () => { 6 | const err = new NotFoundHttpError('error'); 7 | expect(err).toBeInstanceOf(HttpError); 8 | expect(err.code).toBe(404); 9 | expect(err.message).toBe('error'); 10 | }); 11 | 12 | it('should return default message error: Not Found', () => { 13 | const err = new NotFoundHttpError(); 14 | expect(err.message).toBe('Not Found'); 15 | }); 16 | }); 17 | -------------------------------------------------------------------------------- /packages/framework/__tests__/src/errors/validate-http-error.spec.ts: -------------------------------------------------------------------------------- 1 | import { HttpError } from '../../../src/errors/http-error'; 2 | import { ValidateHttpError } from '../../../src/errors/validate-http-error'; 3 | import { Validate } from '../../../src/validate'; 4 | 5 | describe('src/errors/validate-error', () => { 6 | it('validate-error', () => { 7 | const err = new ValidateHttpError('error', new Validate()); 8 | expect(err).toBeInstanceOf(HttpError); 9 | expect(err.code).toBe(422); 10 | }); 11 | }); 12 | -------------------------------------------------------------------------------- /packages/framework/__tests__/src/foundation/middlewares/cross.spec.ts: -------------------------------------------------------------------------------- 1 | import path from 'path'; 2 | import request from 'supertest'; 3 | import { Application } from '../../../../src'; 4 | 5 | const app = new Application({ 6 | rootPath: path.resolve(__dirname, '../../../daze/src') 7 | }); 8 | 9 | beforeAll(() => app.run()); 10 | afterAll(() => app.close()); 11 | 12 | describe('cross origin', () => { 13 | it('should add options route with cross origin', async () => { 14 | await request((app as any)._server) 15 | .options('/cross') 16 | .expect(200); 17 | }); 18 | 19 | it('should return 204 code when Preflight Request', async () => { 20 | await request((app as any)._server) 21 | .options('/cross') 22 | .set('Access-Control-Request-Method', 'Get') 23 | .set('Origin', 'http://localhost:8888/') 24 | .expect(204); 25 | }); 26 | }); 27 | -------------------------------------------------------------------------------- /packages/framework/__tests__/src/foundation/middlewares/csrf.spec.ts: -------------------------------------------------------------------------------- 1 | 2 | import path from 'path'; 3 | import request from 'supertest'; 4 | import { Application } from '../../../../src'; 5 | 6 | const app = new Application({ 7 | rootPath: path.resolve(__dirname, '../../../daze/src') 8 | }); 9 | 10 | beforeAll(() => app.run()); 11 | afterAll(() => app.close()); 12 | 13 | describe('csrf token', () => { 14 | it('should return 403 code without token', async () => { 15 | await request((app as any)._server) 16 | .post('/csrf') 17 | .expect(403); 18 | }); 19 | 20 | it('do not verify with read verb [get, head, options]', async () => { 21 | await request((app as any)._server) 22 | .get('/csrf/get') 23 | .expect(200); 24 | }); 25 | }); 26 | -------------------------------------------------------------------------------- /packages/framework/__tests__/src/loader/index.spec.ts: -------------------------------------------------------------------------------- 1 | import 'reflect-metadata'; 2 | import { 3 | Loader, 4 | BaseValidator, 5 | Controller, 6 | Component, 7 | Service, Resourcer, Middleware, Validator 8 | } from '../../../src'; 9 | 10 | describe('Loader', () => { 11 | it('should parse module each type', () => { 12 | const loader = new Loader(); 13 | 14 | @Controller() 15 | class ExampleController { } 16 | 17 | @Service('example') 18 | class ExampleService{ } 19 | 20 | @Resourcer('example') 21 | class ExampleResource { 22 | resolve(data: any) { 23 | return data; 24 | } 25 | } 26 | 27 | @Validator('example') 28 | class ExampleValidator extends BaseValidator { } 29 | 30 | @Middleware('example') 31 | class ExampleMiddleware { 32 | resolve(_request: any, next: any) { 33 | return next(); 34 | } 35 | } 36 | 37 | @Component('example') 38 | class ExampleComponent { } 39 | 40 | loader.load(ExampleController, ''); 41 | loader.load(ExampleService, ''); 42 | loader.load(ExampleResource, ''); 43 | loader.load(ExampleMiddleware, ''); 44 | loader.load(ExampleValidator, ''); 45 | loader.load(ExampleComponent, ''); 46 | 47 | expect(loader.loadedComponents.get('controller')?.map(t => t.target)?.includes(ExampleController)).toBeTruthy(); 48 | expect(loader.loadedComponents.get('middleware')?.map(t => t.target)?.includes(ExampleMiddleware)).toBeTruthy(); 49 | expect(loader.loadedComponents.get('service')?.map(t => t.target)?.includes(ExampleService)).toBeTruthy(); 50 | expect(loader.loadedComponents.get('resource')?.map(t => t.target)?.includes(ExampleResource)).toBeTruthy(); 51 | expect(loader.loadedComponents.get('validator')?.map(t => t.target)?.includes(ExampleValidator)).toBeTruthy(); 52 | expect(loader.loadedComponents.get('component')?.map(t => t.target)?.includes(ExampleComponent)).toBeTruthy(); 53 | }); 54 | }); 55 | -------------------------------------------------------------------------------- /packages/framework/__tests__/src/logger/index.spec.ts: -------------------------------------------------------------------------------- 1 | import 'reflect-metadata'; 2 | import path from 'path'; 3 | import { Logger, Application } from '../../../src'; 4 | import { IllegalArgumentError } from '../../../src/errors/illegal-argument-error'; 5 | 6 | const app = new Application({ 7 | rootPath: path.resolve(__dirname, '../../daze/src') 8 | }); 9 | 10 | beforeAll(() => app.initialize()); 11 | 12 | const log = new Logger(app); 13 | describe('src/logger', () => { 14 | it('Logger#isDefaultDriverSupported', () => { 15 | expect(log.isDefaultDriverSupported('console')).toBeTruthy(); 16 | expect(log.isDefaultDriverSupported('file')).toBeTruthy(); 17 | expect(log.isDefaultDriverSupported('http')).toBeTruthy(); 18 | expect(log.isDefaultDriverSupported('stream')).toBeTruthy(); 19 | // expect(log.isDefaultDriverSupported('mongodb')).toBeTruthy(); 20 | expect(log.isDefaultDriverSupported('dailyFile')).toBeTruthy(); 21 | expect(log.isDefaultDriverSupported('custom')).toBeFalsy(); 22 | }); 23 | 24 | it('Logger#channl', () => { 25 | expect((log.channel('console'))).toBe(log.getContainer().get('console')); 26 | expect(log.channel('dailyFile')).toBe(log.getContainer().get('dailyFile')); 27 | expect(log.channel('file')).toBe(log.getContainer().get('file')); 28 | expect(log.channel('http')).toBe(log.getContainer().get('http')); 29 | expect(log.channel('stream')).toBe(log.getContainer().get('stream')); 30 | expect(log.channel('compose')).toEqual(log.getContainer().get('compose')); 31 | }); 32 | 33 | it('Logger#getTransports error', () => { 34 | expect(() => { 35 | log.getTransports('console2'); 36 | }).toThrowError(IllegalArgumentError); 37 | expect(() => { 38 | log.getTransports('console3'); 39 | }).toThrowError(IllegalArgumentError); 40 | }); 41 | }); 42 | -------------------------------------------------------------------------------- /packages/framework/__tests__/src/pipeline/index.spec.ts: -------------------------------------------------------------------------------- 1 | import { Pipeline } from '../../../src/pipeline'; 2 | 3 | 4 | describe('Pipeline', () => { 5 | describe('Pipeline#pipe', () => { 6 | it('should add stage to pipeline stages', () => { 7 | const pipeline = new Pipeline(); 8 | const piper = (num: number) => num + 1; 9 | pipeline.pipe(piper); 10 | expect(pipeline.stages[0]).toBe(piper); 11 | }); 12 | }); 13 | 14 | describe('Pipeline#send', () => { 15 | it('should set payloads array', () => { 16 | const pipeline = new Pipeline(); 17 | pipeline.send(1); 18 | expect(pipeline.payload).toEqual([1]); 19 | }); 20 | it('should set payloads array when muilt params', () => { 21 | const pipeline = new Pipeline(); 22 | pipeline.send(1, 2, 3); 23 | expect(pipeline.payload).toEqual([1, 2, 3]); 24 | }); 25 | }); 26 | 27 | describe('Pipeline#process', () => { 28 | it('should return stages apply result', async () => { 29 | const pipeline = new Pipeline(); 30 | pipeline.pipe((target: any, next: any) => { 31 | target.a = 1; 32 | return next(); 33 | }); 34 | pipeline.pipe((target: any, next: any) => { 35 | target.b = 1; 36 | return next(); 37 | }); 38 | pipeline.pipe((target: any, next: any) => { 39 | target.c = 1; 40 | return next(); 41 | }); 42 | pipeline.send({}); 43 | expect(await pipeline.process((target: any) => target)).toEqual({ 44 | a: 1, 45 | b: 1, 46 | c: 1, 47 | }); 48 | }); 49 | 50 | it('should return process apply result whithout stages', async () => { 51 | const pipeline = new Pipeline(); 52 | pipeline.send({}); 53 | expect(await pipeline.process((target: any) => target)).toEqual({}); 54 | }); 55 | }); 56 | }); 57 | -------------------------------------------------------------------------------- /packages/framework/__tests__/src/resource/app/test.controller.ts: -------------------------------------------------------------------------------- 1 | import { Controller, Get } from '../../../../src'; 2 | import { TestResource } from './test.resource'; 3 | import { WrapResource } from './wrap.resource'; 4 | 5 | @Controller('/resource') 6 | export class TestController { 7 | @Get('/item') 8 | itemAction() { 9 | return TestResource.item({ 10 | name: 'dazejs' 11 | }); 12 | } 13 | 14 | @Get('/collection') 15 | collectionAction() { 16 | return TestResource.collection([ 17 | { 18 | name: 'dazejs' 19 | }, 20 | { 21 | name: 'dazejs' 22 | } 23 | ]); 24 | } 25 | 26 | 27 | @Get('/wrap') 28 | wrapAction() { 29 | return new WrapResource().item({ 30 | name: 'dazejs', 31 | wrap: { 32 | key: 'daze', 33 | } 34 | }); 35 | } 36 | } -------------------------------------------------------------------------------- /packages/framework/__tests__/src/resource/app/test.resource.ts: -------------------------------------------------------------------------------- 1 | import { Resourcer, BaseResource, ResourceInterface } from '../../../../src'; 2 | 3 | 4 | @Resourcer() 5 | export class TestResource extends BaseResource implements ResourceInterface { 6 | resolve(data: any) { 7 | return { 8 | ...data, 9 | type: 'node', 10 | }; 11 | } 12 | } -------------------------------------------------------------------------------- /packages/framework/__tests__/src/resource/app/wrap.resource.ts: -------------------------------------------------------------------------------- 1 | import { Resourcer, BaseResource, ResourceInterface } from '../../../../src'; 2 | import { TestResource } from './test.resource'; 3 | 4 | @Resourcer() 5 | export class WrapResource extends BaseResource implements ResourceInterface { 6 | resolve(data: any) { 7 | return { 8 | ...data, 9 | wrap: TestResource.item(data.wrap) 10 | }; 11 | } 12 | } -------------------------------------------------------------------------------- /packages/framework/__tests__/src/response/redirect.spec.ts: -------------------------------------------------------------------------------- 1 | import path from 'path'; 2 | import request from 'supertest'; 3 | import { Application } from '../../../src'; 4 | 5 | const app = new Application({ 6 | rootPath: path.resolve(__dirname, '../../daze/src') 7 | }); 8 | 9 | beforeAll(() => app.run()); 10 | afterAll(() => app.close()); 11 | 12 | describe('redirect feature', () => { 13 | it('should return 302 code default', async () => { 14 | await request((app as any)._server) 15 | .get('/redirect') 16 | .expect(302) 17 | .expect('Location', 'https://www.google.com'); 18 | }); 19 | }); 20 | -------------------------------------------------------------------------------- /packages/framework/__tests__/src/router/routes.spec.ts: -------------------------------------------------------------------------------- 1 | import path from 'path'; 2 | import request from 'supertest'; 3 | import { Application } from '../../../src'; 4 | 5 | const app = new Application({ 6 | rootPath: path.resolve(__dirname, '../../daze/src') 7 | }); 8 | 9 | beforeAll(() => app.run()); 10 | afterAll(() => app.close()); 11 | 12 | describe('routes', () => { 13 | it('should return 200 code and all1', async () => { 14 | await request((app as any)._server) 15 | .get('/routes/all1') 16 | .expect(200, 'all1'); 17 | }); 18 | 19 | it('should return 200 code and all2', async () => { 20 | await request((app as any)._server) 21 | .get('/routes/all2') 22 | .expect(200, 'all2'); 23 | }); 24 | }); 25 | -------------------------------------------------------------------------------- /packages/framework/__tests__/src/session/helper.spec.ts: -------------------------------------------------------------------------------- 1 | 2 | 3 | import { isBase64 } from '../../../src/validate/validators'; 4 | import { Str } from '../../../src/utils/'; 5 | 6 | describe('Session#helper', () => { 7 | it('should encode base64 with object by encode', () => { 8 | const code = Str.encodeBASE64({ a: 'aaa' }); 9 | expect(isBase64(code)).toBeTruthy(); 10 | }); 11 | 12 | it('should decode base64 to object by decode', () => { 13 | const body = Str.decodeBASE64('eyJhIjoiYWFhIn0='); 14 | expect(body).toEqual({ 15 | a: 'aaa', 16 | }); 17 | }); 18 | }); 19 | -------------------------------------------------------------------------------- /packages/framework/__tests__/src/validate/app/test.controller.ts: -------------------------------------------------------------------------------- 1 | import { Controller, response, Request, Get } from '../../../../src'; 2 | import { TestValidator } from './test.validator'; 3 | 4 | @Controller('/validate') 5 | export class TestController { 6 | @Get('/test1') 7 | test1(request: Request) { 8 | request.validate(TestValidator); 9 | return 'hello dazejs'; 10 | } 11 | 12 | @Get('/test3') 13 | test3(request: Request) { 14 | if (!TestValidator.check(request.getParams())) { 15 | return response().badRequest(); 16 | } 17 | return 'hello dazejs'; 18 | } 19 | 20 | @Get('/test4') 21 | test4(request: Request) { 22 | try { 23 | request.validate(TestValidator); 24 | } catch (err) { 25 | return response().badRequest(); 26 | } 27 | return 'hello dazejs'; 28 | } 29 | 30 | @Get('/test5') 31 | test5(request: Request) { 32 | const validate = new TestValidator().make(request.getParams()); 33 | if (validate.fails) { 34 | return response().badRequest(); 35 | } 36 | return 'hello dazejs'; 37 | } 38 | } -------------------------------------------------------------------------------- /packages/framework/__tests__/src/validate/app/test.validator.ts: -------------------------------------------------------------------------------- 1 | import { Validator, BaseValidator, IsEmail } from '../../../../src'; 2 | 3 | @Validator() 4 | export class TestValidator extends BaseValidator { 5 | @IsEmail() 6 | username: string; 7 | } -------------------------------------------------------------------------------- /packages/framework/__tests__/src/validate/feature.spec.ts: -------------------------------------------------------------------------------- 1 | import * as path from 'path'; 2 | import request from 'supertest'; 3 | import { Application } from '../../../src'; 4 | 5 | const app = new Application({ 6 | rootPath: path.resolve(__dirname, './') 7 | }); 8 | 9 | beforeAll(() => app.run(7777)); 10 | afterAll(() => app.close()); 11 | 12 | describe('Validate Feature', () => { 13 | it('should success when request legal', async () => { 14 | await request((app as any)._server) 15 | .get('/validate/test1?username=test@example.com') 16 | .expect(200); 17 | }); 18 | 19 | it('should success when request ilegal', async () => { 20 | await request((app as any)._server) 21 | .get('/validate/test1?username=ilegal') 22 | .expect(422); 23 | }); 24 | 25 | it('should success when request legal (check)', async () => { 26 | await request((app as any)._server) 27 | .get('/validate/test3?username=test@example.com') 28 | .expect(200); 29 | }); 30 | 31 | it('should success when request ilegal (check)', async () => { 32 | await request((app as any)._server) 33 | .get('/validate/test3?username=ilegal') 34 | .expect(400); 35 | }); 36 | 37 | it('should success when request legal (custom)', async () => { 38 | await request((app as any)._server) 39 | .get('/validate/test4?username=test@example.com') 40 | .expect(200); 41 | }); 42 | 43 | it('should success when request ilegal (custom)', async () => { 44 | await request((app as any)._server) 45 | .get('/validate/test4?username=ilegal') 46 | .expect(400); 47 | }); 48 | 49 | it('should success when request legal (make)', async () => { 50 | await request((app as any)._server) 51 | .get('/validate/test5?username=test@example.com') 52 | .expect(200); 53 | }); 54 | 55 | it('should success when request ilegal (make)', async () => { 56 | await request((app as any)._server) 57 | .get('/validate/test5?username=ilegal') 58 | .expect(400); 59 | }); 60 | }); 61 | -------------------------------------------------------------------------------- /packages/framework/__tests__/src/view/index.spec.ts: -------------------------------------------------------------------------------- 1 | import 'reflect-metadata'; 2 | import path from 'path'; 3 | import { Application, View } from '../../../src'; 4 | 5 | const app = new Application({ 6 | rootPath: path.resolve(__dirname, '../../daze/src') 7 | }); 8 | 9 | beforeAll(() => app.initialize()); 10 | 11 | describe('View', () => { 12 | it('View#assign', () => { 13 | const view = new View(); 14 | view.assign('color', 'blue'); 15 | view.assign({ 16 | name: 'color', 17 | }); 18 | expect(view.getVars()).toEqual({ 19 | color: 'blue', 20 | name: 'color', 21 | }); 22 | }); 23 | 24 | it('View#render with ext name', () => { 25 | const view = new View(); 26 | view.render('index.html', { 27 | color: 'blue', 28 | }); 29 | expect(view.getTemplate()).toBe('index.html'); 30 | expect(view.getVars()).toEqual({ 31 | color: 'blue', 32 | }); 33 | }); 34 | 35 | it('View#render without ext name', () => { 36 | const view = new View(); 37 | view.render('index', { 38 | color: 'blue', 39 | }); 40 | expect(view.getTemplate()).toBe('index.html'); 41 | expect(view.getVars()).toEqual({ 42 | color: 'blue', 43 | }); 44 | }); 45 | 46 | it('View#render without template ', () => { 47 | const view = new View('index'); 48 | view.render({ 49 | color: 'blue', 50 | }); 51 | expect(view.getTemplate()).toBe('index.html'); 52 | expect(view.getVars()).toEqual({ 53 | color: 'blue', 54 | }); 55 | }); 56 | 57 | it('View#render without template and vars', () => { 58 | const view = new View('index', { 59 | color: 'blue', 60 | }); 61 | view.render(); 62 | expect(view.getTemplate()).toBe('index.html'); 63 | expect(view.getVars()).toEqual({ 64 | color: 'blue', 65 | }); 66 | }); 67 | }); 68 | -------------------------------------------------------------------------------- /packages/framework/src/base/entity.ts: -------------------------------------------------------------------------------- 1 | import { ComponentType } from '../decorators/component-type'; 2 | import { Model } from '../supports/orm/model'; 3 | import { Repository } from '../supports/orm/repository'; 4 | import { ModelBuilder } from '../supports/orm/builder'; 5 | import { Builder } from '../supports/database/builder'; 6 | 7 | @ComponentType('entity') 8 | @Reflect.metadata('connection', 'default') 9 | export class BaseEntity { 10 | /** 11 | * 根据主键获取单挑记录 12 | * @param id 13 | */ 14 | async get(id: number | string): Promise & this> { 15 | return (new Model(this.constructor as any)).createRepository().get(id) as any; 16 | } 17 | 18 | /** 19 | * 创建模型的查询构建器 20 | */ 21 | createQueryBuilder(): ModelBuilder & Builder { 22 | return (new Model(this.constructor as any)).createRepository().createQueryBuilder() as any; 23 | } 24 | 25 | /** 26 | * 关联预加载 27 | * @param relations 28 | */ 29 | with(relation: string, callback?: (query: Builder) => void): Repository & this { 30 | return (new Model(this.constructor as any)).createRepository().with(relation, callback) as any; 31 | } 32 | 33 | /** 34 | * 自动保存/新建记录 35 | */ 36 | async save() { 37 | const repos = (new Model(this.constructor as any)).createRepository(); 38 | repos.fill(this); 39 | await repos.save(); 40 | Object.assign(this, repos.getAttributes()); 41 | return repos; 42 | } 43 | 44 | /** 45 | * 创建记录 46 | * @param attributes 47 | */ 48 | async create(attributes: Record): Promise & this> { 49 | const repos = (new Model(this.constructor as any)).createRepository(); 50 | return repos.create(attributes) as any; 51 | } 52 | 53 | /** 54 | * 根据主键 id 删除记录 55 | * @param ids 56 | */ 57 | async destroy(...ids: (number | string)[]) { 58 | const repos = (new Model(this.constructor as any)).createRepository(); 59 | return repos.destroy(...ids); 60 | } 61 | } -------------------------------------------------------------------------------- /packages/framework/src/base/index.ts: -------------------------------------------------------------------------------- 1 | export { BaseEntity } from './entity'; 2 | export { BasePivotEntity } from './pivot-entity'; 3 | export * from './validator'; 4 | export * from './resource'; -------------------------------------------------------------------------------- /packages/framework/src/base/pivot-entity.ts: -------------------------------------------------------------------------------- 1 | import { BaseEntity } from './entity'; 2 | 3 | export class BasePivotEntity extends BaseEntity { 4 | // 5 | } 6 | -------------------------------------------------------------------------------- /packages/framework/src/base/resource.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2019 zewail 3 | * 4 | * This software is released under the MIT License. 5 | * https://opensource.org/licenses/MIT 6 | */ 7 | import { Resource } from '../resource'; 8 | import { ComponentType } from '../decorators/component-type'; 9 | 10 | @ComponentType('resource') 11 | export abstract class BaseResource { 12 | 13 | collection(data: any): Resource { 14 | return new Resource(this.constructor as any).collection(data); 15 | } 16 | 17 | item(data: any): Resource { 18 | return new Resource(this.constructor as any).item(data); 19 | } 20 | 21 | static collection(data: any): Resource { 22 | return new Resource(this as any).collection(data); 23 | } 24 | 25 | static item(data: any): Resource { 26 | return new Resource(this as any).item(data); 27 | } 28 | } 29 | 30 | -------------------------------------------------------------------------------- /packages/framework/src/base/validator.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2019 zewail 3 | * 4 | * This software is released under the MIT License. 5 | * https://opensource.org/licenses/MIT 6 | */ 7 | import { ComponentType } from '../decorators/component-type'; 8 | import { Validate } from '../validate'; 9 | 10 | @ComponentType('validator') 11 | export abstract class BaseValidator { 12 | check(data: Record) { 13 | return new Validate(this.constructor as any).check(data); 14 | } 15 | 16 | make(data: Record) { 17 | return new Validate(this.constructor as any).make(data); 18 | } 19 | 20 | static check(data: Record) { 21 | return new Validate(this).check(data); 22 | } 23 | 24 | static make(data: Record) { 25 | return new Validate(this).make(data); 26 | } 27 | 28 | } 29 | 30 | -------------------------------------------------------------------------------- /packages/framework/src/cluster/const.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2018 Chan Zewail 3 | * 4 | * This software is released under the MIT License. 5 | * https://opensource.org/licenses/MIT 6 | */ 7 | 8 | // The main process receives an interrupt signal to restart the working process 9 | // 主进程接收中断信号来重启工作进程 10 | export const RELOAD_SIGNAL = 'SIGUSR2'; 11 | 12 | // Whether the work process has been restarted 13 | // 工作进程是否已进行重启 14 | export const WORKER_DYING = 'daze-worker-dying'; 15 | 16 | // After the main process reforks the worker process, 17 | // it notifies the corresponding worker process to terminate the service 18 | // 主进程重新 fork 工作进程后通知对应工作进程让其结束服务的信号 19 | export const WORKER_DID_FORKED = 'daze-worker-did-fork'; 20 | 21 | // Signal that the work process is about to stop providing service to the main process 22 | // 工作进程即将停止提供服务通知主进程的信号 23 | export const WORKER_DISCONNECT = 'daze-worker-disconnect'; 24 | 25 | // sticky sessions for websocket communication 26 | export const STIKCY_CONNECTION = 'daze-sticky-connection'; 27 | 28 | // 框架进程类型 29 | export const DAZE_PROCESS_TYPE = 'daze:process:type'; 30 | -------------------------------------------------------------------------------- /packages/framework/src/cluster/helpers.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2018 Chan Zewail 3 | * 4 | * This software is released under the MIT License. 5 | * https://opensource.org/licenses/MIT 6 | */ 7 | import cluster, { Worker } from 'cluster'; 8 | import os from 'os'; 9 | 10 | import { WORKER_DYING } from './const'; 11 | import { MasterOptions } from './master'; 12 | 13 | const cpus = os.cpus().length; 14 | 15 | /** 16 | * Analyze the parameters of Cluster module 17 | * Adds the number of work processes to the parameters 18 | * 解析 Cluster 模块的参数 19 | * 添加工作进程数量数量到参数中 20 | */ 21 | export function parseMasterOpts(opts: MasterOptions) { 22 | opts.workers = opts.workers || cpus; 23 | return opts; 24 | } 25 | 26 | 27 | /** 28 | * Determine if the work process is alive 29 | * 判断工作进程是否存活状态 30 | */ 31 | export function isAliveWorker(worker: Worker) { 32 | if (!worker.isConnected() || worker.isDead()) return false; 33 | if (Reflect.getMetadata(WORKER_DYING, worker)) return false; 34 | return true; 35 | } 36 | 37 | /** 38 | * Capture the surviving work process 39 | * Return an array 40 | * 获取存活的工作进程 41 | * 返回一个数组 42 | */ 43 | export function getAlivedWorkers(): Worker[] { 44 | const workers: Worker[] = []; 45 | for (const id in cluster.workers) { 46 | if (Object.prototype.hasOwnProperty.call(cluster.workers, id)) { 47 | const worker: any = cluster.workers[id]; 48 | if (isAliveWorker(worker)) { 49 | workers.push(worker); 50 | } 51 | } 52 | } 53 | return workers; 54 | } 55 | 56 | -------------------------------------------------------------------------------- /packages/framework/src/cluster/index.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2018 Chan Zewail 3 | * 4 | * This software is released under the MIT License. 5 | * https://opensource.org/licenses/MIT 6 | */ 7 | 8 | export * from './master'; 9 | export * from './worker'; 10 | -------------------------------------------------------------------------------- /packages/framework/src/config/index.ts: -------------------------------------------------------------------------------- 1 | export * from './config'; 2 | -------------------------------------------------------------------------------- /packages/framework/src/controller/controller-service.ts: -------------------------------------------------------------------------------- 1 | import { Application } from '../foundation/application'; 2 | import { UseMiddlewareOption } from '../decorators/use/interface'; 3 | import { Router } from '../http/router'; 4 | 5 | /** 6 | * 控制器解析类 7 | */ 8 | export class ControllerService { 9 | /** 10 | * 应用实例 11 | */ 12 | public app: Application; 13 | 14 | /** 15 | * 控制器解析类构造函数 16 | * @param app 17 | */ 18 | constructor(app: Application) { 19 | this.app = app; 20 | } 21 | 22 | /** 23 | * 注册一个控制器 24 | */ 25 | public register(controller: any) { 26 | if (Reflect.getMetadata('type', controller) !== 'controller') return this; 27 | this.resolve(controller); 28 | return this; 29 | } 30 | 31 | /** 32 | * 解析控制器 33 | */ 34 | public resolve(controller: any) { 35 | const routes = Reflect.getMetadata('routes', controller) || {}; 36 | const prefixs = Reflect.getMetadata('prefixs', controller) || ['']; 37 | for (const prefix of prefixs) { 38 | this.registerRoutes(controller, routes, prefix); 39 | } 40 | } 41 | 42 | /** 43 | * 注册控制器路由 44 | */ 45 | private registerRoutes(controller: any, routes: any, prefix = '') { 46 | const router = this.app.get('router'); 47 | const controllerMiddlewareOptions: UseMiddlewareOption[] = Reflect.getMetadata('use-middlewares', controller) ?? []; 48 | for (const key of Object.keys(routes)) { 49 | const routeMiddlewares: { [key: string]: UseMiddlewareOption[] } = Reflect.getMetadata('use-middlewares', controller, key) ?? {}; 50 | for (const route of routes[key]) { 51 | const { uri, method, option } = route; 52 | const actionMiddlewareOptions = routeMiddlewares[key] ?? []; 53 | router.register(`${prefix}${uri}`, [method], option, controller, key, [...controllerMiddlewareOptions, ...actionMiddlewareOptions]); 54 | } 55 | } 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /packages/framework/src/controller/index.ts: -------------------------------------------------------------------------------- 1 | export * from './controller-service'; -------------------------------------------------------------------------------- /packages/framework/src/decorators/autowired.ts: -------------------------------------------------------------------------------- 1 | 2 | import { PROPERTYTYPE_METADATA } from '../symbol'; 3 | 4 | export const Autowired: PropertyDecorator = function (target, propertyKey) { 5 | const type = Reflect.getMetadata('design:type', target, propertyKey); 6 | Reflect.defineMetadata(PROPERTYTYPE_METADATA, type, target.constructor, propertyKey); 7 | }; 8 | -------------------------------------------------------------------------------- /packages/framework/src/decorators/component-type.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2020 Chan Zewail 3 | * 4 | * This software is released under the MIT License. 5 | * https://opensource.org/licenses/MIT 6 | */ 7 | 8 | /** 9 | * set type for component 10 | * @param type 11 | */ 12 | export const ComponentType = function (type: any): ClassDecorator { 13 | return function (constructor) { 14 | Reflect.defineMetadata('type', type, constructor); 15 | return constructor; 16 | }; 17 | }; -------------------------------------------------------------------------------- /packages/framework/src/decorators/create-decorator.ts: -------------------------------------------------------------------------------- 1 | import { decoratorFactory } from './factory/decorator-factory'; 2 | 3 | export const createCustomDecorator = 4 | (abstract: any, params: any[] = [], handler?: (injectedParam: any) => any) => 5 | decoratorFactory(abstract, params, handler); -------------------------------------------------------------------------------- /packages/framework/src/decorators/cross-origin.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2020 Chan Zewail 3 | * 4 | * This software is released under the MIT License. 5 | * https: //opensource.org/licenses/MIT 6 | */ 7 | 8 | export const CrossOrigin = function (options: any = {}) { 9 | return function (...args: any[]) { 10 | // class decorator 11 | if (args.length === 1) { 12 | const [target] = args; 13 | Reflect.defineMetadata('controllerCrossOrigin', { 14 | ...options, 15 | }, target); 16 | } 17 | // method decorator 18 | else { 19 | const [target, name] = args; 20 | const corses = Reflect.getMetadata('routeCrossOrigin', target.constructor) || {}; 21 | corses[name] = { 22 | ...options, 23 | }; 24 | Reflect.defineMetadata('routeCrossOrigin', corses, target.constructor); 25 | } 26 | }; 27 | }; 28 | -------------------------------------------------------------------------------- /packages/framework/src/decorators/csrf.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2020 Chan Zewail 3 | * 4 | * This software is released under the MIT License. 5 | * https: //opensource.org/licenses/MIT 6 | */ 7 | 8 | import { UseMiddleware } from './use/use-middleware'; 9 | import { VerifyCsrfToken } from '../foundation/buildin-app/middlewares/verify-csrf-token'; 10 | 11 | export const CSRF = function () { 12 | return UseMiddleware(VerifyCsrfToken); 13 | }; 14 | export const Csrf = CSRF; 15 | -------------------------------------------------------------------------------- /packages/framework/src/decorators/disbale.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2020 Chan Zewail 3 | * 4 | * This software is released under the MIT License. 5 | * https: //opensource.org/licenses/MIT 6 | */ 7 | import { DISABLE_INJECT } from '../symbol'; 8 | 9 | export const Disable = (target: any, propertyKey?: string | symbol) => { 10 | if (!propertyKey) { // Class 11 | Reflect.defineMetadata(DISABLE_INJECT, true, target); 12 | } else { 13 | Reflect.defineMetadata(DISABLE_INJECT, true, target.constructor, propertyKey); 14 | } 15 | }; 16 | 17 | -------------------------------------------------------------------------------- /packages/framework/src/decorators/encrypt.ts: -------------------------------------------------------------------------------- 1 | 2 | 3 | export const EncryptResponse: MethodDecorator | ClassDecorator = function (...args: any[]) { 4 | // decorator class 5 | if (args.length === 1) { 6 | const [target] = args; 7 | Reflect.defineMetadata('encrypt', true, target); 8 | } 9 | // decorator method 10 | else { 11 | const [target, name] = args; 12 | Reflect.defineMetadata('encrypt', true, target.constructor, name); 13 | } 14 | }; -------------------------------------------------------------------------------- /packages/framework/src/decorators/http-code.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2018 Chan Zewail 3 | * 4 | * This software is released under the MIT License. 5 | * https://opensource.org/licenses/MIT 6 | */ 7 | import { HTTP_CODE } from '../symbol'; 8 | 9 | export const HttpCode = function (code = 200): MethodDecorator { 10 | return function (target: Record, propertyKey: string | symbol) { 11 | target[propertyKey.toString()][HTTP_CODE] = code; 12 | }; 13 | }; 14 | -------------------------------------------------------------------------------- /packages/framework/src/decorators/ignore.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2020 Chan Zewail 3 | * 4 | * This software is released under the MIT License. 5 | * https: //opensource.org/licenses/MIT 6 | */ 7 | 8 | export const Ignore: ClassDecorator = function (constructor: any) { 9 | Reflect.defineMetadata('ignore', true, constructor); 10 | }; 11 | 12 | -------------------------------------------------------------------------------- /packages/framework/src/decorators/index.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2020 Chan Zewail 3 | * 4 | * This software is released under the MIT License. 5 | * https: //opensource.org/licenses/MIT 6 | */ 7 | 8 | // import * as httpContext from './contexts-http'; 9 | // import * as verbs from './verb'; 10 | 11 | export * from './stereotype'; 12 | export * from './disbale'; 13 | export * from './component-type'; 14 | export * from './cross-origin'; 15 | export * from './csrf'; 16 | export * from './http-code'; 17 | export * from './ignore'; 18 | export * from './inject'; 19 | export * from './autowired'; 20 | export * from './model'; 21 | export * from './multiton'; 22 | export * from './order'; 23 | export * from './provider'; 24 | export * from './rest'; 25 | export * from './singleton'; 26 | export * from './use'; 27 | export * from './encrypt'; 28 | export * from './validates'; 29 | export * from './create-decorator'; 30 | // export const http = { 31 | // ...verbs, 32 | // ...httpContext 33 | // }; 34 | export * from './verb'; 35 | export * from './contexts-http'; 36 | export * from './schedule'; 37 | 38 | -------------------------------------------------------------------------------- /packages/framework/src/decorators/inject.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2020 Chan Zewail 3 | * 4 | * This software is released under the MIT License. 5 | * https: //opensource.org/licenses/MIT 6 | */ 7 | 8 | import { decoratorFactory } from './factory/decorator-factory'; 9 | 10 | /** 11 | * for javascript 12 | * Inject by custom name 13 | * Supports injection in a variety of ways, including but not limited to methods, properties, and constructors 14 | * 15 | * @param name 16 | * @param args 17 | */ 18 | export const Inject = function (name?: any, ...args: any[]) { 19 | return decoratorFactory(name, args); 20 | }; -------------------------------------------------------------------------------- /packages/framework/src/decorators/model/index.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2020 Chan Zewail 3 | * 4 | * This software is released under the MIT License. 5 | * https: //opensource.org/licenses/MIT 6 | */ 7 | 8 | export * from './column'; 9 | export * from './relation'; -------------------------------------------------------------------------------- /packages/framework/src/decorators/multiton.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2020 Chan Zewail 3 | * 4 | * This software is released under the MIT License. 5 | * https: //opensource.org/licenses/MIT 6 | */ 7 | 8 | import { MULTITON, SINGLETON } from '../symbol'; 9 | 10 | export const Multiton: ClassDecorator = function (target: any) { 11 | Reflect.defineMetadata(SINGLETON, false, target); 12 | Reflect.defineMetadata(MULTITON, true, target); 13 | }; 14 | 15 | -------------------------------------------------------------------------------- /packages/framework/src/decorators/order.ts: -------------------------------------------------------------------------------- 1 | import { ProviderType } from '../symbol'; 2 | 3 | /** 4 | * Organize the order in which components are executed by priority, such as the order in which Middleware is executed 5 | * 6 | * @param value Priority, the smaller the higher the priority 7 | */ 8 | export const Order = function (value: number = Number.MAX_SAFE_INTEGER): ClassDecorator { 9 | return function (target: any) { 10 | Reflect.defineMetadata(ProviderType.ORDER, value, target); 11 | }; 12 | }; 13 | 14 | export const Priority = Order; -------------------------------------------------------------------------------- /packages/framework/src/decorators/provider/index.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2020 Chan Zewail 3 | * 4 | * This software is released under the MIT License. 5 | * https: //opensource.org/licenses/MIT 6 | */ 7 | 8 | export * from './provider'; 9 | export * from './provide'; 10 | export * from './provide-on-config'; 11 | export * from './provide-on-missing'; 12 | export * from './provide-on'; 13 | -------------------------------------------------------------------------------- /packages/framework/src/decorators/provider/provide-on-config.ts: -------------------------------------------------------------------------------- 1 | /* eslint-disable @typescript-eslint/ban-types */ 2 | /** 3 | * Copyright (c) 2020 Chan Zewail 4 | * 5 | * This software is released under the MIT License. 6 | * https: //opensource.org/licenses/MIT 7 | */ 8 | 9 | import { ProviderType } from '../../symbol'; 10 | import { ProvideMetaData } from './provide'; 11 | 12 | /** 13 | * Provides the service when the specified configuration item exists 14 | * 15 | * @param key 16 | */ 17 | export const ProvideOnConfig = function (key: string): ClassDecorator | MethodDecorator | any { 18 | return function ( 19 | target: Function | object, 20 | name?: string | symbol | undefined, 21 | descriptor?: TypedPropertyDescriptor | undefined, 22 | ) { 23 | // Decorator on method 24 | if (!!name && !!descriptor) { 25 | const metaMap: Map = 26 | Reflect.getMetadata(ProviderType.PROVIDE, target.constructor) ?? new Map(); 27 | if (metaMap.has(name)) { 28 | const options = (metaMap.get(name) ?? {}) as ProvideMetaData; 29 | options.onConfigKey = key; 30 | metaMap.set(name, options); 31 | } else { 32 | metaMap.set(name, { onConfigKey: key }); 33 | } 34 | Reflect.defineMetadata(ProviderType.PROVIDE, metaMap, target.constructor); 35 | } 36 | // Decorator on class 37 | else { 38 | const metaMap: Map = 39 | Reflect.getMetadata(ProviderType.PROVIDE, target) ?? new Map(); 40 | if (metaMap.has(target)) { 41 | const options = (metaMap.get(target) ?? {}) as ProvideMetaData; 42 | options.onConfigKey = key; 43 | metaMap.set(target, options); 44 | } else { 45 | metaMap.set(target, { onConfigKey: key }); 46 | } 47 | Reflect.defineMetadata(ProviderType.PROVIDE, metaMap, target); 48 | } 49 | }; 50 | }; 51 | -------------------------------------------------------------------------------- /packages/framework/src/decorators/provider/provide-on-missing.ts: -------------------------------------------------------------------------------- 1 | /* eslint-disable @typescript-eslint/ban-types */ 2 | /** 3 | * Copyright (c) 2020 Chan Zewail 4 | * 5 | * This software is released under the MIT License. 6 | * https: //opensource.org/licenses/MIT 7 | */ 8 | 9 | import { ProviderType } from '../../symbol'; 10 | import { ProvideMetaData } from './provide'; 11 | 12 | /** 13 | * Provide a service when no specified service exists 14 | * 15 | * @param provider 16 | */ 17 | export const ProvideOnMissing = function (provider: string | Function): MethodDecorator { 18 | return function (target: object, name: string | symbol) { 19 | const metaMap: Map = 20 | Reflect.getMetadata(ProviderType.PROVIDE, target.constructor) ?? new Map(); 21 | if (metaMap.has(name)) { 22 | const options = (metaMap.get(name) ?? {}) as ProvideMetaData; 23 | options.onMissingProviderkey = provider; 24 | metaMap.set(name, options); 25 | } else { 26 | metaMap.set(name, { onMissingProviderkey: provider }); 27 | } 28 | Reflect.defineMetadata(ProviderType.PROVIDE, metaMap, target.constructor); 29 | }; 30 | }; 31 | -------------------------------------------------------------------------------- /packages/framework/src/decorators/provider/provide-on.ts: -------------------------------------------------------------------------------- 1 | /* eslint-disable @typescript-eslint/ban-types */ 2 | /** 3 | * Copyright (c) 2020 Chan Zewail 4 | * 5 | * This software is released under the MIT License. 6 | * https: //opensource.org/licenses/MIT 7 | */ 8 | 9 | import { ProviderType } from '../../symbol'; 10 | import { ProvideMetaData } from './provide'; 11 | 12 | /** 13 | * Provides a service when a specified service exists 14 | * 15 | * @param provider 16 | */ 17 | export const ProvideOn = function (provider: string | Function): MethodDecorator { 18 | return function (target: object, key: string | symbol) { 19 | const metaMap: Map = 20 | Reflect.getMetadata(ProviderType.PROVIDE, target.constructor) ?? new Map(); 21 | 22 | if (metaMap.has(key)) { 23 | const options = (metaMap.get(key) ?? {}) as ProvideMetaData; 24 | options.onProviderKey = provider; 25 | metaMap.set(key, options); 26 | } else { 27 | metaMap.set(key, { onProviderKey: provider }); 28 | } 29 | Reflect.defineMetadata(ProviderType.PROVIDE, metaMap, target.constructor); 30 | }; 31 | }; 32 | -------------------------------------------------------------------------------- /packages/framework/src/decorators/provider/provide.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2020 Chan Zewail 3 | * 4 | * This software is released under the MIT License. 5 | * https: //opensource.org/licenses/MIT 6 | */ 7 | 8 | import { ProviderType } from '../../symbol'; 9 | 10 | export interface ProvideMetaData { 11 | provideName?: any; 12 | isShared?: boolean; 13 | onMissingProviderkey?: any; 14 | onConfigKey?: string; 15 | onProviderKey?: any; 16 | } 17 | 18 | /** 19 | * To provide services 20 | * 21 | * @param name 22 | * @param isShared 23 | */ 24 | export const Provide = function (name?: any, isShared = true): MethodDecorator { 25 | return function (target: object, key: string | symbol) { 26 | const metaMap: Map = 27 | Reflect.getMetadata(ProviderType.PROVIDE, target.constructor) ?? new Map(); 28 | const _name = name ?? key.toString(); 29 | if (metaMap.has(key)) { 30 | const options = (metaMap.get(key) ?? {}) as ProvideMetaData; 31 | options.provideName = _name; 32 | options.isShared = isShared; 33 | metaMap.set(key, options); 34 | } else { 35 | metaMap.set(key, { provideName: _name, isShared }); 36 | } 37 | Reflect.defineMetadata(ProviderType.PROVIDE, metaMap, target.constructor); 38 | }; 39 | }; 40 | 41 | 42 | -------------------------------------------------------------------------------- /packages/framework/src/decorators/rest.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2018 Chan Zewail 3 | * 4 | * This software is released under the MIT License. 5 | * https://opensource.org/licenses/MIT 6 | */ 7 | import { Str } from '../utils'; 8 | import { INJECTABLE } from '../symbol'; 9 | 10 | const defaultRestRoutes = { 11 | index: [{ uri: '/', method: 'get' }], 12 | create: [{ uri: '/create', method: 'get' }], 13 | show: [{ uri: '/:id', method: 'get' }], 14 | store: [{ uri: '/', method: 'post' }], 15 | edit: [{ uri: '/:id/edit', method: 'get' }], 16 | update: [{ uri: '/:id', method: 'put' }], 17 | destroy: [{ uri: '/:id', method: 'delete' }], 18 | }; 19 | 20 | export const Rest = function (...prefixs: string[]): ClassDecorator { 21 | return function (constructor) { 22 | Reflect.defineMetadata(INJECTABLE, true, constructor); 23 | Reflect.defineMetadata('prefixs', prefixs?.map(prefix => Str.formatPrefix(prefix)) ?? ['/'], constructor); 24 | const routes = Reflect.getMetadata('routes', constructor); 25 | Reflect.defineMetadata('routes', { 26 | ...defaultRestRoutes, 27 | ...routes, 28 | }, constructor); 29 | }; 30 | }; 31 | -------------------------------------------------------------------------------- /packages/framework/src/decorators/schedule/index.ts: -------------------------------------------------------------------------------- 1 | 2 | import * as _ from './corntab'; 3 | 4 | export const Corntab = { 5 | ..._ 6 | }; -------------------------------------------------------------------------------- /packages/framework/src/decorators/singleton.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2018 Chan Zewail 3 | * 4 | * This software is released under the MIT License. 5 | * https://opensource.org/licenses/MIT 6 | */ 7 | import { MULTITON, SINGLETON } from '../symbol'; 8 | 9 | 10 | export const Singleton: ClassDecorator = function (target: any) { 11 | Reflect.defineMetadata(MULTITON, false, target); 12 | Reflect.defineMetadata(SINGLETON, true, target); 13 | }; 14 | 15 | 16 | -------------------------------------------------------------------------------- /packages/framework/src/decorators/stereotype/agent.ts: -------------------------------------------------------------------------------- 1 | import { Component } from './component'; 2 | 3 | export const agent = function (name?: string): ClassDecorator { 4 | return function (constructor) { 5 | Component(name, 'agent')(constructor); 6 | }; 7 | }; 8 | 9 | export const Agent = agent; -------------------------------------------------------------------------------- /packages/framework/src/decorators/stereotype/component.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2020 Chan Zewail 3 | * 4 | * This software is released under the MIT License. 5 | * https: //opensource.org/licenses/MIT 6 | */ 7 | 8 | import { Injectable } from './injectable'; 9 | 10 | /** 11 | * component metadata 12 | * @param name 13 | * @param type 14 | */ 15 | export const Component = function (name?: string, type = 'component'): ClassDecorator { 16 | return function (constructor) { 17 | Injectable(constructor); 18 | Reflect.defineMetadata('name', name, constructor); 19 | Reflect.defineMetadata('type', type, constructor); 20 | }; 21 | }; -------------------------------------------------------------------------------- /packages/framework/src/decorators/stereotype/controller.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2020 Chan Zewail 3 | * 4 | * This software is released under the MIT License. 5 | * https: //opensource.org/licenses/MIT 6 | */ 7 | 8 | import { Str } from '../../utils'; 9 | import { Component } from './component'; 10 | 11 | export const Controller = function (...prefixs: string[]): ClassDecorator { 12 | return function (constructor) { 13 | Component('', 'controller')(constructor); 14 | Reflect.defineMetadata('prefixs', prefixs.length > 0 ? prefixs.map(prefix => Str.formatPrefix(prefix)) : [Str.formatPrefix()], constructor); 15 | }; 16 | }; -------------------------------------------------------------------------------- /packages/framework/src/decorators/stereotype/entity.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2018 Chan Zewail 3 | * 4 | * This software is released under the MIT License. 5 | * https://opensource.org/licenses/MIT 6 | */ 7 | import { Component } from './component'; 8 | 9 | export const Entity = function (name: string): ClassDecorator { 10 | return function (constructor) { 11 | Component(undefined, 'entity')(constructor); 12 | Reflect.defineMetadata('table', name, constructor); 13 | }; 14 | }; -------------------------------------------------------------------------------- /packages/framework/src/decorators/stereotype/index.ts: -------------------------------------------------------------------------------- 1 | 2 | export * from './component'; 3 | export * from './controller'; 4 | export * from './service'; 5 | export * from './entity'; 6 | export * from './injectable'; 7 | export * from './middleware'; 8 | export * from './resourcer'; 9 | export * from './validator'; 10 | export * from './job'; 11 | export * from './agent'; 12 | export * from './schedule'; 13 | -------------------------------------------------------------------------------- /packages/framework/src/decorators/stereotype/injectable.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2018 Chan Zewail 3 | * 4 | * This software is released under the MIT License. 5 | * https://opensource.org/licenses/MIT 6 | */ 7 | 8 | import { INJECTABLE } from '../../symbol'; 9 | 10 | export const Injectable: ClassDecorator = function (constructor: any) { 11 | Reflect.defineMetadata(INJECTABLE, true, constructor); 12 | }; 13 | -------------------------------------------------------------------------------- /packages/framework/src/decorators/stereotype/job.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2020 Chan Zewail 3 | * 4 | * This software is released under the MIT License. 5 | * https://opensource.org/licenses/MIT 6 | */ 7 | import { Component } from './component'; 8 | 9 | export const Job = function (name?: string): ClassDecorator { 10 | return function (constructor) { 11 | Component(name, 'job')(constructor); 12 | }; 13 | }; 14 | -------------------------------------------------------------------------------- /packages/framework/src/decorators/stereotype/middleware.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2020 Chan Zewail 3 | * 4 | * This software is released under the MIT License. 5 | * https://opensource.org/licenses/MIT 6 | */ 7 | import { Component } from './component'; 8 | 9 | export const Middleware = function (name?: string): ClassDecorator { 10 | return function (constructor) { 11 | Component(name, 'middleware')(constructor); 12 | }; 13 | }; -------------------------------------------------------------------------------- /packages/framework/src/decorators/stereotype/resourcer.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2020 Chan Zewail 3 | * 4 | * This software is released under the MIT License. 5 | * https://opensource.org/licenses/MIT 6 | */ 7 | import { Component } from './component'; 8 | 9 | export const Resourcer = function (name?: string): ClassDecorator { 10 | return function (constructor) { 11 | Component(name, 'resource')(constructor); 12 | }; 13 | }; 14 | -------------------------------------------------------------------------------- /packages/framework/src/decorators/stereotype/schedule.ts: -------------------------------------------------------------------------------- 1 | import { Component } from './component'; 2 | 3 | 4 | export const schedule = function (name?: string): ClassDecorator { 5 | return function (constructor) { 6 | Component(name, 'schedule')(constructor); 7 | }; 8 | }; 9 | 10 | export const Schedule = schedule; -------------------------------------------------------------------------------- /packages/framework/src/decorators/stereotype/service.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2020 Chan Zewail 3 | * 4 | * This software is released under the MIT License. 5 | * https: //opensource.org/licenses/MIT 6 | */ 7 | import { Component } from './component'; 8 | 9 | export const Service = function (name?: string): ClassDecorator { 10 | return function (constructor) { 11 | Component(name, 'service')(constructor); 12 | }; 13 | }; 14 | -------------------------------------------------------------------------------- /packages/framework/src/decorators/stereotype/validator.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2018 Chan Zewail 3 | * 4 | * This software is released under the MIT License. 5 | * https://opensource.org/licenses/MIT 6 | */ 7 | import { Component } from './component'; 8 | 9 | export const Validator = function (name = ''): ClassDecorator { 10 | return function (constructor) { 11 | Component(name, 'validator')(constructor); 12 | }; 13 | }; -------------------------------------------------------------------------------- /packages/framework/src/decorators/use/index.ts: -------------------------------------------------------------------------------- 1 | export * from './use-middleware'; -------------------------------------------------------------------------------- /packages/framework/src/decorators/use/interface.ts: -------------------------------------------------------------------------------- 1 | export interface UseMiddlewareOption { 2 | middleware: any; 3 | args: any[]; 4 | } -------------------------------------------------------------------------------- /packages/framework/src/decorators/use/use-middleware.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2018 Chan Zewail 3 | * 4 | * This software is released under the MIT License. 5 | * https://opensource.org/licenses/MIT 6 | */ 7 | 8 | import { UseMiddlewareOption } from './interface'; 9 | 10 | /** 11 | * use middleware on controller 12 | * 13 | * @param middleware 14 | */ 15 | export const UseMiddleware = function (middleware: any, middlewareArgs: any[] = []) { 16 | return function (...args: any[]) { 17 | // decorator class 18 | if (args.length === 1) { 19 | const [target] = args; 20 | // const middlewares = Reflect.getMetadata('controllerMiddlewares', target) || []; 21 | const middlewaresMeta: UseMiddlewareOption[] = Reflect.getMetadata('use-middlewares', target) ?? []; 22 | middlewaresMeta.push({ 23 | middleware, 24 | args: middlewareArgs 25 | }); 26 | Reflect.defineMetadata('use-middlewares', middlewaresMeta, target); 27 | } 28 | // decorator method 29 | else { 30 | const [target, name] = args; 31 | const middlewaresMeta = Reflect.getMetadata('use-middlewares', target.constructor, name) || {}; 32 | if (!middlewaresMeta[name]) { 33 | middlewaresMeta[name] = []; 34 | } 35 | middlewaresMeta[name].push({ 36 | middleware, 37 | args: middlewareArgs 38 | }); 39 | Reflect.defineMetadata('use-middlewares', middlewaresMeta, target.constructor, name); 40 | } 41 | }; 42 | }; 43 | 44 | 45 | 46 | -------------------------------------------------------------------------------- /packages/framework/src/decorators/validates/factory.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2020 Chan Zewail 3 | * 4 | * This software is released under the MIT License. 5 | * https: //opensource.org/licenses/MIT 6 | */ 7 | 8 | export function validatorFactory(validatorMethod: any, args: any[] = [], options: any = {}): PropertyDecorator { 9 | return (target, name) => { 10 | const rules = Reflect.getMetadata('rules', target.constructor) || []; 11 | rules.push({ 12 | field: name, 13 | handler: validatorMethod, 14 | args, 15 | options, 16 | }); 17 | Reflect.defineMetadata('rules', rules, target.constructor); 18 | }; 19 | }; 20 | -------------------------------------------------------------------------------- /packages/framework/src/decorators/verb.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2020 Chan Zewail 3 | * 4 | * This software is released under the MIT License. 5 | * https: //opensource.org/licenses/MIT 6 | */ 7 | 8 | import * as http from 'http'; 9 | import { Str } from '../utils'; 10 | 11 | function verb(methods: any[], uri = '/'): MethodDecorator { 12 | return function (target, propertyKey) { 13 | const routes = Reflect.getMetadata('routes', target.constructor) || {}; 14 | if (!routes[propertyKey]) routes[propertyKey] = []; 15 | for (const method of methods) { 16 | routes[propertyKey].push({ 17 | uri: Str.formatPrefix(uri), 18 | method, 19 | }); 20 | } 21 | Reflect.defineMetadata('routes', routes, target.constructor); 22 | }; 23 | } 24 | 25 | export const Get = function (uri = '') { 26 | return verb(['GET'], uri); 27 | }; 28 | 29 | export const Post = function (uri = '') { 30 | return verb(['POST'], uri); 31 | }; 32 | 33 | export const Put = function (uri = '') { 34 | return verb(['PUT'], uri); 35 | }; 36 | 37 | export const Patch = function (uri = '') { 38 | return verb(['PATCH'], uri); 39 | }; 40 | 41 | export const Options = function (uri = '') { 42 | return verb(['OPTIONS'], uri); 43 | }; 44 | 45 | export const Head = function (uri = '') { 46 | return verb(['HEAD'], uri); 47 | }; 48 | 49 | export const Del = function (uri = '') { 50 | return verb(['DELETE'], uri); 51 | }; 52 | 53 | export const All = function (uri = '', methods: any[] = http.METHODS) { 54 | return verb(methods, uri); 55 | }; 56 | -------------------------------------------------------------------------------- /packages/framework/src/errors/http-error.ts: -------------------------------------------------------------------------------- 1 | import { OutgoingHttpHeaders } from "http"; 2 | 3 | /** 4 | * Copyright (c) 2018 Chan Zewail 5 | * 6 | * This software is released under the MIT License. 7 | * https://opensource.org/licenses/MIT 8 | */ 9 | 10 | export class HttpError extends Error { 11 | code: number; 12 | 13 | headers: OutgoingHttpHeaders; 14 | 15 | errors: any[]; 16 | 17 | constructor(code = 500, message = '', headers = {}, errors: any[] = []) { 18 | super(message); 19 | this.code = code; 20 | this.headers = headers; 21 | this.errors = errors; 22 | Error.captureStackTrace(this, this.constructor); 23 | } 24 | 25 | getErrors() { 26 | return this.errors; 27 | } 28 | } -------------------------------------------------------------------------------- /packages/framework/src/errors/illegal-argument-error.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2018 Chan Zewail 3 | * 4 | * This software is released under the MIT License. 5 | * https://opensource.org/licenses/MIT 6 | */ 7 | 8 | export class IllegalArgumentError extends Error { 9 | constructor(message = 'Illegal Argument') { 10 | super(message); 11 | Error.captureStackTrace(this, this.constructor); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /packages/framework/src/errors/not-found-http-error.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2018 Chan Zewail 3 | * 4 | * This software is released under the MIT License. 5 | * https://opensource.org/licenses/MIT 6 | */ 7 | import { HttpError } from './http-error'; 8 | 9 | 10 | export class NotFoundHttpError extends HttpError { 11 | constructor(message = 'Not Found') { 12 | super(404, message); 13 | Error.captureStackTrace(this, this.constructor); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /packages/framework/src/errors/validate-http-error.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2018 Chan Zewail 3 | * 4 | * This software is released under the MIT License. 5 | * https://opensource.org/licenses/MIT 6 | */ 7 | import { HttpError } from './http-error'; 8 | import { Validate } from '../validate'; 9 | 10 | 11 | export class ValidateHttpError extends HttpError { 12 | _validate: Validate; 13 | constructor(message = 'Validation error', validate: Validate) { 14 | super(422, message, {}, validate && validate.errors); 15 | this._validate = validate; 16 | Error.captureStackTrace(this, this.constructor); 17 | } 18 | 19 | get validate() { 20 | return this._validate; 21 | } 22 | 23 | getValidate() { 24 | return this._validate; 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /packages/framework/src/errors/views/errors/401.njk: -------------------------------------------------------------------------------- 1 | {% extends "errors/layout.njk" %} 2 | 3 | {% block content %} 4 | Sorry, you are not authorized to access this page. 5 | {% endblock %} -------------------------------------------------------------------------------- /packages/framework/src/errors/views/errors/404.njk: -------------------------------------------------------------------------------- 1 | {% extends "errors/layout.njk" %} 2 | 3 | {% block content %} 4 | Sorry, the page you are looking for could not be found. 5 | {% endblock %} -------------------------------------------------------------------------------- /packages/framework/src/errors/views/errors/500.njk: -------------------------------------------------------------------------------- 1 | {% extends "errors/layout.njk" %} 2 | 3 | {% block content %} 4 | Sorry, something went wrong on our servers. 5 | {% endblock %} -------------------------------------------------------------------------------- /packages/framework/src/errors/views/errors/503.njk: -------------------------------------------------------------------------------- 1 | {% extends "errors/layout.njk" %} 2 | 3 | {% block content %} 4 | Sorry, we are doing some maintenance. Please check back soon. 5 | {% endblock %} -------------------------------------------------------------------------------- /packages/framework/src/errors/views/errors/error.njk: -------------------------------------------------------------------------------- 1 | {% extends "errors/layout.njk" %} 2 | 3 | {% block content %} 4 | Oops! Something went wrong. 5 | {% endblock %} 6 | -------------------------------------------------------------------------------- /packages/framework/src/errors/views/errors/layout.njk: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Daze.js 8 | 33 | {% block head %} 34 | {% endblock %} 35 | 36 | 37 | {% block header %} 38 | {% endblock %} 39 |
40 |
41 | {% block content %} 42 | {% endblock %} 43 |
44 |
45 | {% block footer %} 46 | {% endblock %} 47 | 48 | -------------------------------------------------------------------------------- /packages/framework/src/foundation/auto-providers/common.provider.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2019 Chan Zewail 3 | * 4 | * This software is released under the MIT License. 5 | * https://opensource.org/licenses/MIT 6 | */ 7 | import path from 'path'; 8 | import { Depends, Provider, AppendAgent, AppendMaster } from '../../decorators'; 9 | import { app } from '../../helpers'; 10 | import { Loader } from '../../loader'; 11 | import * as providers from './depends'; 12 | 13 | @Depends([ 14 | providers.RouterProvider, 15 | providers.StereotypeProvider, 16 | providers.MessengerProvider, 17 | providers.LoggerProvider, 18 | providers.DatabaseProvider, 19 | providers.RedisProvider, 20 | providers.ProxyProvider, 21 | providers.CacheProvider, 22 | providers.MailerProvider, 23 | providers.ScheduleProvider, 24 | ]) 25 | @AppendAgent() 26 | @AppendMaster() 27 | @Provider() 28 | export class CommonProvider { 29 | async register() { 30 | const loader = app().get('loader'); 31 | await loader.scan( 32 | path.resolve(__dirname, '../buildin-app') 33 | ); 34 | await loader.autoScanApp(); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /packages/framework/src/foundation/auto-providers/depends/cache.provider.ts: -------------------------------------------------------------------------------- 1 | import { Provide, Provider, AppendAgent } from '../../../decorators'; 2 | import { Cache } from '../../../supports/cache'; 3 | import { app } from '../../../helpers'; 4 | 5 | 6 | @Provider() 7 | @AppendAgent() 8 | export class CacheProvider{ 9 | @Provide(Cache) 10 | _cache() { 11 | return new Cache(); 12 | } 13 | 14 | @Provide('cache') 15 | _cacheAlias() { 16 | return app().get(Cache); 17 | } 18 | } -------------------------------------------------------------------------------- /packages/framework/src/foundation/auto-providers/depends/database.provider.ts: -------------------------------------------------------------------------------- 1 | import { Provide, Disable } from '../../../decorators'; 2 | import { Database } from '../../../supports/database/database'; 3 | import { Application } from '../../application'; 4 | 5 | export class DatabaseProvider{ 6 | @Provide(Database) 7 | @Disable 8 | _database(app: Application) { 9 | return new Database(app); 10 | } 11 | 12 | @Provide('db') 13 | @Disable 14 | _databaseAlias(app: Application) { 15 | return app.get(Database); 16 | } 17 | } -------------------------------------------------------------------------------- /packages/framework/src/foundation/auto-providers/depends/index.ts: -------------------------------------------------------------------------------- 1 | export * from './database.provider'; 2 | export * from './logger.provider'; 3 | export * from './template-engine.provider'; 4 | export * from './stereotype.provider'; 5 | export * from './router.provider'; 6 | export * from './messenger.provider'; 7 | export * from './redis.provider'; 8 | export * from './server.provider'; 9 | export * from './proxy.provider'; 10 | export * from './cache.provider'; 11 | export * from './schedule.provider'; 12 | export * from './mailer.provider'; -------------------------------------------------------------------------------- /packages/framework/src/foundation/auto-providers/depends/logger.provider.ts: -------------------------------------------------------------------------------- 1 | import { Provide, Provider, AppendAgent, AppendMaster } from '../../../decorators'; 2 | import { ProviderInterface } from '../../../interfaces'; 3 | import { Application } from '../../application'; 4 | import { Logger } from '../../../supports/logger'; 5 | import { app } from '../../../helpers'; 6 | 7 | @Provider() 8 | @AppendAgent() 9 | @AppendMaster() 10 | export class LoggerProvider implements ProviderInterface { 11 | @Provide(Logger) 12 | logger(app: Application) { 13 | return new Logger(app); 14 | } 15 | 16 | @Provide('logger') 17 | loggerAlias(app: Application) { 18 | return app.get(Logger); 19 | } 20 | 21 | launch() { 22 | const logger = app().get(Logger); 23 | if (app().isAgent) { 24 | Logger.Cluster.bindListener(logger); 25 | } 26 | } 27 | } -------------------------------------------------------------------------------- /packages/framework/src/foundation/auto-providers/depends/mailer.provider.ts: -------------------------------------------------------------------------------- 1 | import { Provide, Provider, AppendAgent } from '../../../decorators'; 2 | import { Mailer } from '../../../supports/mailer'; 3 | import { Application } from '../../../foundation/application'; 4 | 5 | 6 | @Provider() 7 | @AppendAgent() 8 | export class MailerProvider{ 9 | @Provide(Mailer) 10 | mailer() { 11 | return new Mailer(); 12 | } 13 | 14 | @Provide('mail') 15 | mailerAlias(app: Application) { 16 | return app.get(Mailer); 17 | } 18 | } -------------------------------------------------------------------------------- /packages/framework/src/foundation/auto-providers/depends/messenger.provider.ts: -------------------------------------------------------------------------------- 1 | import { Provide, Provider, AppendAgent, AppendMaster } from '../../../decorators'; 2 | import { ProviderInterface } from '../../../interfaces'; 3 | import { Messenger } from '../../../messenger'; 4 | import { app } from '../../../helpers'; 5 | 6 | 7 | @Provider() 8 | @AppendAgent() 9 | @AppendMaster() 10 | export class MessengerProvider implements ProviderInterface { 11 | @Provide(Messenger) 12 | messenger() { 13 | return new Messenger(); 14 | } 15 | 16 | @Provide('messenger') 17 | loggerAlias() { 18 | return app().get(Messenger); 19 | } 20 | 21 | launch() { 22 | app().make(Messenger); 23 | } 24 | } -------------------------------------------------------------------------------- /packages/framework/src/foundation/auto-providers/depends/proxy.provider.ts: -------------------------------------------------------------------------------- 1 | import { Provider } from '../../../decorators'; 2 | import { app, config } from '../../../helpers'; 3 | import { ProxyMiddleware } from '../../buildin-app/middlewares/proxy'; 4 | import { Str } from '../../../utils'; 5 | import path from 'path'; 6 | 7 | @Provider() 8 | export class ProxyProvider{ 9 | 10 | private fixContext(context: string) { 11 | return path.join(Str.formatPrefix(config().get('app.baseUrl', '')), context) 12 | .replace(/^\*$/, "**") 13 | .replace(/\/\*$/, ""); 14 | } 15 | 16 | launch() { 17 | let proxyConfig = config().get('proxy', {}); 18 | // For backwards compatibility reasons. 19 | proxyConfig = Object.keys(proxyConfig).map(context => { 20 | const correctedContext = this.fixContext(context); 21 | if (typeof (proxyConfig[context]) === "string") { 22 | return { 23 | context: correctedContext, 24 | target: proxyConfig[context], 25 | originContext: context 26 | }; 27 | } else { 28 | return { 29 | ...proxyConfig[context], 30 | context: correctedContext, 31 | originContext: context, 32 | only: Array.isArray(proxyConfig[context]?.only) ? 33 | proxyConfig[context]?.only.map((uri: string) => this.fixContext(uri)) : 34 | undefined, 35 | except: Array.isArray(proxyConfig[context]?.except) ? 36 | proxyConfig[context]?.except.map((uri: string) => this.fixContext(uri)) : 37 | undefined, 38 | }; 39 | } 40 | }); 41 | for (const context of Object.keys(proxyConfig)) { 42 | const conf = proxyConfig[context]; 43 | app().use(ProxyMiddleware, [conf]); 44 | } 45 | } 46 | } -------------------------------------------------------------------------------- /packages/framework/src/foundation/auto-providers/depends/redis.provider.ts: -------------------------------------------------------------------------------- 1 | import { Provide, Provider, AppendAgent } from '../../../decorators'; 2 | import { Redis } from '../../../supports/redis'; 3 | import { app } from '../../../helpers'; 4 | 5 | 6 | @Provider() 7 | @AppendAgent() 8 | export class RedisProvider{ 9 | @Provide(Redis) 10 | _database() { 11 | return new Redis(); 12 | } 13 | 14 | @Provide('redis') 15 | _databaseAlias() { 16 | return app().get(Redis); 17 | } 18 | } -------------------------------------------------------------------------------- /packages/framework/src/foundation/auto-providers/depends/router.provider.ts: -------------------------------------------------------------------------------- 1 | import { Provide, Provider, AppendAgent } from '../../../decorators'; 2 | import { ProviderInterface } from '../../../interfaces'; 3 | import { Router } from '../../../http/router'; 4 | import { app } from '../../../helpers'; 5 | 6 | @Provider() 7 | @AppendAgent() 8 | export class RouterProvider implements ProviderInterface { 9 | @Provide(Router) 10 | router() { 11 | return new Router(); 12 | } 13 | 14 | @Provide('router') 15 | _routerAlias() { 16 | return app().get(Router); 17 | } 18 | } -------------------------------------------------------------------------------- /packages/framework/src/foundation/auto-providers/depends/schedule.provider.ts: -------------------------------------------------------------------------------- 1 | import { Provide, Provider, AppendAgent } from '../../../decorators'; 2 | import { ProviderInterface } from '../../../interfaces'; 3 | import { Application } from '../../../foundation/application'; 4 | import { Container } from '../../../container'; 5 | import { ScheduleService } from '../../../supports/schedule'; 6 | 7 | @Provider() 8 | @AppendAgent() 9 | export class ScheduleProvider implements ProviderInterface { 10 | app: Application = Container.get('app'); 11 | 12 | @Provide(ScheduleService) 13 | schedule() { 14 | return new ScheduleService(this.app); 15 | } 16 | } -------------------------------------------------------------------------------- /packages/framework/src/foundation/auto-providers/depends/server.provider.ts: -------------------------------------------------------------------------------- 1 | import { Provide, Provider } from '../../../decorators'; 2 | import { AppServer } from '../../../http/server'; 3 | import { ProviderInterface } from '../../../interfaces'; 4 | import { app } from '../../../helpers'; 5 | 6 | @Provider() 7 | export class AppServerProvider implements ProviderInterface { 8 | @Provide('appServer') 9 | httpServer() { 10 | return new AppServer(); 11 | } 12 | 13 | launch() { 14 | app().get('appServer').createServer(); 15 | } 16 | } -------------------------------------------------------------------------------- /packages/framework/src/foundation/auto-providers/depends/template-engine.provider.ts: -------------------------------------------------------------------------------- 1 | import { Application } from '../../application'; 2 | import * as nunjucks from 'nunjucks'; 3 | import * as path from 'path'; 4 | import { Provide, Provider } from '../../../decorators'; 5 | import { ProviderInterface } from '../../../interfaces'; 6 | import { Str } from '../../../utils'; 7 | 8 | import { app } from '../../../helpers'; 9 | 10 | @Provider() 11 | export class TemplateEngineProvider implements ProviderInterface { 12 | @Provide('template') 13 | _tmp(app: Application) { 14 | const templateEnv = new nunjucks.Environment([new nunjucks.FileSystemLoader(app.viewPath, { 15 | // noCache: app.isDebug, 16 | // watch: app.isDebug, 17 | noCache: false, 18 | watch: false 19 | }), new nunjucks.FileSystemLoader(path.resolve(__dirname, '../../../errors/views'), { 20 | // noCache: app.isDebug, 21 | // watch: app.isDebug, 22 | noCache: false, 23 | watch: false 24 | })], { 25 | autoescape: false, 26 | }); 27 | const config = app.get('config'); 28 | templateEnv.addGlobal('app', app); 29 | templateEnv.addGlobal('config', config); 30 | templateEnv.addGlobal('__public__', Str.formatPrefix(config.get('app.baseUrl', '')) + Str.formatPrefix(config.get('app.publicPrefix', ''))); 31 | return templateEnv; 32 | } 33 | 34 | launch() { 35 | app().make('template'); 36 | } 37 | } -------------------------------------------------------------------------------- /packages/framework/src/foundation/auto-providers/index.ts: -------------------------------------------------------------------------------- 1 | export * from './common.provider'; 2 | export * from './worker.provider'; 3 | 4 | 5 | -------------------------------------------------------------------------------- /packages/framework/src/foundation/auto-providers/worker.provider.ts: -------------------------------------------------------------------------------- 1 | // import Tokens from 'csrf'; 2 | import Tokens from 'csrf'; 3 | import { Depends, Provide, Disable, Provider } from '../../decorators'; 4 | import { Request } from '../../http/request'; 5 | // import { Response } from '../../http/response'; 6 | import * as symbols from '../../symbol'; 7 | import { request } from '../../helpers'; 8 | import * as providers from './depends'; 9 | import { AsyncLocalStorage } from 'async_hooks'; 10 | 11 | @Depends([ 12 | providers.TemplateEngineProvider, 13 | providers.AppServerProvider, 14 | ]) 15 | @Provider() 16 | export class WorkerProvider { 17 | @Provide(symbols.ASYNC_LOCAL_STORAGE) 18 | @Disable 19 | asyncLocalStorage() { 20 | return new AsyncLocalStorage(); 21 | } 22 | 23 | @Provide('csrf') 24 | _csrf() { 25 | return new Tokens(); 26 | } 27 | 28 | @Provide(Request, false) 29 | @Disable 30 | _requestInstance() { 31 | return request(); 32 | } 33 | 34 | @Provide(symbols.INJECTORS.QUERY, false) 35 | @Disable 36 | _query() { 37 | return request().query; 38 | } 39 | 40 | @Provide(symbols.INJECTORS.BODY, false) 41 | @Disable 42 | _body() { 43 | return request().body; 44 | } 45 | } -------------------------------------------------------------------------------- /packages/framework/src/foundation/buildin-app/agents/schedule.ts: -------------------------------------------------------------------------------- 1 | import { Agent } from '../../../decorators'; 2 | import { Application } from '../../application'; 3 | import { Container } from '../../../container'; 4 | import { ScheduleService } from '../../../supports/schedule'; 5 | 6 | /** 7 | * 在 Agent 进程处理定时任务 8 | */ 9 | @Agent() 10 | export class ScheduleAgent { 11 | app: Application = Container.get('app'); 12 | 13 | resolve() { 14 | this.app.get(ScheduleService).start(); 15 | } 16 | } -------------------------------------------------------------------------------- /packages/framework/src/http/middleware/index.ts: -------------------------------------------------------------------------------- 1 | export * from './middleware-service'; -------------------------------------------------------------------------------- /packages/framework/src/http/proxy/index.ts: -------------------------------------------------------------------------------- 1 | export * from './proxy'; -------------------------------------------------------------------------------- /packages/framework/src/http/request/utils/parse-body.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2019 Chan Zewail 3 | * 4 | * This software is released under the MIT License. 5 | * https://opensource.org/licenses/MIT 6 | */ 7 | import buddy from 'co-body'; 8 | import formidable from 'formidable'; 9 | import { Request } from '../index'; 10 | 11 | function parseForm(req: any) { 12 | return new Promise(((resolve, reject) => { 13 | const fields: any = {}; 14 | const files: any = {}; 15 | const form = new formidable.IncomingForm(); 16 | form.on('end', () => resolve({ 17 | fields, 18 | files, 19 | })).on('error', (err: any) => reject(err)).on('field', (field: string, value: any) => { 20 | if (fields[field]) { 21 | if (Array.isArray(fields[field])) { 22 | fields[field].push(value); 23 | } else { 24 | fields[field] = [fields[field], value]; 25 | } 26 | } else { 27 | fields[field] = value; 28 | } 29 | }).on('file', (field: string, file: any) => { 30 | if (files[field]) { 31 | if (Array.isArray(files[field])) { 32 | files[field].push(file); 33 | } else { 34 | files[field] = [files[field], file]; 35 | } 36 | } else { 37 | files[field] = file; 38 | } 39 | }); 40 | form.parse(req); 41 | })); 42 | } 43 | 44 | export async function parseBody(request: Request) { 45 | let body: any = {}; 46 | if (request.is('json')) { 47 | body.fields = await buddy.json(request.req); 48 | } else if (request.is('urlencoded')) { 49 | body.fields = await buddy.form(request.req); 50 | } else if (request.is('text')) { 51 | body.fields = await buddy.text(request.req); 52 | } else if (request.is('multipart')) { 53 | body = await parseForm(request.req); 54 | } else { 55 | body.fields = await buddy.text(request.req); 56 | } 57 | return body; 58 | } 59 | -------------------------------------------------------------------------------- /packages/framework/src/http/response/manager.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2019 zewail 3 | * 4 | * This software is released under the MIT License. 5 | * https://opensource.org/licenses/MIT 6 | */ 7 | import { Response } from '.'; 8 | 9 | export class ResponseManager { 10 | response: any; 11 | constructor(data: any = null, code = 200, headers = {}) { 12 | if (data instanceof Response) { 13 | this.response = data; 14 | } else { 15 | this.response = new Response(data, code, headers); 16 | } 17 | } 18 | 19 | output(request: any) { 20 | if (!this.response) return undefined; 21 | this.response.send(request); 22 | return this.response; 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /packages/framework/src/http/router/helpers.ts: -------------------------------------------------------------------------------- 1 | import { Node } from './node'; 2 | 3 | 4 | /** 5 | * match trie node with type 6 | */ 7 | export function isMatchNodeWithType(node: Node, key: string) { 8 | if (node.key && node.type === 'all') { 9 | return true; 10 | } 11 | if (node.key && node.type === 'static') { 12 | return node.key === key; 13 | } 14 | if (node.key && node.type === 'reg') { 15 | return (new RegExp(node.key).test(key)); 16 | } 17 | return false; 18 | }; 19 | 20 | /** 21 | * parse pattern to array 22 | */ 23 | export function parsePattern(pattern: string) { 24 | return pattern.split('/').filter(p => p !== ''); 25 | }; 26 | -------------------------------------------------------------------------------- /packages/framework/src/http/router/trie.ts: -------------------------------------------------------------------------------- 1 | import { Request } from '../request'; 2 | import { parsePattern } from './helpers'; 3 | import { Node } from './node'; 4 | import { Route } from './route'; 5 | 6 | export class Trie { 7 | /** 8 | * route trie cache map 9 | */ 10 | routes: Map = new Map(); 11 | 12 | /** 13 | * add a route 14 | * @param route 15 | */ 16 | add(route: Route) { 17 | for (const method of route.methods) { 18 | if (!this.routes.has(method)) { 19 | this.routes.set(method, new Node()); 20 | } 21 | this.register(this.routes.get(method), route); 22 | } 23 | } 24 | 25 | /** 26 | * register route node 27 | * @param rootNode 28 | * @param route 29 | */ 30 | register(rootNode: Node, route: Route) { 31 | rootNode.insert(route, route.pieces, 0); 32 | } 33 | 34 | /** 35 | * match route by request 36 | * @param request 37 | */ 38 | match(request: Request) { 39 | const _method = request.getMethod() || ''; 40 | const _path = request.getPath(); 41 | const rootNode = this.routes.get(_method); 42 | if (!rootNode) return null; 43 | const keys = parsePattern(_path); 44 | const result = rootNode.search(keys, 0); 45 | if (result) return result.route || null; 46 | return null; 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /packages/framework/src/http/server/index.ts: -------------------------------------------------------------------------------- 1 | export * from './server'; -------------------------------------------------------------------------------- /packages/framework/src/index.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2020 Chan Zewail 3 | * 4 | * This software is released under the MIT License. 5 | * https: //opensource.org/licenses/MIT 6 | */ 7 | 8 | import 'reflect-metadata'; 9 | 10 | export * from './base'; 11 | export * from './container'; 12 | export * from './http/cookie'; 13 | export * from './config'; 14 | export * from './supports/database'; 15 | export * from './decorators'; 16 | export * from './foundation/application'; 17 | export * from './loader'; 18 | export * from './supports/logger'; 19 | export * from './messenger'; 20 | export * from './http/middleware'; 21 | export * from './http/request'; 22 | export * from './resource'; 23 | export * from './http/response'; 24 | export * from './http/response/redirect'; 25 | export * from './view'; 26 | export * from './interfaces'; 27 | export * from './utils'; 28 | export * from './pagination'; 29 | export * from './helpers'; 30 | 31 | -------------------------------------------------------------------------------- /packages/framework/src/interfaces/agent.interface.ts: -------------------------------------------------------------------------------- 1 | 2 | 3 | export interface AgentInterface { 4 | resolve(): Promise | any; 5 | } -------------------------------------------------------------------------------- /packages/framework/src/interfaces/index.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2020 Chan Zewail 3 | * 4 | * This software is released under the MIT License. 5 | * https: //opensource.org/licenses/MIT 6 | */ 7 | 8 | export * from './middleware.interface'; 9 | export * from './resource.interface'; 10 | export * from './provider.interface'; 11 | export * from './agent.interface'; -------------------------------------------------------------------------------- /packages/framework/src/interfaces/middleware.interface.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2020 Chan Zewail 3 | * 4 | * This software is released under the MIT License. 5 | * https: //opensource.org/licenses/MIT 6 | */ 7 | 8 | import { Request } from '../http/request'; 9 | import { Next } from '../http/middleware'; 10 | 11 | export interface MiddlewareInterface { 12 | resolve(request: Request, next: Next): any; 13 | } -------------------------------------------------------------------------------- /packages/framework/src/interfaces/provider.interface.ts: -------------------------------------------------------------------------------- 1 | 2 | 3 | export interface ProviderInterface { 4 | register?(): void | Promise; 5 | launch?(): void | Promise; 6 | [key: string]: any; 7 | } -------------------------------------------------------------------------------- /packages/framework/src/interfaces/resource.interface.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2020 Chan Zewail 3 | * 4 | * This software is released under the MIT License. 5 | * https: //opensource.org/licenses/MIT 6 | */ 7 | 8 | export interface ResourceInterface { 9 | resolve(...args: any[]): any; 10 | } -------------------------------------------------------------------------------- /packages/framework/src/loader/index.ts: -------------------------------------------------------------------------------- 1 | export * from './loader'; -------------------------------------------------------------------------------- /packages/framework/src/messenger/index.ts: -------------------------------------------------------------------------------- 1 | export * from './messenger'; -------------------------------------------------------------------------------- /packages/framework/src/pagination/index.ts: -------------------------------------------------------------------------------- 1 | export * from './paginator'; -------------------------------------------------------------------------------- /packages/framework/src/pipeline/index.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2018 Chan Zewail 3 | * 4 | * This software is released under the MIT License. 5 | * https://opensource.org/licenses/MIT 6 | */ 7 | 8 | type TStage = (...args: any[]) => any 9 | 10 | type TProcesser = (...args: any[]) => any 11 | 12 | export class Pipeline { 13 | 14 | stages: TStage[] 15 | 16 | payload: any; 17 | 18 | /** 19 | * Create Pipeline Instance 20 | */ 21 | constructor(...stages: TStage[]) { 22 | /** 23 | * @type stages pipe stages 24 | */ 25 | this.stages = stages; 26 | } 27 | 28 | /** 29 | * add pipe stage 30 | */ 31 | pipe(...stages: TStage[]) { 32 | for (const stage of stages) { 33 | // assert(is.isFunction(stage), new IllegalArgumentError('pipe stage must be function')); 34 | this.stages.push(stage); 35 | } 36 | return this; 37 | } 38 | 39 | /** 40 | * send payloads 41 | */ 42 | send(...payload: any[]) { 43 | this.payload = payload; 44 | return this; 45 | } 46 | 47 | /** 48 | * run pipeline 49 | */ 50 | async process(processor: TProcesser) { 51 | if (this.stages.length > 0) { 52 | const callback = this.stages 53 | .reduceRight( 54 | (next, pipe) => async (...data: any[]) => pipe(...data, next.bind(null, ...data)), 55 | async (...params: any[]) => processor(...params), 56 | ); 57 | return callback(...this.payload); 58 | } 59 | return processor(...this.payload); 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /packages/framework/src/provider/index.ts: -------------------------------------------------------------------------------- 1 | export * from './provider'; -------------------------------------------------------------------------------- /packages/framework/src/resource/index.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2019 zewail 3 | * 4 | * This software is released under the MIT License. 5 | * https://opensource.org/licenses/MIT 6 | */ 7 | 8 | export * from './resource'; -------------------------------------------------------------------------------- /packages/framework/src/supports/cache/config.interface.ts: -------------------------------------------------------------------------------- 1 | export interface CacheConfigInterface { 2 | store: 'memory' | 'redis' | 'fs'; 3 | connection: string; 4 | } -------------------------------------------------------------------------------- /packages/framework/src/supports/cache/index.ts: -------------------------------------------------------------------------------- 1 | export * from './cache'; 2 | export * from './config.interface'; -------------------------------------------------------------------------------- /packages/framework/src/supports/cache/store/index.ts: -------------------------------------------------------------------------------- 1 | export * from './store'; 2 | export * from './memory'; 3 | export * from './redis'; 4 | export * from './fs'; -------------------------------------------------------------------------------- /packages/framework/src/supports/cache/store/store.ts: -------------------------------------------------------------------------------- 1 | 2 | 3 | export interface StorageItemInterface { 4 | value: any; 5 | expiresAt: number; 6 | } 7 | 8 | /** 9 | * 缓存的抽象方法 10 | */ 11 | export abstract class CacheStore { 12 | /** 13 | * 获取单个缓存 14 | * @param key 15 | */ 16 | abstract get(key: string): Promise; 17 | 18 | /** 19 | * 获取多个缓存 20 | * @param keys 21 | */ 22 | // abstract many(...keys: string[]): Promise; 23 | /** 24 | * 设置一个缓存 25 | * @param key 26 | * @param value 27 | * @param seconds 28 | */ 29 | abstract set(key: string, value: any, seconds?: number): Promise; 30 | abstract add(key: string, value: any, seconds: number): Promise; 31 | 32 | /** 33 | * 设置多个缓存 34 | * @param data 35 | */ 36 | // abstract setMany(data: Record): Promise; 37 | /** 38 | * 使缓存的值增加 39 | * @param key 40 | * @param value 41 | */ 42 | abstract increment(key: string, value: number): Promise; 43 | 44 | /** 45 | * 使缓存的值减少 46 | * @param key 47 | * @param value 48 | */ 49 | abstract decrement(key: string, value: number): Promise; 50 | 51 | /** 52 | * 设置一个不会过期的缓存 53 | * @param key 54 | * @param value 55 | */ 56 | abstract forever(key: string, value: any): Promise; 57 | 58 | /** 59 | * 删除一个缓存 60 | * @param key 61 | */ 62 | abstract remove(key: string): Promise; 63 | 64 | /** 65 | * 删除所有缓存 66 | */ 67 | abstract flush(): Promise; 68 | } -------------------------------------------------------------------------------- /packages/framework/src/supports/database/actuator/actuator.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * 执行器抽象类 3 | */ 4 | export abstract class Actuator { 5 | abstract query(sql: string, bindings?: any): Promise 6 | abstract select(query: string, bindings?: any[]): Promise 7 | abstract insert(query: string, bindings?: any[]): Promise 8 | abstract update(query: string, bindings?: any[]): Promise 9 | abstract delete(query: string, bindings?: any[]): Promise 10 | abstract commit(): Promise 11 | abstract rollback(): Promise 12 | } -------------------------------------------------------------------------------- /packages/framework/src/supports/database/actuator/index.ts: -------------------------------------------------------------------------------- 1 | export * from './actuator'; 2 | export * from './mysql-tansaction-actuator'; 3 | export * from './mysql-actuator'; 4 | -------------------------------------------------------------------------------- /packages/framework/src/supports/database/builder/index.ts: -------------------------------------------------------------------------------- 1 | export * from './builder'; -------------------------------------------------------------------------------- /packages/framework/src/supports/database/builder/join.ts: -------------------------------------------------------------------------------- 1 | import { Builder, TJoinType, TSymlink } from './builder'; 2 | 3 | export class NJoin { 4 | /** 5 | * sql builder instance 6 | */ 7 | builder: Builder; 8 | 9 | /** 10 | * join type 11 | * 'inner' | 'left' | 'right' | 'cross' 12 | */ 13 | type: TJoinType; 14 | 15 | /** 16 | * Create Join Builder 17 | * @param builder 18 | * @param type 19 | */ 20 | constructor(builder: Builder, type: TJoinType) { 21 | this.builder = builder; 22 | this.type = type; 23 | 24 | return new Proxy(this, this.proxy); 25 | } 26 | 27 | /** 28 | * get Join proxy 29 | */ 30 | get proxy(): ProxyHandler { 31 | return { 32 | get(target, p, receiver) { 33 | if (typeof p !== 'string') return Reflect.get(target, p, receiver); 34 | if (Reflect.has(target, p)) { 35 | return Reflect.get(target, p, receiver); 36 | } 37 | return target.builder[p as keyof Builder]; 38 | } 39 | }; 40 | } 41 | /** 42 | * set join table 43 | * @param table 44 | * @param as 45 | */ 46 | table(table: string, as?: string) { 47 | this.builder.table(table, as); 48 | return this; 49 | } 50 | 51 | /** 52 | * set on sql 53 | * @param column 54 | * @param operator 55 | * @param seed 56 | * @param symlink 57 | */ 58 | on(column: string, operator: string, seed?: string, symlink: TSymlink = 'and') { 59 | this.builder.whereColumn(column, operator, seed, symlink); 60 | return this; 61 | } 62 | 63 | /** 64 | * set or on sql 65 | * @param column 66 | * @param operator 67 | * @param seed 68 | */ 69 | orOn(column: string, operator: string, seed?: string) { 70 | return this.on(column, operator, seed, 'or'); 71 | } 72 | } 73 | 74 | export type Join = NJoin & Builder; 75 | export const Join: new (builder: Builder, type: TJoinType) => Join = NJoin as any; -------------------------------------------------------------------------------- /packages/framework/src/supports/database/connector/connector.ts: -------------------------------------------------------------------------------- 1 | export abstract class Connector { 2 | abstract connect(options: any): any; 3 | } -------------------------------------------------------------------------------- /packages/framework/src/supports/database/connector/mysql-connector.ts: -------------------------------------------------------------------------------- 1 | import { PoolOptions, createPool } from 'mysql2'; 2 | import { Connector } from './connector'; 3 | 4 | export class MysqlConnector extends Connector { 5 | /** 6 | * connect to mysql use pool 7 | * @param options 8 | */ 9 | connect(options: PoolOptions) { 10 | const pool = createPool(options); 11 | return pool; 12 | } 13 | 14 | // /** 15 | // * connect to mysql 16 | // */ 17 | // connect(options: string | ConnectionConfig) { 18 | // const connection = createConnection(options); 19 | // connection.connect(); 20 | // connection.on('error', (err: MysqlError) => { 21 | // this.handleConnectionLost(err, options); 22 | // }); 23 | // return connection; 24 | // } 25 | 26 | // /** 27 | // * handle error when connection lost 28 | // * @param err 29 | // * @param options 30 | // */ 31 | // handleConnectionLost(err: MysqlError, options: string | ConnectionConfig) { 32 | // if (err) { 33 | // if (err.fatal) { 34 | // this.connect(options); 35 | // } else { 36 | // throw err; 37 | // } 38 | // } 39 | // } 40 | } -------------------------------------------------------------------------------- /packages/framework/src/supports/database/index.ts: -------------------------------------------------------------------------------- 1 | export * from './database'; -------------------------------------------------------------------------------- /packages/framework/src/supports/database/manager/index.ts: -------------------------------------------------------------------------------- 1 | export * from './manager'; 2 | export * from './mysql-manager'; -------------------------------------------------------------------------------- /packages/framework/src/supports/database/manager/manager.ts: -------------------------------------------------------------------------------- 1 | import { Actuator } from '../actuator/actuator'; 2 | import { Builder } from '../builder'; 3 | import { Parser } from '../parser/parser'; 4 | 5 | export abstract class Manager { 6 | /** 7 | * sql parser 8 | */ 9 | parser: Parser; 10 | 11 | /** 12 | * sql actuator 13 | */ 14 | actuator: Actuator; 15 | 16 | /** 17 | * close connection close 18 | */ 19 | abstract close(): void 20 | 21 | /** 22 | * set table 23 | * @param table 24 | * @param as 25 | */ 26 | abstract table(table: string, as?: string): Builder 27 | abstract beginTransaction(): Promise 28 | abstract transaction(callback: (conn: Builder) => Promise | void): Promise 29 | abstract query(sql: string, bindings?: any): Promise 30 | abstract select(query: string, bindings?: any[]): Promise 31 | abstract insert(query: string, bindings?: any[]): Promise 32 | abstract update(query: string, bindings?: any[]): Promise 33 | abstract delete(query: string, bindings?: any[]): Promise 34 | } -------------------------------------------------------------------------------- /packages/framework/src/supports/database/parser/index.ts: -------------------------------------------------------------------------------- 1 | export * from './parser'; 2 | export * from './mysql-parser'; -------------------------------------------------------------------------------- /packages/framework/src/supports/database/parser/mysql-parser.ts: -------------------------------------------------------------------------------- 1 | import { Builder } from '../builder'; 2 | import { Parser } from './parser'; 3 | 4 | export class MysqlParser extends Parser { 5 | parseLock(builder: Builder) { 6 | if (typeof builder._lock === 'string') return builder._lock; 7 | if (typeof builder._lock === 'boolean') return builder._lock ? 'for update' : 'lock in share mode'; 8 | return ''; 9 | } 10 | } -------------------------------------------------------------------------------- /packages/framework/src/supports/logger/consts.ts: -------------------------------------------------------------------------------- 1 | export const LOGGER_PROCESS_MESSAGE = 'tiger:process_logger_message'; -------------------------------------------------------------------------------- /packages/framework/src/supports/logger/index.ts: -------------------------------------------------------------------------------- 1 | export * from './logger'; -------------------------------------------------------------------------------- /packages/framework/src/supports/mailer/connector.ts: -------------------------------------------------------------------------------- 1 | import nodemailer from 'nodemailer'; 2 | 3 | /** 4 | * 邮件服务连接器 5 | */ 6 | export class MailConnector { 7 | /** 8 | * 连接邮件服务器 9 | * @param options 10 | * @returns 11 | */ 12 | connect(options: any) { 13 | return nodemailer.createTransport(options); 14 | } 15 | } -------------------------------------------------------------------------------- /packages/framework/src/supports/mailer/index.ts: -------------------------------------------------------------------------------- 1 | export * from './mailer'; -------------------------------------------------------------------------------- /packages/framework/src/supports/mailer/mailer.ts: -------------------------------------------------------------------------------- 1 | 2 | import { config } from '../../helpers'; 3 | import { MailManager } from './manager'; 4 | import { MailConnector } from './connector'; 5 | /** 6 | * 邮件服务 7 | */ 8 | export class Mailer { 9 | /** 10 | * mail 管理器 11 | */ 12 | managers: Map = new Map(); 13 | 14 | /** 15 | * 获取已经连接的 mail 服务 16 | * @param name 17 | * @returns 18 | */ 19 | transporter(name = 'default') { 20 | if (!this.managers.has(name)) { 21 | const mailConfig = this.getTransporterConfigure(name); 22 | this.managers.set(name, this.createTransporterManager(mailConfig)); 23 | } 24 | return this.managers.get(name) as MailManager; 25 | } 26 | 27 | createTransporterManager(options: any) { 28 | const transporter = (new MailConnector()).connect(options); 29 | return new MailManager(transporter); 30 | } 31 | 32 | /** 33 | * 根据名称获取对应邮箱配置 34 | * @param name 35 | * @returns 36 | */ 37 | private getTransporterConfigure(name: string) { 38 | return config().get(`mail.${name}`); 39 | } 40 | } -------------------------------------------------------------------------------- /packages/framework/src/supports/mailer/manager.ts: -------------------------------------------------------------------------------- 1 | import nodemailer from 'nodemailer'; 2 | import { MailBuilder } from './builder'; 3 | 4 | /** 5 | * 邮件管理器 6 | */ 7 | export class MailManager { 8 | private transporter: nodemailer.Transporter; 9 | 10 | constructor(transporter: nodemailer.Transporter) { 11 | this.transporter = transporter; 12 | } 13 | 14 | create() { 15 | return new MailBuilder(this); 16 | } 17 | 18 | send(message: nodemailer.SendMailOptions) { 19 | return this.transporter.sendMail(message); 20 | } 21 | } -------------------------------------------------------------------------------- /packages/framework/src/supports/orm/index.ts: -------------------------------------------------------------------------------- 1 | export * from './base-model'; 2 | export * from './pivot-model'; 3 | export * from './repository'; 4 | export * from './model'; -------------------------------------------------------------------------------- /packages/framework/src/supports/orm/pivot-model.ts: -------------------------------------------------------------------------------- 1 | import { BaseEntity } from './base-model'; 2 | 3 | export class PivotEntity extends BaseEntity { 4 | // 5 | } 6 | -------------------------------------------------------------------------------- /packages/framework/src/supports/orm/relations/has-relations.abstract.ts: -------------------------------------------------------------------------------- 1 | import { Builder } from '../../database/builder'; 2 | import { Application } from '../../../foundation/application'; 3 | import { Container } from '../../../container'; 4 | import { ModelBuilder } from '../builder'; 5 | import { Model } from '../model'; 6 | import { Repository } from '../repository'; 7 | 8 | export abstract class HasRelations { 9 | /** 10 | * application 11 | */ 12 | protected app: Application = Container.get('app'); 13 | 14 | /** 15 | * 父模型 16 | */ 17 | protected parent: Model; 18 | 19 | /** 20 | * 当前关联模型 21 | */ 22 | protected model: Model; 23 | 24 | /** 25 | * 外键 26 | */ 27 | protected foreignKey: string; 28 | 29 | /** 30 | * 关联主键 31 | */ 32 | protected localKey: string; 33 | 34 | /** 35 | * 渴求式加载单个模型关联数据 36 | * @param result 37 | * @param relation 38 | */ 39 | abstract eagerly(result: Repository, relation: string, queryCallback?: (query: ModelBuilder & Builder) => void): Promise 40 | /** 41 | * 渴求式加载多个模型关联数据 42 | * @param results 43 | * @param relation 44 | */ 45 | abstract eagerlyMap(results: Repository[], relation: string, queryCallback?: (query: ModelBuilder & Builder) => void): Promise 46 | } -------------------------------------------------------------------------------- /packages/framework/src/supports/orm/relations/index.ts: -------------------------------------------------------------------------------- 1 | export * from './has-one'; 2 | export * from './belongs-to'; 3 | export * from './has-many'; 4 | export * from './belongs-to-many'; 5 | export * from './has-relations.abstract'; -------------------------------------------------------------------------------- /packages/framework/src/supports/redis/config.interface.ts: -------------------------------------------------------------------------------- 1 | import { RedisOptions, ClusterNode, ClusterOptions } from 'ioredis'; 2 | 3 | type clusterConfig = { 4 | cluster: boolean, 5 | nodes: ClusterNode[], 6 | } & ClusterOptions 7 | 8 | export interface RedisConfigInterface { 9 | default: RedisOptions | clusterConfig, 10 | schedule: RedisOptions | clusterConfig, 11 | cache: RedisOptions | clusterConfig, 12 | [key: string]: RedisOptions | clusterConfig, 13 | } -------------------------------------------------------------------------------- /packages/framework/src/supports/redis/connector.ts: -------------------------------------------------------------------------------- 1 | 2 | import IORedis from 'ioredis'; 3 | 4 | 5 | export class Connector { 6 | connect(options: any) { 7 | if (options.cluster === true) { 8 | const nodes = options.nodes || []; 9 | if (!nodes || !nodes.length) return; 10 | return new IORedis.Cluster(nodes, options); 11 | } else if (options.sentinels) { 12 | if (!options.sentinels || !options.sentinels.length) return; 13 | return new IORedis(options); 14 | } else { 15 | return new IORedis(options); 16 | } 17 | } 18 | } -------------------------------------------------------------------------------- /packages/framework/src/supports/redis/index.ts: -------------------------------------------------------------------------------- 1 | export * from './redis'; 2 | export * from './config.interface'; -------------------------------------------------------------------------------- /packages/framework/src/supports/redis/redis.ts: -------------------------------------------------------------------------------- 1 | import { config } from '../../helpers'; 2 | import { Connector } from './connector'; 3 | import { Redis as IORedis, Cluster } from 'ioredis'; 4 | import { fakeBaseClass } from '../../utils/fake-base-class'; 5 | 6 | export type RedisClient = IORedis | Cluster 7 | 8 | export class Redis extends fakeBaseClass() { 9 | /** 10 | * 连接实例 11 | */ 12 | private instances: Map = new Map(); 13 | 14 | constructor() { 15 | super(); 16 | return new Proxy(this, this.proxy); 17 | } 18 | 19 | /** 20 | * 代理器 21 | */ 22 | get proxy(): ProxyHandler { 23 | return { 24 | get(target: Redis, p: string | number | symbol, receiver: any) { 25 | if (typeof p === 'string') { 26 | if (Reflect.has(target, p)) { 27 | return Reflect.get(target, p, receiver); 28 | } 29 | return target.connection()[p as keyof RedisClient]; 30 | } 31 | return Reflect.get(target, p, receiver); 32 | } 33 | }; 34 | } 35 | 36 | /** 37 | * 获取 redis 连接 38 | * @param name 39 | * @returns 40 | */ 41 | public connection(name = 'default') { 42 | if (!this.instances.has(name)) { 43 | const config = this.getConnectioncConfigure(name); 44 | const instance = this.createConnection(config); 45 | instance && this.instances.set(name, instance); 46 | } 47 | return this.instances.get(name) as RedisClient; 48 | } 49 | 50 | /** 51 | * 获取连接配置 52 | * @param name 53 | * @returns 54 | */ 55 | private getConnectioncConfigure(name: string) { 56 | const options = config().get(`redis.${name}`); 57 | if (!options) throw new Error(`未找到 Redis 配置 [redis.${name}]`); 58 | return options; 59 | } 60 | 61 | /** 62 | * 创建连接 63 | * @param options 64 | * @returns 65 | */ 66 | private createConnection(options: any) { 67 | const redis = (new Connector()).connect(options); 68 | return redis; 69 | } 70 | } -------------------------------------------------------------------------------- /packages/framework/src/supports/schedule/index.ts: -------------------------------------------------------------------------------- 1 | export * from './schedule-service'; 2 | export * from './scheduler'; -------------------------------------------------------------------------------- /packages/framework/src/supports/schedule/matcher.ts: -------------------------------------------------------------------------------- 1 | import mz from 'moment-timezone'; 2 | 3 | /** 4 | * CORN 匹配器 5 | */ 6 | export class Matcher { 7 | /** 8 | * 匹配数组 9 | * @param pattern 10 | * @param value 11 | * @returns 12 | */ 13 | private matchPattern(pattern: string, value: number) { 14 | if (~pattern.indexOf(',')){ 15 | const patterns = pattern.split(','); 16 | return !!~patterns.indexOf(value.toString()); 17 | } 18 | return pattern === value.toString(); 19 | } 20 | 21 | /** 22 | * 根据表达式和时间进行匹配 23 | * @param pattern 24 | * @param date 25 | * @param timezone 26 | * @returns 27 | */ 28 | public match(pattern: string, date: Date, timezone?: string) { 29 | const _date = timezone ? mz.tz(date, timezone).toDate() : date; 30 | const expressions = pattern.split(' '); 31 | const runOnSecond = this.matchPattern(expressions[0], _date.getSeconds()); 32 | const runOnMinute = this.matchPattern(expressions[1], _date.getMinutes()); 33 | const runOnHour = this.matchPattern(expressions[2], _date.getHours()); 34 | const runOnDay = this.matchPattern(expressions[3], _date.getDate()); 35 | const runOnMonth = this.matchPattern(expressions[4], _date.getMonth() + 1); 36 | const runOnWeekDay = this.matchPattern(expressions[5], _date.getDay()); 37 | return runOnSecond && runOnMinute && runOnHour && runOnDay && runOnMonth && runOnWeekDay; 38 | } 39 | } -------------------------------------------------------------------------------- /packages/framework/src/supports/template-engine/index.ts: -------------------------------------------------------------------------------- 1 | export * from './template'; -------------------------------------------------------------------------------- /packages/framework/src/supports/template-engine/template.ts: -------------------------------------------------------------------------------- 1 | import * as nunjucks from 'nunjucks'; 2 | import * as path from 'path'; 3 | import { Application } from '../../foundation/application'; 4 | 5 | export class Template { 6 | static create(app: Application) { 7 | const templateEnv = new nunjucks.Environment([new nunjucks.FileSystemLoader(app.viewPath, { 8 | noCache: app.isDebug, 9 | watch: app.isDebug, 10 | }), new nunjucks.FileSystemLoader(path.resolve(__dirname, '../errors/views'), { 11 | noCache: app.isDebug, 12 | watch: app.isDebug, 13 | })], { 14 | autoescape: false, 15 | }); 16 | const config = app.get('config'); 17 | templateEnv.addGlobal('app', app); 18 | templateEnv.addGlobal('config', config); 19 | templateEnv.addGlobal('__public__', config.get('app.publicPrefix', '')); 20 | return templateEnv; 21 | } 22 | } -------------------------------------------------------------------------------- /packages/framework/src/utils/defered.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2019 Chan Zewail 3 | * 4 | * This software is released under the MIT License. 5 | * https://opensource.org/licenses/MIT 6 | */ 7 | 8 | export class Deferred { 9 | /** 10 | * promise 11 | */ 12 | private _promise: Promise; 13 | 14 | 15 | /** 16 | * resolve func 17 | */ 18 | private _resolve: (value: T | PromiseLike) => void; 19 | 20 | /** 21 | * reject func 22 | */ 23 | private _reject: (reason?: any) => void; 24 | 25 | /** 26 | * Create Deferred 27 | */ 28 | constructor() { 29 | this._promise = new Promise((resolve, reject) => { 30 | this._resolve = resolve; 31 | this._reject = reject; 32 | }); 33 | } 34 | 35 | /** 36 | * promise getter 37 | */ 38 | get promise(): Promise { 39 | return this._promise; 40 | } 41 | 42 | /** 43 | * resolve promise 44 | * @param value 45 | */ 46 | resolve (value: T | PromiseLike): void { 47 | this._resolve(value); 48 | } 49 | 50 | /** 51 | * reject promise 52 | * @param reason 53 | */ 54 | reject (reason?: any): void { 55 | this._reject(reason); 56 | } 57 | } -------------------------------------------------------------------------------- /packages/framework/src/utils/encrypt.ts: -------------------------------------------------------------------------------- 1 | 2 | import { createHash, BinaryLike } from 'crypto'; 3 | 4 | export const encrypt = (algorithm: string, content: BinaryLike) => { 5 | const hash = createHash(algorithm); 6 | hash.update(content); 7 | return hash.digest('hex'); 8 | }; -------------------------------------------------------------------------------- /packages/framework/src/utils/fake-base-class.ts: -------------------------------------------------------------------------------- 1 | export function fakeBaseClass(): new() => Pick { 2 | return class {} as any; 3 | } -------------------------------------------------------------------------------- /packages/framework/src/utils/index.ts: -------------------------------------------------------------------------------- 1 | 2 | export { Str } from './str'; 3 | export { Tool } from './tool'; 4 | -------------------------------------------------------------------------------- /packages/framework/src/utils/tool.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2018 Chan Zewail 3 | * 4 | * This software is released under the MIT License. 5 | * https://opensource.org/licenses/MIT 6 | */ 7 | 8 | import * as A from 'fp-ts/lib/Array'; 9 | import * as O from 'fp-ts/lib/Option'; 10 | import { pipe } from 'fp-ts/lib/pipeable'; 11 | 12 | export class Tool { 13 | 14 | /** 15 | * defer function based on promise 16 | * 基于 promise 的延迟函数 17 | */ 18 | static defer() { 19 | const result: any = {}; 20 | result.promise = new Promise((resolve: (value: T | PromiseLike) => void, reject: (reason?: any) => void) => { 21 | result.resolve = resolve; 22 | result.reject = reject; 23 | }); 24 | return result; 25 | } 26 | 27 | static A = A; 28 | static O = O; 29 | static pipe = pipe; 30 | } 31 | -------------------------------------------------------------------------------- /packages/framework/src/validate/index.ts: -------------------------------------------------------------------------------- 1 | export * from './validate'; 2 | -------------------------------------------------------------------------------- /packages/framework/src/view/factory.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2019 Chan Zewail 3 | * 4 | * This software is released under the MIT License. 5 | * https://opensource.org/licenses/MIT 6 | */ 7 | import { View } from '.'; 8 | import { Container } from '../container'; 9 | import { Application } from '../foundation/application'; 10 | import { Request } from '../http/request'; 11 | 12 | export class ViewFactory { 13 | /** 14 | * application 15 | */ 16 | app: Application = Container.get('app'); 17 | 18 | /** 19 | * view 20 | */ 21 | view: View; 22 | 23 | constructor(view: View) { 24 | this.view = view; 25 | } 26 | 27 | combineVars(request: Request) { 28 | const defaultVars = { 29 | sessionValue(key: string) { 30 | return request.session().get(key); 31 | }, 32 | get __token__() { 33 | return request._csrf; 34 | }, 35 | }; 36 | return Object.assign({}, defaultVars, this.view.getVars()); 37 | } 38 | 39 | output(request: Request) { 40 | const template = this.app.get('template'); 41 | const vars = this.combineVars(request); 42 | return template.render(this.view.getTemplate(), vars); 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /packages/framework/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.json", 3 | "compilerOptions": { 4 | "baseUrl": "./", 5 | "outDir": "dist", 6 | "module": "commonjs" 7 | }, 8 | "include": [ 9 | "src/**/*.ts", 10 | "vendors.d.ts" 11 | ], 12 | "exclude": [ 13 | "node_modules", 14 | "**/FUTURE_*", 15 | "**/DEPRECATED_*" 16 | ] 17 | } -------------------------------------------------------------------------------- /packages/framework/vendors.d.ts: -------------------------------------------------------------------------------- 1 | 2 | 3 | declare module 'keygrip' { 4 | const x: any; 5 | export = x; 6 | } 7 | 8 | declare module 'require-main-filename' { 9 | const x: any; 10 | export = x; 11 | } 12 | 13 | declare module 'core-util-is' { 14 | const x: any; 15 | export = x; 16 | } 17 | 18 | 19 | declare module 'cache-content-type' { 20 | const x: any; 21 | export = x; 22 | } 23 | 24 | declare module '@dazejs/trace-page' { 25 | const x: any; 26 | export = x; 27 | } 28 | 29 | 30 | declare module 'winston-mongodb' { 31 | const MongoDB: MongoDBTransportInstance; 32 | } 33 | 34 | // declare module 'winston-daily-rotate-file' { 35 | // var x: any; 36 | // export = x; 37 | // } 38 | 39 | // declare module 'winston' { 40 | // var x: any; 41 | // export = x; 42 | // } 43 | 44 | -------------------------------------------------------------------------------- /packages/trace-page/.npmignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | coverage 3 | __tests__ 4 | __debug__ 5 | .idea 6 | .vscode 7 | logs 8 | -------------------------------------------------------------------------------- /packages/trace-page/README.md: -------------------------------------------------------------------------------- 1 | # `@dazejs/trace-page` 2 | 3 | > TODO: description 4 | 5 | ## Usage 6 | 7 | ``` 8 | const tracePage = require('@dazejs/trace-page'); 9 | 10 | // TODO: DEMONSTRATE API 11 | ``` 12 | -------------------------------------------------------------------------------- /packages/trace-page/__tests__/index.spec.ts: -------------------------------------------------------------------------------- 1 | // import tracePage from '..'; 2 | 3 | describe('@dazejs/trace-page', () => { 4 | it('needs tests', () => { 5 | expect(true).toBeTruthy() 6 | }); 7 | }); 8 | -------------------------------------------------------------------------------- /packages/trace-page/global.d.ts: -------------------------------------------------------------------------------- 1 | declare module 'html-webpack-inline-source-plugin'; 2 | declare module 'code-prettify'; 3 | declare module 'zepto'; 4 | declare module 'html-webpack-plugin'; 5 | -------------------------------------------------------------------------------- /packages/trace-page/images.d.ts: -------------------------------------------------------------------------------- 1 | declare module '*.svg' 2 | declare module '*.png' 3 | declare module '*.jpg' 4 | declare module '*.jpeg' 5 | declare module '*.gif' 6 | declare module '*.bmp' 7 | declare module '*.tiff' -------------------------------------------------------------------------------- /packages/trace-page/template/index.ts: -------------------------------------------------------------------------------- 1 | 2 | import './less/index.less'; 3 | // eslint-disable-next-line 4 | // @ts-ignore 5 | import $ from 'zepto'; 6 | // eslint-disable-next-line 7 | // @ts-ignore 8 | import PR from 'code-prettify'; 9 | 10 | $(function () { 11 | PR.prettyPrint(); 12 | // eslint-disable-next-line 13 | // @ts-ignore 14 | $('.frame').on('click', function () { 15 | // eslint-disable-next-line 16 | // @ts-ignore 17 | const index = $(this).data('index'); 18 | $('.frame.active').removeClass('active'); 19 | // eslint-disable-next-line 20 | // @ts-ignore 21 | $(this).addClass('active'); 22 | $('.frame-code.active').removeClass('active'); 23 | $('.frame-code' + '-' + index).addClass('active'); 24 | }); 25 | // eslint-disable-next-line 26 | // @ts-ignore 27 | $('.frame-code').each(function () { 28 | // eslint-disable-next-line 29 | // @ts-ignore 30 | const ele = $(this); 31 | const li = ele.find('.prettyprint').find('li'); 32 | const currentLineNumber = ele.data('current'); 33 | const firstLineNumber = li.first().attr('value'); 34 | const activeLineNumber = currentLineNumber - firstLineNumber - 1; 35 | li.eq(activeLineNumber).addClass('active', 'current'); 36 | li.eq(activeLineNumber - 1).addClass('current'); 37 | li.eq(activeLineNumber + 1).addClass('current'); 38 | }); 39 | }); 40 | -------------------------------------------------------------------------------- /packages/trace-page/template/less/code.less: -------------------------------------------------------------------------------- 1 | 2 | /*! Color themes for Google Code Prettify | MIT License | github.com/jmblog/color-themes-for-google-code-prettify */ 3 | .prettyprint { 4 | background: #2f3640; 5 | font-family: Menlo, "Bitstream Vera Sans Mono", "DejaVu Sans Mono", Monaco, Consolas, monospace; 6 | border: 0 !important; 7 | } 8 | 9 | .pln { 10 | color: #e6e9ed; 11 | } 12 | 13 | 14 | /* Specify class=linenums on a pre to get line numbering */ 15 | ol.linenums { 16 | margin-top: 0; 17 | margin-bottom: 0; 18 | color: #656d78; 19 | margin-left: 10px; 20 | } 21 | 22 | li.L0, 23 | li.L1, 24 | li.L2, 25 | li.L3, 26 | li.L4, 27 | li.L5, 28 | li.L6, 29 | li.L7, 30 | li.L8, 31 | li.L9 { 32 | padding-left: 1em; 33 | background-color: #2f3640; 34 | list-style-type: decimal; 35 | } 36 | 37 | @media screen { 38 | 39 | /* string content */ 40 | 41 | .str { 42 | color: #ffce54; 43 | } 44 | 45 | /* keyword */ 46 | 47 | .kwd { 48 | color: #4fc1e9; 49 | } 50 | 51 | /* comment */ 52 | 53 | .com { 54 | color: #656d78; 55 | } 56 | 57 | /* type name */ 58 | 59 | .typ { 60 | color: #4fc1e9; 61 | } 62 | 63 | /* literal value */ 64 | 65 | .lit { 66 | color: #ac92ec; 67 | } 68 | 69 | /* punctuation */ 70 | 71 | .pun { 72 | color: #e6e9ed; 73 | } 74 | 75 | /* lisp open bracket */ 76 | 77 | .opn { 78 | color: #e6e9ed; 79 | } 80 | 81 | /* lisp close bracket */ 82 | 83 | .clo { 84 | color: #e6e9ed; 85 | } 86 | 87 | /* markup tag name */ 88 | 89 | .tag { 90 | color: #ed5565; 91 | } 92 | 93 | /* markup attribute name */ 94 | 95 | .atn { 96 | color: #a0d468; 97 | } 98 | 99 | /* markup attribute value */ 100 | 101 | .atv { 102 | color: #ffce54; 103 | } 104 | 105 | /* declaration */ 106 | 107 | .dec { 108 | color: #ac92ec; 109 | } 110 | 111 | /* variable name */ 112 | 113 | .var { 114 | color: #e6e9ed; 115 | } 116 | 117 | /* function name */ 118 | 119 | .fun { 120 | color: #e6e9ed; 121 | } 122 | } -------------------------------------------------------------------------------- /packages/trace-page/tsconfig-for-webpack-config.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "module": "commonjs", 4 | "target": "es5", 5 | "esModuleInterop": true, 6 | "skipLibCheck": true, 7 | "declaration": false, 8 | "noLib": true 9 | } 10 | } -------------------------------------------------------------------------------- /packages/trace-page/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.json", 3 | "compilerOptions": { 4 | "module": "commonjs", 5 | "target": "es5", 6 | "baseUrl": "./", 7 | "outDir": "dist" 8 | }, 9 | "include": [ 10 | "./index.ts", 11 | "./global.d.ts", 12 | "./images.d.ts" 13 | ], 14 | "exclude": [ 15 | "node_modules" 16 | ] 17 | } -------------------------------------------------------------------------------- /scripts/build.sh: -------------------------------------------------------------------------------- 1 | 2 | #!/bin/bash 3 | set -e 4 | cp ./README.md ./packages/framework/README.md 5 | cp ./README_en.md ./packages/framework/README_en.md 6 | lerna run build --stream -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es2017", 4 | "module": "commonjs", 5 | "lib": [ 6 | "esnext" 7 | ], 8 | "allowJs": false, 9 | "declaration": true, 10 | "sourceMap": true, 11 | "removeComments": true, 12 | "strict": true, 13 | "noImplicitAny": true, 14 | "strictNullChecks": true, 15 | "strictFunctionTypes": true, 16 | "strictPropertyInitialization": false, 17 | "noImplicitThis": true, 18 | "alwaysStrict": true, 19 | "noUnusedLocals": true, 20 | "noUnusedParameters": true, 21 | "noImplicitReturns": true, 22 | "moduleResolution": "node", 23 | "allowSyntheticDefaultImports": true, 24 | "esModuleInterop": true, 25 | "experimentalDecorators": true, 26 | "emitDecoratorMetadata": true, 27 | "skipLibCheck": true, 28 | "preserveSymlinks": true 29 | } 30 | } --------------------------------------------------------------------------------