diff --git a/hackernews-async-ts/.autod.conf.js b/hackernews-async-ts/.autod.conf.js index 4d1fb4a..96fdfa1 100644 --- a/hackernews-async-ts/.autod.conf.js +++ b/hackernews-async-ts/.autod.conf.js @@ -10,6 +10,10 @@ module.exports = { ], dep: [ 'egg', + 'egg-scripts', + 'egg-view-nunjucks', + 'moment', + 'source-map-support', ], devdep: [ 'autod', diff --git a/hackernews-async-ts/.gitignore b/hackernews-async-ts/.gitignore index faf57fa..59af3eb 100644 --- a/hackernews-async-ts/.gitignore +++ b/hackernews-async-ts/.gitignore @@ -1,71 +1,19 @@ +logs/ +npm-debug.log +node_modules/ +coverage/ +.idea/ +run/ +logs/ +.DS_Store +.vscode +*.swp +*.lock +*.js + app/**/*.js test/**/*.js config/**/*.js -*.map -run -logs - -# 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 - -# Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) -.grunt - -# Bower dependency directory (https://bower.io/) -bower_components - -# node-waf configuration -.lock-wscript - -# Compiled binary addons (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 +app/**/*.map +test/**/*.map +config/**/*.map \ No newline at end of file diff --git a/hackernews-async-ts/.vscode/settings.json b/hackernews-async-ts/.vscode/settings.json index db221e0..25fa621 100644 --- a/hackernews-async-ts/.vscode/settings.json +++ b/hackernews-async-ts/.vscode/settings.json @@ -1,13 +1,3 @@ { - "files.exclude": { - "USE_GITIGNORE": true, - "**/*.js": { - "when": "$(basename).ts" - }, - "**/*.map": true, - "run": true, - "logs": true, - "out": true, - "node_modules": true - } + "typescript.tsdk": "node_modules/typescript/lib" } diff --git a/hackernews-async-ts/app/controller/index.d.ts b/hackernews-async-ts/app/controller/index.d.ts deleted file mode 100644 index 0b8bebb..0000000 --- a/hackernews-async-ts/app/controller/index.d.ts +++ /dev/null @@ -1,6 +0,0 @@ -import NewsController from './news'; -declare module 'egg' { - export interface IController { - news: NewsController; - } -} diff --git a/hackernews-async-ts/app/router.ts b/hackernews-async-ts/app/router.ts index 4d5d311..50a9d49 100644 --- a/hackernews-async-ts/app/router.ts +++ b/hackernews-async-ts/app/router.ts @@ -1,9 +1,10 @@ import { Application } from 'egg'; export default (app: Application) => { - const controller = app.controller; - app.redirect('/', '/news'); - app.router.get('/news', controller.news.list); - app.router.get('/news/item/:id', controller.news.detail); - app.router.get('/news/user/:id', controller.news.user); + const { controller, router } = app; + + // router.redirect('/', '/news'); + router.get('/news', controller.news.list); + router.get('/news/item/:id', controller.news.detail); + router.get('/news/user/:id', controller.news.user); }; diff --git a/hackernews-async-ts/app/service/HackerNews.ts b/hackernews-async-ts/app/service/HackerNews.ts index 290b8b9..8076c74 100644 --- a/hackernews-async-ts/app/service/HackerNews.ts +++ b/hackernews-async-ts/app/service/HackerNews.ts @@ -1,4 +1,4 @@ -import { Context, Service } from 'egg'; +import { Service } from 'egg'; export interface NewsItem { id: number; @@ -16,13 +16,6 @@ export interface NewsItem { * HackerNews Api Service */ export class HackerNews extends Service { - constructor(ctx: Context) { - super(ctx); - } - getConfig() { - return this.app.config.news; - } - /** * request hacker-news api * @param api - Api name @@ -34,7 +27,7 @@ export class HackerNews extends Service { timeout: ['30s', '30s'], }, opts); - const result = await this.ctx.curl(`${this.getConfig().serverUrl}/${api}`, options); + const result = await this.ctx.curl(`${this.config.news.serverUrl}/${api}`, options); return result.data; } @@ -45,7 +38,7 @@ export class HackerNews extends Service { */ public async getTopStories(page?: number, pageSize?: number): Promise { page = page || 1; - pageSize = pageSize || this.getConfig().pageSize; + pageSize = pageSize || this.config.news.pageSize; try { const result = await this.request('topstories.json', { diff --git a/hackernews-async-ts/app/service/index.d.ts b/hackernews-async-ts/app/service/index.d.ts deleted file mode 100644 index 95157d8..0000000 --- a/hackernews-async-ts/app/service/index.d.ts +++ /dev/null @@ -1,6 +0,0 @@ -import HackerNews from './HackerNews'; -declare module 'egg' { - export interface IService { - hackerNews: HackerNews; - } -} diff --git a/hackernews-async-ts/config/config.default.ts b/hackernews-async-ts/config/config.default.ts new file mode 100644 index 0000000..828e65d --- /dev/null +++ b/hackernews-async-ts/config/config.default.ts @@ -0,0 +1,32 @@ +'use strict'; +import { EggAppConfig } from 'egg'; +import * as fs from 'fs'; +import * as path from 'path'; + +export default (appInfo: EggAppConfig) => { + return { + keys: appInfo.name + '123456', + siteFile: { + '/favicon.ico': fs.readFileSync( + path.join(appInfo.baseDir, 'app/public/favicon.png'), + ), + }, + view: { + defaultViewEngine: 'nunjucks', + mapping: { + '.tpl': 'nunjucks', + }, + }, + news: { + /** + * page size + */ + pageSize: 30, + + /** + * hacker news server url + */ + serverUrl: 'https://hacker-news.firebaseio.com/v0', + }, + }; +}; diff --git a/hackernews-async-ts/config/config.local.ts b/hackernews-async-ts/config/config.local.ts new file mode 100644 index 0000000..2138d55 --- /dev/null +++ b/hackernews-async-ts/config/config.local.ts @@ -0,0 +1,3 @@ +export const info = { + msg: 'hello', +}; diff --git a/hackernews-async-ts/config/config.prod.ts b/hackernews-async-ts/config/config.prod.ts new file mode 100644 index 0000000..46e1878 --- /dev/null +++ b/hackernews-async-ts/config/config.prod.ts @@ -0,0 +1,5 @@ +export default { + info: { + msg: 'hello', + }, +}; diff --git a/hackernews-async-ts/config/config.ts b/hackernews-async-ts/config/config.ts deleted file mode 100644 index f15ec1c..0000000 --- a/hackernews-async-ts/config/config.ts +++ /dev/null @@ -1,26 +0,0 @@ -'use strict'; -import { EggAppConfig } from 'egg'; -import * as fs from 'fs'; -import * as path from 'path'; -import 'source-map-support/register'; -import defaultConfig from './defaultConfig'; - -export default (appInfo: EggAppConfig) => { - const config: any = {}; - - // should change to your own - config.keys = appInfo.name + '123456'; - - config.siteFile = { - '/favicon.ico': fs.readFileSync(path.join(appInfo.baseDir, 'app/public/favicon.png')), - }; - - config.view = { - defaultViewEngine: 'nunjucks', - mapping: { - '.tpl': 'nunjucks', - }, - }; - - return { ...config, ...defaultConfig }; -}; diff --git a/hackernews-async-ts/config/defaultConfig.ts b/hackernews-async-ts/config/defaultConfig.ts deleted file mode 100644 index e6279b5..0000000 --- a/hackernews-async-ts/config/defaultConfig.ts +++ /dev/null @@ -1,14 +0,0 @@ -export class DefaultConfig { - news = { - pageSize: 30, - serverUrl: 'https://hacker-news.firebaseio.com/v0', - }; -}; - -export default new DefaultConfig(); - -declare module 'egg' { - export interface Application { - config: EggAppConfig & DefaultConfig; - } -} diff --git a/hackernews-async-ts/config/index.d.ts b/hackernews-async-ts/config/index.d.ts new file mode 100644 index 0000000..f105b89 --- /dev/null +++ b/hackernews-async-ts/config/index.d.ts @@ -0,0 +1,23 @@ +import { EggAppConfig } from 'egg'; +import defaultConfig from './config.default'; +import * as localConfig from './config.local'; +import prodConfig from './config.prod'; + +type DefaultConfig = ReturnType; +type LocalConfig = typeof localConfig; +type ProdConfig = typeof prodConfig; +type NewAppConfig = EggAppConfig & DefaultConfig & LocalConfig & ProdConfig; + +declare module 'egg' { + interface Application { + config: NewAppConfig; + } + + interface Controller { + config: NewAppConfig; + } + + interface Service { + config: NewAppConfig; + } +} \ No newline at end of file diff --git a/hackernews-async-ts/package.json b/hackernews-async-ts/package.json index 45ef869..e811bf9 100644 --- a/hackernews-async-ts/package.json +++ b/hackernews-async-ts/package.json @@ -3,13 +3,15 @@ "version": "1.0.0", "description": "hackernews showcase using async/await for egg", "private": true, + "egg": { + "typescript": true + }, "dependencies": { - "egg": "^2.0.0", - "egg-view-nunjucks": "^2.1.4", - "moment": "^2.19.4", - "source-map-support": "^0.5.0", - "tslib": "^1.8.1", - "typescript": "^2.6.2" + "egg": "^2.5.0", + "egg-scripts": "^2.5.1", + "egg-view-nunjucks": "^2.2.0", + "moment": "^2.21.0", + "source-map-support": "^0.5.4" }, "devDependencies": { "@types/cheerio": "^0.22.1", @@ -19,25 +21,28 @@ "autod": "^3.0.1", "autod-egg": "^1.1.0", "cheerio": "^1.0.0-rc.2", - "egg-bin": "^4.3.7", - "egg-mock": "^3.14.0", + "egg-bin": "^4.6.0", + "egg-mock": "^3.16.0", + "egg-ts-helper": "^1.1.3", "rimraf": "^2.6.1", - "tslint": "^4.0.0" + "tslib": "^1.8.1", + "tslint": "^4.0.0", + "typescript": "^2.8.1" }, "engines": { "node": ">=8.9.0" }, "scripts": { - "clean": "rimraf app/**/*.{js,map} test/**/*.{js,map} config/**/*.{js,map}", - "tsc": "tsc -p tsconfig.json", - "tsc:w": "tsc -p tsconfig.json -w", - "debug": "egg-bin debug", - "dev": "egg-bin dev", - "test": "npm run tsc && npm run test-local", - "test-local": "egg-bin test", + "start": "egg-scripts start", + "dev": "egg-bin dev -r 'egg-ts-helper/register'", + "tsc": "ets && tsc -p tsconfig.json", + "clean": "ets clean", + "test": "npm run lint -- --fix && npm run test-local", + "test-local": "egg-bin test -r 'egg-ts-helper/register'", "cov": "egg-bin cov", "lint": "tslint .", "ci": "npm run lint && npm run cov", + "debug": "egg-bin debug", "autod": "autod" } } diff --git a/hackernews-async-ts/test/app/controller/news.test.ts b/hackernews-async-ts/test/app/controller/news.test.ts index df93b56..49574dd 100644 --- a/hackernews-async-ts/test/app/controller/news.test.ts +++ b/hackernews-async-ts/test/app/controller/news.test.ts @@ -1,19 +1,9 @@ 'use strict'; -import * as assert from 'assert'; import * as cheerio from 'cheerio'; -import mm from 'egg-mock'; +import { app, assert } from 'egg-mock/bootstrap'; describe('test/app/controller/news.test.ts', () => { - const app = mm.app(); - before(async () => { - await app.ready(); - }); - - after(() => app.close()); - - afterEach(mm.restore); - it('should GET /news', async () => { const result = await app.httpRequest().get('/news').expect(200); const $ = cheerio.load(result.text); diff --git a/hackernews-async-ts/test/app/service/HackerNews.test.ts b/hackernews-async-ts/test/app/service/HackerNews.test.ts index 539317a..2d6bf27 100644 --- a/hackernews-async-ts/test/app/service/HackerNews.test.ts +++ b/hackernews-async-ts/test/app/service/HackerNews.test.ts @@ -1,21 +1,15 @@ 'use strict'; -import * as assert from 'assert'; import { Context } from 'egg'; -import mm from 'egg-mock'; +import { app, assert } from 'egg-mock/bootstrap'; describe('test/app/service/HackerNews.test.js', () => { - const app = mm.app(); let ctx: Context; before(async () => { - await app.ready(); ctx = app.mockContext(); }); - after(() => app.close()); - afterEach(mm.restore); - it('getTopStories', async () => { const list = await ctx.service.hackerNews.getTopStories(); assert(list.length === 30); diff --git a/hackernews-async-ts/tsconfig.json b/hackernews-async-ts/tsconfig.json index 05d10e4..4e4f7d9 100644 --- a/hackernews-async-ts/tsconfig.json +++ b/hackernews-async-ts/tsconfig.json @@ -3,6 +3,7 @@ "compilerOptions": { "target": "es2017", "module": "commonjs", + "strict": true, "noImplicitAny": false, "experimentalDecorators": true, "emitDecoratorMetadata": true, @@ -14,17 +15,13 @@ "noUnusedParameters": true, "allowUnreachableCode": false, "allowUnusedLabels": false, + "strictPropertyInitialization": false, "noFallthroughCasesInSwitch": true, "skipLibCheck": true, "skipDefaultLibCheck": true, "inlineSourceMap": true, "importHelpers": true }, - "include": [ - "app/**/*", - "config/**/*", - "test/**/*.ts" - ], "exclude": [ "app/public", "app/views" diff --git a/hackernews-async-ts/typings/app/controller/index.d.ts b/hackernews-async-ts/typings/app/controller/index.d.ts new file mode 100644 index 0000000..d8d65c3 --- /dev/null +++ b/hackernews-async-ts/typings/app/controller/index.d.ts @@ -0,0 +1,10 @@ +// This file was auto created by egg-ts-helper +// Do not modify this file!!!!!!!!! + +import News from '../../../app/controller/news'; + +declare module 'egg' { + interface IController { + news: News; + } +} diff --git a/hackernews-async-ts/typings/app/service/index.d.ts b/hackernews-async-ts/typings/app/service/index.d.ts new file mode 100644 index 0000000..d51448b --- /dev/null +++ b/hackernews-async-ts/typings/app/service/index.d.ts @@ -0,0 +1,10 @@ +// This file was auto created by egg-ts-helper +// Do not modify this file!!!!!!!!! + +import HackerNews from '../../../app/service/HackerNews'; + +declare module 'egg' { + interface IService { + hackerNews: HackerNews; + } +}