Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

refactor: convert more tests to typescript #5379

Open
wants to merge 17 commits into
base: next
Choose a base branch
from
6 changes: 3 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "egg",
"version": "4.0.0-beta.11",
"version": "4.0.0-beta.12",
"engines": {
"node": ">= 18.19.0"
},
Expand Down Expand Up @@ -46,7 +46,7 @@
"is-type-of": "^2.1.0",
"koa-bodyparser": "^4.4.1",
"koa-override": "^4.0.0",
"onelogger": "^1.0.0",
"onelogger": "^1.0.1",
"performance-ms": "^1.1.0",
"sendmessage": "^3.0.1",
"urllib": "^4.6.11",
Expand Down Expand Up @@ -78,7 +78,7 @@
"formstream": "^1.5.1",
"koa-static": "^5.0.0",
"mm": "^3.4.0",
"pedding": "^1.1.0",
"pedding": "^2.0.1",
"prettier": "^2.7.1",
"rimraf": "6",
"runscript": "^2.0.1",
Expand Down
3 changes: 3 additions & 0 deletions src/app/extend/context.types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,5 +17,8 @@ declare module '@eggjs/core' {
get httpclient(): HttpClient;
get httpClient(): HttpClient;
getLogger(name: string): EggLogger;
get logger(): EggLogger;
get coreLogger(): EggLogger;
get locals(): Record<string, any>;
}
}
3 changes: 3 additions & 0 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,9 @@ export * from './lib/egg.js';
export * from './lib/type.js';
export * from './lib/start.js';

// export errors
export * from './lib/error/index.js';

/**
* Start egg application with cluster mode
* @since 1.0.0
Expand Down
18 changes: 15 additions & 3 deletions src/lib/application.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,15 @@ import { Socket } from 'node:net';
import { graceful } from 'graceful';
import { assign } from 'utility';
import { utils as eggUtils } from '@eggjs/core';
import { isGeneratorFunction } from 'is-type-of';
import {
EggApplicationCore,
type EggApplicationCoreOptions,
type ContextDelegation,
} from './egg.js';
import { AppWorkerLoader } from './loader/index.js';
import Helper from '../app/extend/helper.js';
import { CookieLimitExceedError } from './error/index.js';

const EGG_LOADER = Symbol.for('egg#loader');

Expand Down Expand Up @@ -266,16 +268,26 @@ export class Application extends EggApplicationCore {
return this._keys;
}

/**
* @deprecated keep compatible with egg 3.x
*/
toAsyncFunction(fn: (...args: any[]) => any) {
if (isGeneratorFunction(fn)) {
throw new Error('Generator function is not supported');
}
return fn;
}

