diff --git a/framework-ts/README.md b/framework-ts/README.md new file mode 100644 index 0000000..23a909c --- /dev/null +++ b/framework-ts/README.md @@ -0,0 +1,44 @@ +# Framework with TypeScript Example + +This example contains [app] and [framework] + +## Quick Start + +Start an application using custom framework called yadan + +```bash +$ cd yadan +$ npm install +$ npm run tsc +$ cd ../app +$ npm install +$ npm run tsc +$ npm run dev +``` + +Yadan is a framework by TypeScript, it should be published to npm normally. With this example, you need `npm run tsc`. + +## Run Test + +Application + +```bash +$ cd app +$ npm run tsc +$ npm test +``` + +Framework + +```bash +$ cd yadan +$ npm run tsc +$ npm test +``` + +## Questions & Suggestions + +Please open an issue [here](https://github.com/eggjs/egg/issues). + +[app]: https://github.com/eggjs/examples/tree/master/framework-ts/app +[framework]: https://github.com/eggjs/examples/tree/master/framework-ts/yadan diff --git a/framework-ts/app/.travis.yml b/framework-ts/app/.travis.yml new file mode 100644 index 0000000..c48d667 --- /dev/null +++ b/framework-ts/app/.travis.yml @@ -0,0 +1,11 @@ +sudo: false +language: node_js +node_js: + - '8' +install: + - npm i -g ts-node + - npm i npminstall && npminstall +script: + - npm run ci +after_script: + - npminstall codecov && codecov diff --git a/framework-ts/app/app/controller/home.ts b/framework-ts/app/app/controller/home.ts new file mode 100644 index 0000000..de3ec6f --- /dev/null +++ b/framework-ts/app/app/controller/home.ts @@ -0,0 +1,24 @@ +import { Controller, Service } from 'yadan-ts' + +export default class HomeController extends Controller { + async render() { + const { ctx } = this + + // use service defined in framework + const data = await ctx.service.test.get(123); + await ctx.render('home.tpl', data); + } +} + +declare module 'egg' { + export interface IController { + home: HomeController; + } +} + +// @FIXME +declare module 'egg' { + export interface IService { + test: any + } +} diff --git a/framework-ts/app/app/public/css/news.css b/framework-ts/app/app/public/css/news.css new file mode 100644 index 0000000..b922c98 --- /dev/null +++ b/framework-ts/app/app/public/css/news.css @@ -0,0 +1,203 @@ +body, +html { + font-family: Verdana; + font-size: 13px; + height: 100% +} +ul { + list-style-type: none; + padding: 0; + margin: 0 +} +a { + color: #000; + cursor: pointer; + text-decoration: none +} +#wrapper { + background-color: #f6f6ef; + width: 85%; + min-height: 80px; + margin: 0 auto +} +#header, +#wrapper { + position: relative +} +#header { + background-color: #f60; + height: 24px +} +#header h1 { + font-weight: 700; + font-size: 13px; + display: inline-block; + vertical-align: middle; + margin: 0 +} +#header .source { + color: #fff; + font-size: 11px; + position: absolute; + top: 4px; + right: 4px +} +#header .source a { + color: #fff +} +#header .source a:hover { + text-decoration: underline +} +#yc { + border: 1px solid #fff; + margin: 2px; + display: inline-block +} +#yc, +#yc img { + vertical-align: middle +} +.view { + position: absolute; + background-color: #f6f6ef; + width: 100%; + -webkit-transition: opacity .2s ease; + transition: opacity .2s ease; + box-sizing: border-box; + padding: 8px 20px +} +.view.v-enter, +.view.v-leave { + opacity: 0 +} +@media screen and (max-width: 700px) { + body, + html { + margin: 0 + } + #wrapper { + width: 100% + } +} +.news-view { + padding-left: 5px; + padding-right: 15px +} +.news-view.loading:before { + content: "Loading..."; + position: absolute; + top: 16px; + left: 20px +} +.news-view .nav { + padding: 10px 10px 10px 40px; + margin-top: 10px; + border-top: 2px solid #f60 +} +.news-view .nav a { + margin-right: 10px +} +.news-view .nav a:hover { + text-decoration: underline +} +.item { + padding: 2px 0 2px 40px; + position: relative; + -webkit-transition: background-color .2s ease; + transition: background-color .2s ease +} +.item p { + margin: 2px 0 +} +.item .index, +.item .title:visited { + color: #828282 +} +.item .index { + position: absolute; + width: 30px; + text-align: right; + left: 0; + top: 4px +} +.item .domain, +.item .subtext { + font-size: 11px; + color: #828282 +} +.item .domain a, +.item .subtext a { + color: #828282 +} +.item .subtext a:hover { + text-decoration: underline +} +.item-view .item { + padding-left: 0; + margin-bottom: 30px +} +.item-view .item .index { + display: none +} +.item-view .poll-options { + margin-left: 30px; + margin-bottom: 40px +} +.item-view .poll-options li { + margin: 12px 0 +} +.item-view .poll-options p { + margin: 8px 0 +} +.item-view .poll-options .subtext { + color: #828282; + font-size: 11px +} +.item-view .itemtext { + color: #828282; + margin-top: 0; + margin-bottom: 30px +} +.item-view .itemtext p { + margin: 10px 0 +} +.comhead { + font-size: 11px; + margin-bottom: 8px +} +.comhead, +.comhead a { + color: #828282 +} +.comhead a:hover { + text-decoration: underline +} +.comhead .toggle { + margin-right: 4px +} +.comment-content { + margin: 0 0 16px 24px; + word-wrap: break-word +} +.comment-content code { + white-space: pre-wrap +} +.child-comments { + margin: 8px 0 8px 22px +} +.user-view { + color: #828282 +} +.user-view li { + margin: 5px 0 +} +.user-view .label { + display: inline-block; + min-width: 60px +} +.user-view .about { + margin-top: 1em +} +.user-view .links a { + text-decoration: underline +} \ No newline at end of file diff --git a/framework-ts/app/app/public/favicon.png b/framework-ts/app/app/public/favicon.png new file mode 100644 index 0000000..41d69cd Binary files /dev/null and b/framework-ts/app/app/public/favicon.png differ diff --git a/framework-ts/app/app/router.ts b/framework-ts/app/app/router.ts new file mode 100644 index 0000000..882b97d --- /dev/null +++ b/framework-ts/app/app/router.ts @@ -0,0 +1,7 @@ +import { Application } from 'egg' + +export default (app: Application) => { + const controller = app.controller + + app.router.get('/', app.controller.home.render); +} diff --git a/framework-ts/app/app/view/home.tpl b/framework-ts/app/app/view/home.tpl new file mode 100644 index 0000000..2349c26 --- /dev/null +++ b/framework-ts/app/app/view/home.tpl @@ -0,0 +1 @@ +hi, {{ name }} \ No newline at end of file diff --git a/framework-ts/app/appveyor.yml b/framework-ts/app/appveyor.yml new file mode 100644 index 0000000..62954d0 --- /dev/null +++ b/framework-ts/app/appveyor.yml @@ -0,0 +1,15 @@ +environment: + matrix: + - nodejs_version: '8' + +install: + - ps: Install-Product node $env:nodejs_version + - npm i -g ts-node + - npm i npminstall && node_modules\.bin\npminstall + +test_script: + - node --version + - npm --version + - npm run test + +build: off diff --git a/framework-ts/app/config/config.default.ts b/framework-ts/app/config/config.default.ts new file mode 100644 index 0000000..234109c --- /dev/null +++ b/framework-ts/app/config/config.default.ts @@ -0,0 +1,29 @@ +import { EggAppConfig, PowerPartial } from 'egg'; + +// for config.{env}.ts +export type DefaultConfig = PowerPartial; + +// app special config scheme +export interface BizConfig { + sourceUrl: string; + news: { + pageSize: number; + serverUrl: string; + }; +} + +export default (appInfo: EggAppConfig) => { + const config = & BizConfig> {}; + + // app special config + config.sourceUrl = `https://github.com/eggjs/examples/tree/master/${appInfo.name}`; + config.news = { + pageSize: 30, + serverUrl: 'https://hacker-news.firebaseio.com/v0', + }; + + // override config from framework / plugin + config.keys = appInfo.name + '123456'; + + return config; +}; diff --git a/framework-ts/app/config/config.local.ts b/framework-ts/app/config/config.local.ts new file mode 100644 index 0000000..c790a63 --- /dev/null +++ b/framework-ts/app/config/config.local.ts @@ -0,0 +1,9 @@ +import { DefaultConfig } from './config.default'; + +export default () => { + const config: DefaultConfig = {}; + config.news = { + pageSize: 20, + }; + return config; +}; diff --git a/framework-ts/app/config/config.prod.ts b/framework-ts/app/config/config.prod.ts new file mode 100644 index 0000000..a1cb344 --- /dev/null +++ b/framework-ts/app/config/config.prod.ts @@ -0,0 +1,9 @@ +import { DefaultConfig } from './config.default'; + +export default () => { + const config: DefaultConfig = {}; + config.news = { + pageSize: 30, + }; + return config; +}; diff --git a/framework-ts/app/config/plugin.ts b/framework-ts/app/config/plugin.ts new file mode 100644 index 0000000..2554dd8 --- /dev/null +++ b/framework-ts/app/config/plugin.ts @@ -0,0 +1,3 @@ + +export default { +}; diff --git a/framework-ts/app/package.json b/framework-ts/app/package.json new file mode 100644 index 0000000..c8dc0e4 --- /dev/null +++ b/framework-ts/app/package.json @@ -0,0 +1,34 @@ +{ + "name": "framework-ts-example", + "version": "1.0.0", + "dependencies": { + "egg": "^2.7.1", + "egg-scripts": "^2.6.0", + "yadan-ts": "../yadan" + }, + "devDependencies": { + "egg-bin": "^4.7.0", + "egg-mock": "^3.13.1" + }, + "engines": { + "node": ">=8.10.0" + }, + "scripts": { + "autod": "autod", + "clean": "rimraf app/**/*.{js,map} test/**/*.{js,map} config/**/*.{js,map}", + "ci": "npm run lint && npm run cov", + "cov": "npm run tsc && egg-bin cov", + "debug": "egg-bin debug", + "dev": "egg-bin dev", + "lint": "tslint --fix -p tsconfig.json -t stylish", + "test": "npm run tsc && npm run test-local", + "test-local": "egg-bin test", + "start": "egg-scripts start --daemon --port=7001 --title=egg-win-test --workers=2", + "stop": "egg-scripts stop --title=egg-win-test", + "tsc": "tsc -p tsconfig.json", + "tsc:w": "tsc -p tsconfig.json -w" + }, + "egg": { + "framework": "yadan-ts" + } +} diff --git a/framework-ts/app/test/app/controller/home.test.js b/framework-ts/app/test/app/controller/home.test.js new file mode 100644 index 0000000..f60869d --- /dev/null +++ b/framework-ts/app/test/app/controller/home.test.js @@ -0,0 +1,19 @@ +'use strict'; + +const mock = require('egg-mock'); + +describe('test/app/controller/home.test.js', () => { + + let app; + before(() => { + app = mock.app(); + return app.ready(); + }); + + it('should GET /', () => { + return app.httpRequest() + .get('/') + .expect(200) + .expect('hi, framework-ts-example_123456'); + }); +}); diff --git a/framework-ts/app/tsconfig.json b/framework-ts/app/tsconfig.json new file mode 100644 index 0000000..2181abc --- /dev/null +++ b/framework-ts/app/tsconfig.json @@ -0,0 +1,35 @@ +{ + "compilerOptions": { + "alwaysStrict": true, + "charset": "utf8", + "declaration": false, + "emitDecoratorMetadata": true, + "experimentalDecorators": true, + "importHelpers": false, + "inlineSourceMap": true, + "module": "commonjs", + "newLine": "lf", + "noFallthroughCasesInSwitch": true, + "pretty": true, + "skipLibCheck": true, + "sourceMap": false, + "strict": true, + "noImplicitAny": true, + "noImplicitThis": true, + "target": "ES2017", + "types" : ["node"] + }, + "include": [ + "./*.ts", + "app/**/*.ts", + "config/**/*.ts", + "test/**/*.ts" + ], + "exclude": [ + "app/public", + "app/views", + "node_modules*", + "**/*.d.ts", + "**/*.spec.ts" + ] +} diff --git a/framework-ts/app/tslint.json b/framework-ts/app/tslint.json new file mode 100644 index 0000000..532fd40 --- /dev/null +++ b/framework-ts/app/tslint.json @@ -0,0 +1,151 @@ +{ + "extends": ["tslint:latest", "tslint-eslint-rules"], + "linterOptions": { + "exclude": [ + "node_modules", + "*.d.ts" + ] + }, + "rules": { + "adjacent-overload-signatures": true, + "align": [true, "members", "parameters", "statements"], + "array-bracket-spacing": [true, "never", {"singleValue": false, "objectsInArrays": true, "arraysInArrays": true} ], + "arrow-parens": [true, "ban-single-arg-parens"], + "await-promise": [true, "Thenable"], + "ban-comma-operator": true, + "block-spacing": [true, "always"], + "brace-style": [true, "stroustrup", { "allowSingleLine": true }], + "comment-format": [true, "check-space", {"ignore-words": ["-", "+"]}], + "curly": [true, "ignore-same-line"], + "eofline": true, + "forin": false, + "import-blacklist": [ + true, + "rxjs", + "rxjs/Rx" + ], + "indent": [true, "spaces", 2], + "interface-name": [ false, "never-prefix" ], + "linebreak-style": [true , "LF" ], + "max-classes-per-file": [ true, 10 ], + "max-line-length": [true, 120], + "member-access": [ false ], + "member-ordering": [true, {"order": [ + "public-static-field", + "public-instance-field", + "public-constructor", + "private-static-field", + "private-instance-field", + "private-constructor", + "public-instance-method", + "protected-instance-method", + "private-instance-method" + ]}], + "no-arg": true, + "no-angle-bracket-type-assertion": false, + "no-consecutive-blank-lines": [true, 4], + "no-console": [ true, "dir", "log", "warn" ], + "no-construct": true, + "no-control-regex": true, + "no-duplicate-variable": true, + "no-duplicate-imports": true, + "no-duplicate-switch-case": true, + "no-empty": false, + "no-extra-semi": true, + "no-eval": true, + "no-implicit-dependencies": [true, "dev"], + "no-multi-spaces": [ true, { "exceptions": { "PropertyAssignment": true, "VariableDeclaration": false } } ], + "no-object-literal-type-assertion": false, + "no-parameter-reassignment": false, + "no-return-await": true, + "no-reference": true, + "no-shadowed-variable": [ + true, + { + "class": true, + "enum": true, + "function": true, + "interface": true, + "namespace": true, + "typeAlias": true, + "typeParameter": true + } + ], + "no-string-throw": true, + "no-submodule-imports": [true, + "rxjs", + "@angular/platform-browser", + "source-map-support/register" + ], + "no-trailing-whitespace": [true, "ignore-comments"], + "no-unnecessary-initializer": true, + "no-unused-expression": [true, "allow-fast-null-checks"], + "no-unused-variable": { + "severity": "warning", + "options": [true, { "ignore-pattern": "^_" }] + }, + "no-unnecessary-type-assertion": false, + "no-use-before-declare": true, + "no-var-keyword": true, + "no-var-requires": true, + "object-curly-spacing": [true, "always"], + "object-literal-shorthand": [true], + "object-literal-sort-keys": false, + "one-line": [true, "check-open-brace", "check-whitespace"], + "ordered-imports": [ + true, + { + "grouped-imports": true, + "import-sources-order": "lowercase-last", + "named-imports-order": "lowercase-first" + } + ], + "prefer-for-of": true, + "quotemark": [true, "single", "avoid-escape", "avoid-template"], + "radix": true, + "semicolon": [true, "never"], + "space-before-function-paren": [ + true, + {"anonymous": "always", "named": "never"} + ], + "ter-arrow-spacing": [true, { "before": true, "after": true }], + "ter-func-call-spacing": [true, "never"], + "ter-indent": [true, 2, + { + "SwitchCase": 1 + } + ], + "ter-no-irregular-whitespace": true, + "trailing-comma": [true, + { + "multiline": { + "arrays": "always", + "exports": "always", + "imports": "always", + "functions": "never", + "objects": "always", + "typeLiterals": "always" + }, + "singleline": "never", + "esSpecCompliant": true + } + ], + "triple-equals": true, + "use-isnan": true, + "valid-typeof": true, + "variable-name": [true, "ban-keywords", "allow-leading-underscore"], + "whitespace": { + "options": [true, + "check-branch", + "check-decl", + "check-operator", + "check-module", + "check-separator", + "check-rest-spread", + "check-type", + "check-typecast", + "check-type-operator", + "check-preblock"] + } + } +} diff --git a/framework-ts/yadan/.eslintignore b/framework-ts/yadan/.eslintignore new file mode 100644 index 0000000..3d155ce --- /dev/null +++ b/framework-ts/yadan/.eslintignore @@ -0,0 +1,7 @@ +# /node_modules/* and /bower_components/* ignored by default + +**/*.min.js +.git/* +bin/* +doc/* +src/* diff --git a/framework-ts/yadan/.gitignore b/framework-ts/yadan/.gitignore new file mode 100644 index 0000000..3d21770 --- /dev/null +++ b/framework-ts/yadan/.gitignore @@ -0,0 +1,222 @@ +/*.js +app/**/*.js +test/**/*.js +config/**/*.js +lib/**/*.js +*.map +*.swp +*.bak +*.[oa] +*.md5 +*.d.ts +Thumbs.db +node_modules* +.coveralls.yml +install/ +target/ +build/ +run/ + +dbconfig.json + +!.vscode/settings.json.example +!settings/*.example + + +# for java +bin/ +gen/ +.springBeans/ +workspaces/ +WebRoot/WEB-INF/classes/ +/resource/database.properties +/resource/webserviceConfig.xml +/src/config.properties +.buildpath + + + +# Specifies intentionally untracked files to ignore when using Git +# http://git-scm.com/docs/gitignore + +*~ +*.sw[mnpcod] +*.tmp +*.tmp.* +log.txt +*.sublime-project +*.sublime-workspace +.vscode/ + +.idea/ +.sourcemaps/ +.sass-cache/ +.tmp/ +.versions/ +dist/ +tmp/ +temp/ +hooks/ +platforms/ +plugins/ +plugins/android.json +plugins/ios.json +$RECYCLE.BIN/ + +UserInterfaceState.xcuserstate + + +# files for the dex VM +*.dex + +# for Mac +.DS_Store + +# for C +.lib +.so +.dll + +# Python: +*.py[cod] +*.egg +*.egg-info + +# C#: +[Oo]bj +[Bb]in +*.user +*.suo +*.[Cc]ache +*.ncb +[Tt]humbs.db +Ankh.NoLoad + +*_i.c +*_p.c +*.ilk +*.meta +*.obj +*.pch +*.pdb +*.pgc +*.pgd +*.rsp +*.sbr +*.tlb +*.tli +*.tlh +*.tmp_proj +*.vspscc +*.vssscc +.builds +*.pidb +*.scc + +!.gitkeep + + +# Created by https://www.gitignore.io/api/node + +### Node ### +# Logs +logs +*.log +npm-debug.log* +yarn-debug.log* +yarn-error.log* + +# Runtime data +pids +*.pid +*.seed +*.pid.lock + +# Directory for instrumented libs generated by jscoverage/JSCover +lib-cov + +# Coverage directory used by tools like istanbul +coverage + +# nyc test coverage +.nyc_output + +# node-waf configuration +.lock-wscript + +# Compiled binary addons (http://nodejs.org/api/addons.html) +build/Release + +# Dependency directories +node_modules/ +jspm_packages/ + +# Typescript v1 declaration files +typings/ + +# Optional npm cache directory +.npm + +# Optional eslint cache +.eslintcache + +# Optional REPL history +.node_repl_history + +# Output of 'npm pack' +*.tgz + +# Yarn Integrity file +.yarn-integrity + +# dotenv environment variables file +.env + + +# End of https://www.gitignore.io/api/node + + + +# Eclipse project files +proguard-project.txt +.classpath +.project +.settings +.myeclipse +.apt_generated + +# Proguard folder generated by Eclipse +proguard/ + +# Intellij project files +*.iml +*.ipr +*.iws + +# built application files +*.apk +*.ap_ + + + +# Created by https://www.gitignore.io/api/java + +### Java ### +*.class +*.ctxt + + +# Package Files # +*.jar +*.war +*.ear +*.zip +*.tar.gz +*.rar + +# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml +hs_err_pid* + + +# End of https://www.gitignore.io/api/java + diff --git a/framework-ts/yadan/.npmignore b/framework-ts/yadan/.npmignore new file mode 100644 index 0000000..6b9b19e --- /dev/null +++ b/framework-ts/yadan/.npmignore @@ -0,0 +1,16 @@ +src/ +node_modules/ +node_modules*/ +npm-shrinkwrap.json +tsconfig.json +tslint.json +.eslintignore +.eslintrc.json +.travis.yml +appveyor.yml +*.swp +*.bak +demo/ +test/ +coverage/ +.nyc_output/ diff --git a/framework-ts/yadan/app/service/test.ts b/framework-ts/yadan/app/service/test.ts new file mode 100644 index 0000000..550625c --- /dev/null +++ b/framework-ts/yadan/app/service/test.ts @@ -0,0 +1,24 @@ +import { Context, EggAppConfig, Service } from 'egg' + + +/** + * Test Service + */ +export default class Test extends Service { + config: EggAppConfig + + constructor(ctx: Context) { + super(ctx) + this.config = this.app.config.test + } + + async get(id: number) { + return { id, name: this.config.key } + } +} + +declare module 'egg' { + export interface IService { + test: Test + } +} diff --git a/framework-ts/yadan/config/config.default.ts b/framework-ts/yadan/config/config.default.ts new file mode 100644 index 0000000..83ceb3c --- /dev/null +++ b/framework-ts/yadan/config/config.default.ts @@ -0,0 +1,31 @@ +import { EggAppConfig, PowerPartial } from 'egg'; +import { readFileSync } from 'fs' +import { join } from 'path' + + +// for config.{env}.ts +export type DefaultConfig = PowerPartial; + +export default (appInfo: EggAppConfig) => { + const config = > {} + + /** + * some description + * @member Config#test + * @property {String} key - some description + */ + config.test = { + key: appInfo.name + '_123456', + } + + config.view = { + defaultViewEngine: 'nunjucks', + mapping: { '.tpl': 'nunjucks' }, + } + + config.siteFile = { + '/favicon.ico': readFileSync(join(appInfo.baseDir, 'app/public/favicon.png')), + }; + + return config; +} diff --git a/framework-ts/yadan/config/config.local.ts b/framework-ts/yadan/config/config.local.ts new file mode 100644 index 0000000..79df3f2 --- /dev/null +++ b/framework-ts/yadan/config/config.local.ts @@ -0,0 +1,7 @@ +import { DefaultConfig } from './config.default'; + +export default () => { + const config: DefaultConfig = {}; + + return config; +}; diff --git a/framework-ts/yadan/config/config.prod.ts b/framework-ts/yadan/config/config.prod.ts new file mode 100644 index 0000000..79df3f2 --- /dev/null +++ b/framework-ts/yadan/config/config.prod.ts @@ -0,0 +1,7 @@ +import { DefaultConfig } from './config.default'; + +export default () => { + const config: DefaultConfig = {}; + + return config; +}; diff --git a/framework-ts/yadan/config/plugin.ts b/framework-ts/yadan/config/plugin.ts new file mode 100644 index 0000000..b425d68 --- /dev/null +++ b/framework-ts/yadan/config/plugin.ts @@ -0,0 +1,7 @@ + +export default { + nunjucks: { + enable: true, + package: 'egg-view-nunjucks', + }, +}; diff --git a/framework-ts/yadan/index.ts b/framework-ts/yadan/index.ts new file mode 100644 index 0000000..7354224 --- /dev/null +++ b/framework-ts/yadan/index.ts @@ -0,0 +1,16 @@ +import { BaseContextClass, Controller, EggApplication, Service } from 'egg' + +import Agent from './lib/agent' +import Application from './lib/application' +import startCluster from './lib/cluster' + +export { + Agent, + Application, + startCluster, + + BaseContextClass, + Controller, + EggApplication, + Service, +} diff --git a/framework-ts/yadan/lib/agent.ts b/framework-ts/yadan/lib/agent.ts new file mode 100644 index 0000000..8f07860 --- /dev/null +++ b/framework-ts/yadan/lib/agent.ts @@ -0,0 +1,11 @@ +import { Agent as EggAgent } from 'egg' +import { dirname } from 'path' + + +export const EGG_PATH = Symbol.for('egg#eggPath') + +export default class Agent extends EggAgent { + get [EGG_PATH]() { + return dirname(__dirname) + } +} diff --git a/framework-ts/yadan/lib/application.ts b/framework-ts/yadan/lib/application.ts new file mode 100644 index 0000000..6da25a4 --- /dev/null +++ b/framework-ts/yadan/lib/application.ts @@ -0,0 +1,12 @@ +import { Application as EggApplication } from 'egg' +import { dirname } from 'path' + +export const EGG_PATH = Symbol.for('egg#eggPath') + +export default class Application extends EggApplication { + get [EGG_PATH]() { + return dirname(__dirname) + } +} + + diff --git a/framework-ts/yadan/lib/cluster.ts b/framework-ts/yadan/lib/cluster.ts new file mode 100644 index 0000000..4e00836 --- /dev/null +++ b/framework-ts/yadan/lib/cluster.ts @@ -0,0 +1,48 @@ +import { startCluster, ClusterOptions } from 'egg' + +export interface ClusterOptionsInt extends ClusterOptions { + framework: string + baseDir: string + plugins: object | null + workers: number + port: number + https: boolean + key: string + cert: string + clusterPort: number + title?: string +} + +export interface ClusterMsg { + action: 'egg-ready' | 'egg-pids' + to: 'agent' | 'app' + data?: ClusterOptionsInt | number[] | any + from: 'agent' | 'app' | 'master' +} + +// change window title +process.on('message', (msg: ClusterMsg) => { + if (msg && msg.action) { + const { action, data, from, to } = msg + // let titleNew = data.title ? data.title : data.baseDir + + // process.ppid need node.js v8.10 + // console.info('::message:', process.pid, process.ppid, msg) + console.info('::message:', process.pid, msg) + console.info('::window title:' + process.title) + if (action === 'egg-ready') { + if (to === 'app' && from === 'master') { + console.info('::app worker ready') + } + else if (to === 'agent' && from === 'master') { + console.info('::agent worker ready') + } + } + } +}) + + +export default startCluster +// export default (options: ClusterOptions, cb: (...args: any[]) => any) => { +// return startCluster(options, cb) +// } diff --git a/framework-ts/yadan/package.json b/framework-ts/yadan/package.json new file mode 100644 index 0000000..bb7f2ee --- /dev/null +++ b/framework-ts/yadan/package.json @@ -0,0 +1,37 @@ +{ + "name": "yadan-ts", + "version": "1.0.0", + "dependencies": { + "egg": "^2.7.1", + "egg-view-nunjucks": "^2.1.4" + }, + "devDependencies": { + "@types/cheerio": "^0.22.1", + "@types/mocha": "^5.0.0", + "@types/node": "^9.4.7", + "@types/supertest": "^2.0.0", + "autod": "^3.0.1", + "autod-egg": "^1.1.0", + "cheerio": "^1.0.0-rc.2", + "egg-bin": "^4.7.0", + "egg-ci": "^1.8.0", + "egg-mock": "^3.14.0", + "eslint": "^4.19.0", + "mocha": "^5.0.4", + "rimraf": "^2.6.1", + "tslint": "^5.9.1", + "tslint-eslint-rules": "^5.1.0", + "typescript": "^2.8.1" + }, + "engines": { + "node": ">=8.10.0" + }, + "scripts": { + "clean": "rimraf app/**/*.{js,map} test/**/*.{js,map} config/**/*.{js,map}", + "lint": "tslint --fix -p tsconfig.json -t stylish", + "test": "npm run tsc && egg-bin test", + "test-local": "egg-bin test", + "tsc": "tsc -p tsconfig.json", + "tsc:w": "tsc -p tsconfig.json -w" + } +} diff --git a/framework-ts/yadan/test/lib/framework.test.ts b/framework-ts/yadan/test/lib/framework.test.ts new file mode 100644 index 0000000..d9fe779 --- /dev/null +++ b/framework-ts/yadan/test/lib/framework.test.ts @@ -0,0 +1,42 @@ +/// + +import * as assert from 'assert' +import mm from 'egg-mock' +import * as path from 'path' + + +const key = 'framework-ts-example_123456' + +describe('test/lib/framework.test.ts', () => { + let app + + before(() => { + app = mm.app({ + baseDir: path.join(__dirname, '../../../app'), + framework: path.join(__dirname, '../../'), + }) + return app.ready() + }) + after(() => app.close()) + afterEach(mm.restore) + + it('should GET /', () => { + return app.httpRequest() + .get('/') + .expect(`hi, ${key}`) + .expect(200) + }) + + it('should load config', () => { + assert(app.config.test.key === key) + }) + + it('should load service', async () => { + const ctx = app.mockContext() + const data = await ctx.service.test.get(123) + assert.deepEqual(data, { + id: 123, + name: key, + }) + }) +}) diff --git a/framework-ts/yadan/test/tsconfig.json b/framework-ts/yadan/test/tsconfig.json new file mode 100644 index 0000000..efcbde2 --- /dev/null +++ b/framework-ts/yadan/test/tsconfig.json @@ -0,0 +1,30 @@ +{ + "compilerOptions": { + "alwaysStrict": true, /* Parse in strict mode and emit "use strict" for each source file. */ + "charset": "utf8", + "declaration": false, + "experimentalDecorators": true, + "emitDecoratorMetadata": true, + "importHelpers": true, + "inlineSourceMap": false, + "module": "commonjs", /* 'commonjs', 'amd', 'system', 'umd' or 'es2015'. */ + "newLine": "lf", + "noFallthroughCasesInSwitch": true, + "pretty": true, + "skipLibCheck": true, + "sourceMap": false, + "strict": true, /* Enable all strict type-checking options. */ + "noImplicitAny": false, + "noImplicitThis": false, + "target": "ES2017", /* 'ES5', 'ES2015', 'ES2016', 'ES2017', or 'ESNEXT'. */ + "types" : ["node"] + }, + "include": [ + "**/*.ts" + ], + "exclude": [ + "node_modules", + "**/*.d.ts", + "**/*.spec.ts" + ] +} diff --git a/framework-ts/yadan/tsconfig.json b/framework-ts/yadan/tsconfig.json new file mode 100644 index 0000000..8511d9b --- /dev/null +++ b/framework-ts/yadan/tsconfig.json @@ -0,0 +1,35 @@ +{ + "compilerOptions": { + "alwaysStrict": true, + "charset": "utf8", + "declaration": false, + "experimentalDecorators": true, + "emitDecoratorMetadata": true, + "importHelpers": false, + "inlineSourceMap": true, + "module": "commonjs", + "newLine": "lf", + "noFallthroughCasesInSwitch": true, + "pretty": true, + "skipLibCheck": true, + "strict": true, + "noImplicitAny": false, + "noImplicitThis": false, + "target": "ES2017", + "types" : ["node"] + }, + "include": [ + "./*.ts", + "app/**/*", + "config/**/*", + "test/**/*.ts" + ], + "exclude": [ + "app/public", + "app/views", + "test/", + "node_modules*", + "**/*.d.ts", + "**/*.spec.ts" + ] +} diff --git a/framework-ts/yadan/tslint.json b/framework-ts/yadan/tslint.json new file mode 100644 index 0000000..532fd40 --- /dev/null +++ b/framework-ts/yadan/tslint.json @@ -0,0 +1,151 @@ +{ + "extends": ["tslint:latest", "tslint-eslint-rules"], + "linterOptions": { + "exclude": [ + "node_modules", + "*.d.ts" + ] + }, + "rules": { + "adjacent-overload-signatures": true, + "align": [true, "members", "parameters", "statements"], + "array-bracket-spacing": [true, "never", {"singleValue": false, "objectsInArrays": true, "arraysInArrays": true} ], + "arrow-parens": [true, "ban-single-arg-parens"], + "await-promise": [true, "Thenable"], + "ban-comma-operator": true, + "block-spacing": [true, "always"], + "brace-style": [true, "stroustrup", { "allowSingleLine": true }], + "comment-format": [true, "check-space", {"ignore-words": ["-", "+"]}], + "curly": [true, "ignore-same-line"], + "eofline": true, + "forin": false, + "import-blacklist": [ + true, + "rxjs", + "rxjs/Rx" + ], + "indent": [true, "spaces", 2], + "interface-name": [ false, "never-prefix" ], + "linebreak-style": [true , "LF" ], + "max-classes-per-file": [ true, 10 ], + "max-line-length": [true, 120], + "member-access": [ false ], + "member-ordering": [true, {"order": [ + "public-static-field", + "public-instance-field", + "public-constructor", + "private-static-field", + "private-instance-field", + "private-constructor", + "public-instance-method", + "protected-instance-method", + "private-instance-method" + ]}], + "no-arg": true, + "no-angle-bracket-type-assertion": false, + "no-consecutive-blank-lines": [true, 4], + "no-console": [ true, "dir", "log", "warn" ], + "no-construct": true, + "no-control-regex": true, + "no-duplicate-variable": true, + "no-duplicate-imports": true, + "no-duplicate-switch-case": true, + "no-empty": false, + "no-extra-semi": true, + "no-eval": true, + "no-implicit-dependencies": [true, "dev"], + "no-multi-spaces": [ true, { "exceptions": { "PropertyAssignment": true, "VariableDeclaration": false } } ], + "no-object-literal-type-assertion": false, + "no-parameter-reassignment": false, + "no-return-await": true, + "no-reference": true, + "no-shadowed-variable": [ + true, + { + "class": true, + "enum": true, + "function": true, + "interface": true, + "namespace": true, + "typeAlias": true, + "typeParameter": true + } + ], + "no-string-throw": true, + "no-submodule-imports": [true, + "rxjs", + "@angular/platform-browser", + "source-map-support/register" + ], + "no-trailing-whitespace": [true, "ignore-comments"], + "no-unnecessary-initializer": true, + "no-unused-expression": [true, "allow-fast-null-checks"], + "no-unused-variable": { + "severity": "warning", + "options": [true, { "ignore-pattern": "^_" }] + }, + "no-unnecessary-type-assertion": false, + "no-use-before-declare": true, + "no-var-keyword": true, + "no-var-requires": true, + "object-curly-spacing": [true, "always"], + "object-literal-shorthand": [true], + "object-literal-sort-keys": false, + "one-line": [true, "check-open-brace", "check-whitespace"], + "ordered-imports": [ + true, + { + "grouped-imports": true, + "import-sources-order": "lowercase-last", + "named-imports-order": "lowercase-first" + } + ], + "prefer-for-of": true, + "quotemark": [true, "single", "avoid-escape", "avoid-template"], + "radix": true, + "semicolon": [true, "never"], + "space-before-function-paren": [ + true, + {"anonymous": "always", "named": "never"} + ], + "ter-arrow-spacing": [true, { "before": true, "after": true }], + "ter-func-call-spacing": [true, "never"], + "ter-indent": [true, 2, + { + "SwitchCase": 1 + } + ], + "ter-no-irregular-whitespace": true, + "trailing-comma": [true, + { + "multiline": { + "arrays": "always", + "exports": "always", + "imports": "always", + "functions": "never", + "objects": "always", + "typeLiterals": "always" + }, + "singleline": "never", + "esSpecCompliant": true + } + ], + "triple-equals": true, + "use-isnan": true, + "valid-typeof": true, + "variable-name": [true, "ban-keywords", "allow-leading-underscore"], + "whitespace": { + "options": [true, + "check-branch", + "check-decl", + "check-operator", + "check-module", + "check-separator", + "check-rest-spread", + "check-type", + "check-typecast", + "check-type-operator", + "check-preblock"] + } + } +}