Skip to content

Commit

Permalink
Merge branch 'main' into dev/rtc-parser
Browse files Browse the repository at this point in the history
# Conflicts:
#	src/parsers/iris_api_id_parser.ts
  • Loading branch information
guoxianzhe committed Jan 16, 2024
2 parents ac9ad3f + bcc07c1 commit afe0aa8
Show file tree
Hide file tree
Showing 4 changed files with 45 additions and 130 deletions.
38 changes: 19 additions & 19 deletions src/__tests__/utils/iris_utils.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,9 +44,9 @@ describe('irisApiId', () => {
},
];

let apiType = irisApiId(parseResult, myClass, mf1);
let apiType = irisApiId(myClass, mf1);

expect(apiType).toBe('MYCLASS_MYFUNC_3766a1b9');
expect(apiType).toBe('MYCLASS_MYFUNC_56658dc');
});

it('full api type for overload function with hash code with so long parameter type name', () => {
Expand Down Expand Up @@ -84,9 +84,9 @@ describe('irisApiId', () => {
},
];

let apiType = irisApiId(parseResult, myClass, mf1);
let apiType = irisApiId(myClass, mf1);

expect(apiType).toBe('MYCLASS_MYFUNC_67d36c93');
expect(apiType).toBe('MYCLASS_MYFUNC_026cad0');
});

it('full api type for overload function with hash code, toUpperCase = false', () => {
Expand Down Expand Up @@ -123,9 +123,9 @@ describe('irisApiId', () => {
},
];

let apiType = irisApiId(parseResult, myClass, mf1, { toUpperCase: false });
let apiType = irisApiId(myClass, mf1, { toUpperCase: false });

expect(apiType).toBe('MyClass_MyFunc_3766a1b9');
expect(apiType).toBe('MyClass_MyFunc_56658dc');
});

it('api id for non overload function', () => {
Expand All @@ -148,9 +148,9 @@ describe('irisApiId', () => {
},
];

let apiType = irisApiId(parseResult, myClass, mf);
let apiType = irisApiId(myClass, mf);

expect(apiType).toBe('MYCLASS_MYFUNC');
expect(apiType).toBe('MYCLASS_MYFUNC_56658dc');
});

it('api id for non overload function without class name', () => {
Expand All @@ -173,9 +173,9 @@ describe('irisApiId', () => {
},
];

let apiType = irisApiId(parseResult, myClass, mf, { withClassName: false });
let apiType = irisApiId(myClass, mf, { withClassName: false });

expect(apiType).toBe('MYFUNC');
expect(apiType).toBe('MYFUNC_56658dc');
});

it('api id for non overload function without function name', () => {
Expand All @@ -198,9 +198,9 @@ describe('irisApiId', () => {
},
];

let apiType = irisApiId(parseResult, myClass, mf, { withFuncName: false });
let apiType = irisApiId(myClass, mf, { withFuncName: false });

expect(apiType).toBe('MYCLASS');
expect(apiType).toBe('MYCLASS_56658dc');
});