/**
* bind app's events
*
* @private
*/
#bindEvents() {
// Browser Cookie Limits: http://browsercookielimits.squawky.net/
// Browser Cookie Limits: http://browsercookielimits.iain.guru/
// https://github.com/eggjs/egg-cookies/blob/58ef4ea497a0eb4dd711d7e9751e56bc5fcee004/src/cookies.ts#L145
this.on('cookieLimitExceed', ({ name, value, ctx }) => {
const err = new Error(`cookie ${name}'s length(${value.length}) exceed the limit(4093)`);
err.name = 'CookieLimitExceedError';
const err = new CookieLimitExceedError(name, value);
ctx.coreLogger.error(err);
});
// expose server to support websocket
Expand Down
2 changes: 1 addition & 1 deletion src/lib/core/base_context_class.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import { BaseContextLogger } from './base_context_logger.js';
*/
export class BaseContextClass extends EggCoreBaseContextClass {
declare ctx: ContextDelegation;
protected pathName?: string;
declare pathName?: string;
#logger?: BaseContextLogger;

get logger() {
Expand Down
4 changes: 2 additions & 2 deletions src/lib/core/base_hook_class.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,14 @@ import type { ILifecycleBoot } from '@eggjs/core';
import type { Application, Agent } from '../../index.js';

export class BaseHookClass implements ILifecycleBoot {
fullPath?: string;
declare fullPath?: string;
#instance: Application | Agent;

constructor(instance: Application | Agent) {
this.#instance = instance;
}

get logger(): any {
get logger() {
return this.#instance.logger;
}

Expand Down
30 changes: 30 additions & 0 deletions src/lib/core/messenger/base.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import { EventEmitter, captureRejectionSymbol } from 'node:events';
import { MessageUnhandledRejectionError } from '../../error/index.js';
import { EggApplicationCore } from '../../egg.js';

export class BaseMessenger extends EventEmitter {
protected readonly egg: EggApplicationCore;

constructor(egg: EggApplicationCore) {
super({ captureRejections: true });
this.egg = egg;
}

[captureRejectionSymbol](err: Error, event: string | symbol, ...args: any[]) {
this.egg.coreLogger.error(new MessageUnhandledRejectionError(err, event, args));
}

emit(eventName: string | symbol, ...args: any[]): boolean {
const hasListeners = this.listenerCount(eventName) > 0;
try {
return super.emit(eventName, ...args);
} catch (e: unknown) {
let err = e as Error;
if (!(err instanceof Error)) {
err = new Error(String(err));
}
this.egg.coreLogger.error(new MessageUnhandledRejectionError(err, eventName, args));
return hasListeners;
}
}
}
3 changes: 2 additions & 1 deletion src/lib/core/messenger/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,8 @@ export type { IMessenger } from './IMessenger.js';
* @class Messenger
*/
export function create(egg: EggApplicationCore): IMessenger {
return egg.options.mode === 'single'
const messenger = egg.options.mode === 'single'
? new LocalMessenger(egg)
: new IPCMessenger(egg);
return messenger;
}
8 changes: 3 additions & 5 deletions src/lib/core/messenger/ipc.ts
Original file line number Diff line number Diff line change
@@ -1,24 +1,22 @@
import { EventEmitter } from 'node:events';
import { debuglog } from 'node:util';
import workerThreads from 'node:worker_threads';
import { sendmessage } from 'sendmessage';
import type { IMessenger } from './IMessenger.js';
import type { EggApplicationCore } from '../../egg.js';
import { BaseMessenger } from './base.js';

const debug = debuglog('egg/lib/core/messenger/ipc');

/**
* Communication between app worker and agent worker by IPC channel
*/
export class Messenger extends EventEmitter implements IMessenger {
export class Messenger extends BaseMessenger implements IMessenger {
readonly pid: string;
readonly egg: EggApplicationCore;
opids: string[] = [];

constructor(egg: EggApplicationCore) {
super();
super(egg);
this.pid = String(process.pid);
this.egg = egg;
// pids of agent or app managed by master
// - retrieve app worker pids when it's an agent worker
// - retrieve agent worker pids when it's an app worker
Expand Down
8 changes: 3 additions & 5 deletions src/lib/core/messenger/local.ts
Original file line number Diff line number Diff line change
@@ -1,20 +1,18 @@
import { debuglog } from 'node:util';
import EventEmitter from 'node:events';
import type { IMessenger } from './IMessenger.js';
import type { EggApplicationCore } from '../../egg.js';
import { BaseMessenger } from './base.js';

const debug = debuglog('egg/lib/core/messenger/local');

/**
* Communication between app worker and agent worker with EventEmitter
*/
export class Messenger extends EventEmitter implements IMessenger {
export class Messenger extends BaseMessenger implements IMessenger {
readonly pid: string;
readonly egg: EggApplicationCore;

constructor(egg: EggApplicationCore) {
super();
this.egg = egg;
super(egg);
this.pid = String(process.pid);
}

Expand Down
4 changes: 2 additions & 2 deletions src/lib/core/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import {
isClass, isFunction, isGeneratorFunction, isAsyncFunction,
} from 'is-type-of';

export function convertObject(obj: any, ignore: string | RegExp | (string | RegExp)[]) {
export function convertObject(obj: any, ignore: string | RegExp | (string | RegExp)[] = []) {
if (!Array.isArray(ignore)) {
ignore = [ ignore ];
}
Expand All @@ -30,7 +30,7 @@ function convertValue(key: string, value: any, ignore: (string | RegExp)[]) {
}
}
if (!hit) {
if (isSymbol(value) || isRegExp(value)) {
if (isSymbol(value) || isRegExp(value) || value instanceof URL) {
return value.toString();
}
if (isPrimitive(value) || Array.isArray(value)) {
Expand Down
4 changes: 4 additions & 0 deletions src/lib/egg.ts
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,8 @@ export class EggApplicationCore extends EggCore {
ContextLogger = ContextLogger;
ContextHttpClient = ContextHttpClient;
HttpClient = HttpClient;
// keep compatible with egg version 3.x
HttpClientNext = HttpClient;
/**
* Retrieve base context class
* @member {BaseContextClass} BaseContextClass
Expand Down Expand Up @@ -132,6 +134,7 @@ export class EggApplicationCore extends EggCore {
/**
* Retrieve base boot
* @member {Boot}
* @alias BaseHookClass
*/
Boot = BaseHookClass;

Expand Down Expand Up @@ -439,6 +442,7 @@ export class EggApplicationCore extends EggCore {
}

_unhandledRejectionHandler(err: any) {
this.coreLogger.error('[egg:unhandledRejection] %s', err && err.message || err);
if (!(err instanceof Error)) {
const newError = new Error(String(err));
// err maybe an object, try to copy the name, message and stack to the new error instance
Expand Down
12 changes: 12 additions & 0 deletions src/lib/error/CookieLimitExceedError.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
export class CookieLimitExceedError extends Error {
key: string;
cookie: string;

constructor(key: string, cookie: string) {
super(`cookie ${key}'s length(${cookie.length}) exceed the limit(4093)`);
this.name = this.constructor.name;
this.key = key;
this.cookie = cookie;
Error.captureStackTrace(this, this.constructor);
}
}
12 changes: 12 additions & 0 deletions src/lib/error/MessageUnhandledRejectionError.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
export class MessageUnhandledRejectionError extends Error {
event: string | symbol;
args: any[];

constructor(err: Error, event: string | symbol, ...args: any[]) {
super(`event: ${String(event)}, error: ${err.message}`, { cause: err });
this.name = this.constructor.name;
this.event = event;
this.args = args;
Error.captureStackTrace(this, this.constructor);
}
}
2 changes: 2 additions & 0 deletions src/lib/error/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export * from './CookieLimitExceedError.js';
export * from './MessageUnhandledRejectionError.js';
8 changes: 5 additions & 3 deletions test/fixtures/apps/agent-throw/agent.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
'use strict';

module.exports = agent => {
agent.messenger.on('agent-throw', () => {
throw new Error('agent error');
throw new Error('agent error in sync function');
});

agent.messenger.on('agent-throw-async', async () => {
throw new Error('agent error in async function');
});

agent.messenger.on('agent-throw-string', () => {
Expand Down
7 changes: 5 additions & 2 deletions test/fixtures/apps/agent-throw/app/router.js
Original file line number Diff line number Diff line change
@@ -1,11 +1,14 @@
'use strict';

module.exports = app => {
app.get('/agent-throw', async function() {
app.messenger.broadcast('agent-throw');
this.body = 'done';
});

app.get('/agent-throw-async', async function() {
app.messenger.broadcast('agent-throw-async');
this.body = 'done';
});

app.get('/agent-throw-string', async function() {
app.messenger.broadcast('agent-throw-string');
this.body = 'done';
Expand Down
2 changes: 0 additions & 2 deletions test/fixtures/apps/app-throw/app/router.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
'use strict';

module.exports = app => {
app.get('/throw', function () {
this.body = 'foo';
Expand Down
6 changes: 2 additions & 4 deletions test/fixtures/apps/base-context-class/app/controller/home.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,7 @@
'use strict';

module.exports = app => {
return class HomeController extends app.Controller {
* show() {
yield this.service.home.show();
async show() {
await this.service.home.show();
this.ctx.body = 'hello';
this.logger.debug('debug');
this.logger.info('appname: %s', this.config.name);
Expand Down
2 changes: 0 additions & 2 deletions test/fixtures/apps/base-context-class/app/router.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
'use strict';

module.exports = app => {
app.get('/', 'home.show');
app.get('/pathName', 'home.getPathName');
Expand Down
4 changes: 1 addition & 3 deletions test/fixtures/apps/base-context-class/app/service/home.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
'use strict';

module.exports = app => {
return class HomeController extends app.Service {
* show() {
async show() {
this.ctx.body = 'hello';
this.logger.debug('debug');
this.logger.info('appname: %s', this.config.name);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1 @@
'use strict';

exports.keys = 'test keys';
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
'use strict';

exports.logger = {
consoleLevel: 'NONE',
};
Loading
Loading