it('empty api id for non overload function', () => {
Expand All @@ -223,7 +223,7 @@ describe('irisApiId', () => {
},
];

let apiType = irisApiId(parseResult, myClass, mf, {
let apiType = irisApiId(myClass, mf, {
withClassName: false,
withFuncName: false,
});
Expand Down Expand Up @@ -251,9 +251,9 @@ describe('irisApiId', () => {
},
];

let apiType = irisApiId(parseResult, myClass, mf, { toUpperCase: false });
let apiType = irisApiId(myClass, mf, { toUpperCase: false });

expect(apiType).toBe('MyClass_MyFunc');
expect(apiType).toBe('MyClass_MyFunc_56658dc');
});

it('api id trim prefix other prefix', () => {
Expand All @@ -276,12 +276,12 @@ describe('irisApiId', () => {
},
];

let apiType = irisApiId(parseResult, myClass, mf, {
let apiType = irisApiId(myClass, mf, {
toUpperCase: false,
trimPrefix: 'My',
});

expect(apiType).toBe('Class_MyFunc');
expect(apiType).toBe('Class_MyFunc_56658dc');
});

it('api id trim prefix empty', () => {
Expand All @@ -304,11 +304,11 @@ describe('irisApiId', () => {
},
];

let apiType = irisApiId(parseResult, myClass, mf, {
let apiType = irisApiId(myClass, mf, {
toUpperCase: false,
trimPrefix: '',
});

expect(apiType).toBe('MyClass_MyFunc');
expect(apiType).toBe('MyClass_MyFunc_56658dc');
});
});
50 changes: 6 additions & 44 deletions src/parsers/iris_api_id_parser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,25 +5,10 @@ import {
Clazz,
MemberFunction,
} from '@agoraio-extensions/cxx-parser';
import {
ParseResult,
TerraContext,
resolvePath,
} from '@agoraio-extensions/terra-core';
import { ParseResult, TerraContext } from '@agoraio-extensions/terra-core';

import { irisApiId } from '../utils/iris_utils';

export const defaultFuncNeedCheckWithBaseClasses = [
'agora::media::IAudioFrameObserver',
'agora::rtc::IRtcEngineEventHandlerEx',
];
function isNeedCheckWithBaseClasses(
clazz: Clazz,
funcNeedCheckWithBaseClasses: string[]
): boolean {
return funcNeedCheckWithBaseClasses.includes(clazz.fullName);
}

export interface IrisApiIdParserArgs {
configPath: string;
}
Expand All @@ -37,29 +22,13 @@ export function IrisApiIdParser(
args: IrisApiIdParserArgs,
preParseResult?: ParseResult
): ParseResult | undefined {
let funcNeedCheckWithBaseClasses: string[];
if (args && args.configPath) {
let configPath = resolvePath(args.configPath, terraContext.configDir);
funcNeedCheckWithBaseClasses = require(configPath) as string[];
} else {
funcNeedCheckWithBaseClasses = defaultFuncNeedCheckWithBaseClasses;
}
let cxxFiles = preParseResult?.nodes as CXXFile[];
cxxFiles?.forEach((cxxFile: CXXFile) => {
cxxFile.nodes.forEach((node) => {
if (node.__TYPE == CXXTYPE.Clazz) {
let clazz = node as Clazz;
let needCheckWithBaseClasses = isNeedCheckWithBaseClasses(
clazz,
funcNeedCheckWithBaseClasses
);
clazz.methods.forEach((method) => {
applyIrisApiId(
preParseResult!,
clazz,
method,
needCheckWithBaseClasses
);
applyIrisApiId(clazz, method);
});
}
});
Expand All @@ -68,22 +37,15 @@ export function IrisApiIdParser(
return preParseResult;
}

export function applyIrisApiId(
parseResult: ParseResult,
clazz: Clazz,
method: MemberFunction,
includeBaseClassMethods: boolean = false
) {
export function applyIrisApiId(clazz: Clazz, method: MemberFunction) {
method.user_data ??= {};
(method.user_data as IrisApiIdParserUserData).IrisApiIdParser = {
key: irisApiId(parseResult, clazz, method, {
(method.user_data as IrisApiIdParserUserData).IrisApiIdParser = {
key: irisApiId(clazz, method, {
trimPrefix: '',
toUpperCase: true,
includeBaseClassMethods: includeBaseClassMethods,
}),
value: irisApiId(parseResult, clazz, method, {
value: irisApiId(clazz, method, {
toUpperCase: false,
includeBaseClassMethods: includeBaseClassMethods,
}),
};
}
Expand Down
10 changes: 5 additions & 5 deletions src/parsers/merge_node_parser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -89,12 +89,12 @@ export function MergeNodeParser(

return it;
});
}

// Re-apply the iris api id after merging.
targetClazz!.asClazz().methods.forEach((it) => {
applyIrisApiId(preParseResult, targetClazz!.asClazz(), it);
});
// Re-apply the iris api id after merging.
targetClazz!.asClazz().methods.forEach((it) => {
applyIrisApiId(targetClazz!.asClazz(), it);
});
}
}
}
}
Expand Down
77 changes: 15 additions & 62 deletions src/utils/iris_utils.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import crypto from 'crypto';

import { Clazz, MemberFunction } from '@agoraio-extensions/cxx-parser';
import { ParseResult } from '@agoraio-extensions/terra-core';

/**
* Generates an API type schema for a given class and member function.
Expand All @@ -15,64 +16,22 @@ import { ParseResult } from '@agoraio-extensions/terra-core';
* @returns The generated API type schema.
*/
export function irisApiId(
parseResult: ParseResult,
clazz: Clazz,
mf: MemberFunction,
options?: {
withClassName?: boolean;
withFuncName?: boolean;
toUpperCase?: boolean;
trimPrefix?: string; // default is "I"
includeBaseClassMethods?: boolean;
}
): string {
// Borrow from https://stackoverflow.com/questions/7616461/generate-a-hash-from-string-in-javascript
function _stringHashCode(source: string): number {
let length = source.length;
let hash = 0,
i,
chr;
if (length === 0) return hash;
for (i = 0; i < length; i++) {
chr = source.charCodeAt(i);
hash = (hash << 5) - hash + chr;
hash |= 0; // Convert to 32bit integer
}
return hash;
}

function _isOverload(
cls: Clazz,
f: MemberFunction,
includeBaseClassMethods: boolean
): boolean {
let allMethods = cls.methods ?? [];
if (includeBaseClassMethods) {
let baseClassMethods = cls.base_clazzs
.map((it) => {
return parseResult.resolveNodeByName(it);
})
.flatMap((it) => {
return it?.asClazz()?.methods ?? [];
})
.filter((it) => !it.is_overriding); // filter out overriding methods

allMethods = [...baseClassMethods, ...allMethods];

let visitedMethods: Set<string> = new Set();
allMethods = allMethods.filter((it) => {
let funcSig = `${it.name}(${it.parameters
.map((param) => param.type.source)
.join(',')})`;
if (visitedMethods.has(funcSig)) {
return false;
}
visitedMethods.add(funcSig);
return true;
});
function _stringHashCode(source: string): string {
if (source.length == 0) {
return '';
}

return allMethods.filter((m) => m.name === f.name).length > 1;
const fullHash = crypto.createHash('sha1').update(source).digest('hex');
return fullHash.substring(0, 7);
}

const seperator = '__';
Expand All @@ -82,7 +41,6 @@ export function irisApiId(
let withClassName = options?.withClassName ?? true;
let withFuncName = options?.withFuncName ?? true;
let trimPrefix = options?.trimPrefix ?? 'I';
let includeBaseClassMethods = options?.includeBaseClassMethods ?? false;

let cn = clazz.name.trimNamespace();
let mn = mf.name;
Expand All @@ -93,7 +51,6 @@ export function irisApiId(
}

let output = '';
let isOverload = _isOverload(clazz, mf, includeBaseClassMethods);
// We use single one underscore `shortSeperator` for display purpose
// <Class Name [Uppercase]>_<Function Name [Uppercase]>[_<Full API Type Hash Code>]
if (withClassName) {
Expand All @@ -107,20 +64,16 @@ export function irisApiId(
output = `${output}${mn}`;
}

if (isOverload) {
let ps = mf.parameters
.map((param) => {
return param.type.source;
})
.join(seperator);
let ps = mf.parameters
.map((param) => {
return param.type.source;
})
.join(seperator);

// <Class Name>__<Function Name>__<Param Type1>__<Param Type2>__<...>
let apiType = `${clazz.name.trimNamespace()}${seperator}${
mf.name
}${seperator}${ps}`;
// Convert to hex string, and remove the negative `-`.
let hc = _stringHashCode(apiType).toString(16).replace('-', '');
let apiType = ps;
let hc = apiType.length > 0 ? _stringHashCode(apiType) : '';

if (hc.length && (withClassName || withFuncName)) {
output = `${output}${shortSeperator}${hc}`;
}

Expand Down

0 comments on commit afe0aa8

Please sign in to comment.