Intellisense JSDoc for Mixins and/or Factory Functions - intellisense

My Problem
I'm currently using Visual Code Studio, the lastest version. I'm trying to get the intellisense to show up for the methods on the instance created by a factory function. The methods are going to be applied via object composition (so added directly as properties on the object).
so the function that acts as a constructore basically returns:
function makeWrappedObj() {
var obj = { /* random data */ }; // Then add methods to obj
Object.keys(methods).forEach(key => a[key] = methods[key]; );
return obj;
}
var methods = {
/**
* Yay documentation
* #returns {Object}
*/
method1: function() { return null; }
};
var instance = makeWrappedObj();
instance.method1( // What documentation to show up here
instance. // and here
Is the basic idea. Here's someone doing something similar. I'll address that in the third possible solution.
Solutions I've tried
1) #class on makeWrappedObj I think only works if you attach methods on to makeWrappedObj.prototype which is not what I'm doing so that doesn't work. Unless I'm misunderstanding something.
2) #namespace solution
/* #namespace ClassName */
/* #returns {ClassName}
function createWrappedObj() {
var obj = { /* random data */ }; // Then add methods to obj
Object.keys(methods).forEach(key => a[key] = methods[key]; );
return obj;
}
var methods = {
/**
* Currently the soultion I'm using
* #memberof ClassName
* #param {number} a
**/
method1: function (a) {}
};
var instance = makeWrapperObj();
instance.method1( // Only shows documentation here
So this sort of works. The two problems are that:
methods on instances only get documentation when you type out the full instance.method( and not in the instance. case--not really a big deal
if you have a method name that is the same as an in-built function, eg. toString, instance.toString( will block any documentation you have from showing and show the native toString default documentation instaed.
3) #typedef like the link above.
/** Can be placed anywhere
* #typedef {ClassName}
* #property {function} method1
* dunno how to document arguments with this method
* but it gets the intellisense menu to pop up for "instance." after dot
*/
/* #returns {ClassName} */
function createdWrappedObject() {
var obj = { /* random data */ }; // Then add methods to obj
Object.keys(methods).forEach(key => a[key] = methods[key]; );
return obj;
}
var methods = {
method1: function (a) {}
};
var instance = makeWrappedObj();
instance. // Yay
instance.method1( // Doesn't work
Has the benefit of showing up when one types instance. however has a few disadvantages
Do not know how to specify arguments passed to method1. Maybe it's not possible.
#typedef requires all documentations to be specified in its own comment block. So I have to be redundant between specific documentation on the methods and the typedef
loses the docummentation once you write out the entire method up until the open paren. Sort of workable...
Note: I am willing to just assign all the methods manually one by one instead of doing a foreach on all the keys of the methods mixin.
Also I do not know how to specify the parameters for a function passed as a. This should be possible since Array.map( specifies three arguments for its function call.
The goal is to get documentation when someone imports this as a library with require, or just includes it as a library in browser side script.

Related

What parameter should I feed to Frida `ObjC.api.class_addMethod()` to make it happy?

I want to use Frida to add a class method to the existing Objective C class on Mac OS. After I read the Frida docs, I tried the following code:
const NSString = ObjC.classes.NSString
function func (n) { console.log(n) }
var nativeCb = new NativeCallback(func, 'void', ['int'])
ObjC.api.class_addMethod(
NSString.handle,
ObjC.selector('onTest:'),
nativeCb,
ObjC.api.method_getTypeEncoding(nativeCb)
)
The above code looks straightforward. However, after the ObjC.api.class_addMethod() call, the attached App and the Frida REPL both froze, it looks that the pointers are not right.
I have tried many possible parameter values for a whole night but still can figure the problem out. What's wrong with my code?
Only two issues:
method_getTypeEncoding() can only be called on a Method, which the NativeCallback is not. You could pass it the handle of an existing Objective-C method that has the same signature as the one you're adding, or use Memory.allocUtf8String() to specify your own signature from scratch.
Objective-C methods, at the C ABI level, have two implicit arguments preceding the method's arguments. These are:
self: The class/instance the method is being invoked on.
_cmd: The selector.
Here's a complete example in TypeScript:
const { NSAutoreleasePool, NSString } = ObjC.classes;
const onTest = new NativeCallback(onTestImpl, "void", ["pointer", "pointer", "int"]);
function onTestImpl(selfHandle: NativePointer, cmd: NativePointer, n: number): void {
const self = new ObjC.Object(selfHandle);
console.log(`-[NSString onTestImpl]\n\tself="${self.toString()}"\n\tn=${n}`);
}
function register(): void {
ObjC.api.class_addMethod(
NSString,
ObjC.selector("onTest:"),
onTest,
Memory.allocUtf8String("v#:i"));
}
function test(): void {
const pool = NSAutoreleasePool.alloc().init();
try {
const s = NSString.stringWithUTF8String_(Memory.allocUtf8String("yo"));
s.onTest_(42);
} finally {
pool.release();
}
}
function exposeToRepl(): void {
const g = global as any;
g.register = register;
g.test = test;
}
exposeToRepl();
You can paste it into https://github.com/oleavr/frida-agent-example, and then with one terminal running npm run watch you can load it into a running app using the REPL: frida -n Telegram -l _agent.js. From the REPL you can then call register() to plug in the new method, and test() to take it for a spin.

C API with structures in Swift - immutable value as inout argument

I'm working on a Swift 3 project that involves using some C APIs that I bridged from Objective-C.
Here is a sample snippet of the structure of the API:
typedef struct
{
StructMode mode;
StructLevel level;
} TargetStruct;
typedef struct
{
. . .
TargetStruct *targetStruct;
OtherStruct *otherStruct;
NonPointerStructA nonPointerStructA;
NonPointerStructB nonPointerStructB;
. . .
} InnerStruct;
typedef struct
{
InnerStruct innerStruct;
OtherStructB otherStructB;
} OuterStruct;
In my Swift code, my goal is to set a value of the TargetStruct from the OuterStruct, like the following:
// run function that returns an instance of TargetStruct
var targetStruct: TargetStruct = initializeTargetStruct()
// assign targetStruct to outerStruct
outerStruct.innerStruct.targetStruct = &targetStruct
However, I am getting the following error:
Cannot pass immutable value of TargetStruct as inout argument
If I set a value of a struct without the *, it will work fine:
var nonPointerStructA: NonPointerStructA = initializeNonPointerStructA()
outerStruct.innerStruct.nonPointerStructA = nonPointerStructA
I have tried setting the value of targetStruct like this, but for now I have no way to test it:
var targetStruct: TargetStruct = initializeTargetStruct()
outerStruct.innerStruct.targetStruct.initialize(from: &targetStruct, count: 0)
How to solve this problem? Thank you.
In Swift, prefix & is not an address-of operator. It is just needed to clarify that some expression is passed to an inout parameter. So, your first code is syntactically invalid in Swift.
Your C-structs are imported to Swift as follows:
struct TargetStruct {
var mode: StructMode
var level: StructLevel
//some auto generated initializers...
}
struct InnerStruct {
//...
var targetStruct: UnsafeMutablePointer<TargetStruct>!
var otherStruct: UnsafeMutablePointer<OtherStruct>!
var nonPointerStructA: NonPointerStructA
var nonPointerStructB: NonPointerStructB
//some auto generated initializers...
}
struct OuterStruct {
var innerStruct: InnerStruct
var otherStructB: OtherStructB
//some auto generated initializers...
}
(If something wrong, please tell me.)
As you see, targetStruct in your InnerStruct is a pointer, and initialize(from:count:) tries to write to the pointed region, but at the time you call initialize(from:count:), targetStruct holds its initial value nil, you know what happens when dereferencing null-pointer.
One way is to allocate a memory for the TargetStruct and use the pointer to the allocated region.
func allocateAndInitializeTargetStruct() -> UnsafeMutablePointer<TargetStruct> {
let targetStructRef = UnsafeMutablePointer<TargetStruct>.allocate(capacity: 1)
targetStructRef.initialize(to: initializeTargetStruct())
return targetStructRef
}
outerStruct.innerStruct.targetStruct = allocateAndInitializeTargetStruct()
This is a more general way than below, but you need to explicitly deinitialize and deallocate the allocated region. That's sort of hard to manage.
If you can confine the usage of the outerStruct in a single code-block, you can write something like this:
var targetStruct = initializeTargetStruct()
withUnsafeMutablePointer(to: &targetStruct) {targetStructPtr in
outerStruct.innerStruct.targetStruct = targetStructPtr
//Use `outerStruct` only inside this code-block
//...
}
In this case, the pointer held in outerStruct.innerStruct.targetStruct (== targetStructPtr) is only valid inside the closure and you cannot use it outside of it.
If any of the codes above does not fit for your use case, you may need to provide more context to find the best solution.
An example of nested use of withUnsafeMutablePointer(to:_:):
var targetStruct = initializeTargetStruct()
var otherStruct = initializeOtherStruct()
withUnsafeMutablePointer(to: &targetStruct) {targetStructPtr in
withUnsafeMutablePointer(to: &otherStruct) {otherStructPtr in
outerStruct.innerStruct.targetStruct = targetStructPtr
outerStruct.innerStruct.otherStruct = otherStructPtr
//Use `outerStruct` only inside this code-block
//...
}
}
When you need more pointers to set, this nesting would be a mess, but it's the current limitation of Swift.
An example of deinitialize and deallocate:
extension InnerStruct {
func freeMemberStructs() {
if let targetStructRef = targetStruct {
targetStructRef.deinitialize()
targetStructRef.deallocate(capacity: 1)
targetStruct = nil
}
if let otherStructRef = otherStruct {
otherStructRef.deinitialize()
otherStructRef.deallocate(capacity: 1)
otherStruct = nil
}
}
}
outerStruct.innerStruct.targetStruct = allocateAndInitializeTargetStruct()
outerStruct.innerStruct.otherStruct = allocateAndInitializeOtherStruct()
// Use `outerStruct`
//...
outerStruct.innerStruct.freeMemberStructs()
The code may not seem to be too complex (just a bunch of boilerplate codes), but it's hard to find when or where to do it. As your InnerStruct may be embedded in another struct which may need to be deinitilized and deallocated...
Hope you can find your best solution.

what does `args.unshift(this)` do in Vue's use.js?

I am reading vuejs source code, and got confused by these two lines of code:
const args = toArray(arguments, 1)
args.unshift(this)
in the following snippet, why bother do this ?
/* #flow */
import { toArray } from '../util/index'
export function initUse (Vue: GlobalAPI) {
Vue.use = function (plugin: Function | Object) {
/* istanbul ignore if */
if (plugin.installed) {
return
}
// additional parameters
const args = toArray(arguments, 1)
args.unshift(this)
if (typeof plugin.install === 'function') {
plugin.install.apply(plugin, args)
} else {
plugin.apply(null, args)
}
plugin.installed = true
return this
}
}
Since you are inside of a Vueinstance, the lines in question are in the function defined on Vue.use the this most likely will reference the current Vue instance.
You will have to browse the source of toArray to understand the first line, it might takes the arguments and returning an array from them, and maybe substracting the first argument (the 1 in toArray(arguments, 1) give me this impression but to be sure browse the source of that function).
But then when the call args.unshift(this)comes it puts the Vue instance as the first element of the args array which is then used to provide arguments to the plugin function.
Hope that helps ;-)
Seb

How to address internal module when a name conflict exists in TypeScript

In my TypeScript project (using only internal modules), I want to include polyfills/extension for an existing library. For this example, I will use the RxJS library but the question/problem is not specific to this library.
The following code is what I came up with:
module MyModule.Rx {
Rx.Observable.prototype.myExtension = function() { /* ... */ };
}
The RxJS definitions (.d.ts files) are used and compiled together with the code. This leads to the following compiler error: 2339 Property 'Observable' does not exist on type 'typeof Rx'
As far as I can tell this happens because I used the same Rx identifier in MyModule.Rx. When switching the namespace in the first line to module MyModule.NotRx { everything works fine - the Observable type is correctly looked up from the RxJS .d.ts file.
So it seems that the names MyModule.Rx and the RxJS declared Rx namespaces are in conflict. I know that I could simply rename my namespace to MyModule.SomethingElse but that seems somewhat of a hack.
Having all polyfills/extensions for Rx in the MyModue.Rx namespace seems a natural choice for me - how can this be done in a clean way?
You can't do that.
Take this code in TypeScript:
var B = 'test';
module A.B {
// Declare a function
export function fn() {
}
// Tests
console.log(B); // Object { }
A.B.fn(); // valid
B.fn(); // valid
fn(); // valid
}
The message displayed in the console is: Object { } and not test. Look at the transpiled code:
var B = 'test'; // root scope
var A;
(function (A) {
var B; // same name, hide the root scope one
(function (B) {
// Declare a function
function fn() {
}
B.fn = fn;
// Tests
console.log(B); // Object { }
A.B.fn(); // valid
B.fn(); // valid
fn(); // valid
})(B = A.B || (A.B = {}));
})(A || (A = {}));
The module A.B is transpiled to two JavaScript variables A and B. We can use them in order to access to the exported members of the module: the function fn is accessible from A.B.fn, B.fn and fn. In the module, the variable B from the root scope is hidden by the variable B of the module.
You can't access to a global variable Rx from a module named Rx.
As mentioned by Tarh you cannot refer to an outer module if its been shadowed by a local variable. I've +1ed his answer and that should be the accepted answer. I'll just leave a few workarounds:
One workaround which you already know is to rename MyModule.Rx to something that doesn't have Rx. An alternative is to capture Rx with some other name:
import OrigRx = Rx;
module MyModule.Rx {
OrigRx.Observable.prototype.myExtension = function() { /* ... */ };
}
This is very similar to https://stackoverflow.com/a/29021964/390330

Get generic type using Mono embedded

How to I create a generic List<String> object using mono embedded calls? I can get List's MonoClass:
MonoClass* list = mono_class_from_name(mscorlibimage,
"System.Collections.Generic", "List`1");
and I see in docs that there's
mono_class_from_generic_parameter(MonoGenericParam*...)
but I have no idea where and how to get the MonoGenericParam. Or perhaps I need to construct a valid name for mono_class_from_name? I think this can be a bit slower but I'd accept that for now. I tried
MonoClass* list = mono_class_from_name(mscorlib::get().image, "System.Collections.Generic", "List`1[System.String]");
but no luck.
UPDATE:
OK I found a way. Still I'd like to see if there's an official way of doing thing, as this hack looks too dirty to me.
Basically I searched mono sources for generic methods and found mono_class_bind_generic_parameters (see https://raw.github.com/mono/mono/master/mono/metadata/reflection.c). I had to link to libmono-2.0.a in addition to .so to use it. But it worked:
extern "C" MonoClass*
mono_class_bind_generic_parameters(MonoClass *klass,
int type_argc, MonoType **types, bool is_dynamic);
MonoClass* list = mono_class_from_name(mscorlib::get().image,
"System.Collections.Generic", "List`1");
MonoClass* strcls = mono_class_from_name(mscorlib::get().image, "System", "String");
printf("str class: %p\n", strcls);
MonoType* strtype = mono_class_get_type(strcls);
printf("str type: %p\n", strtype);
MonoType* types[1];
types[0] = strtype;
list = mono_class_bind_generic_parameters(list, 1, types, false);
printf("list[string] class: %p\n", list);
MonoObject* obj = mono_object_new(domain, list);
printf("list[string] created: %p\n", obj);
I suppose I can take sources (UPDATE: hardly so) of these methods and reimplement them (they parse metadata, etc) - if I don't want to link to .a - but I wonder if there's a simpler way. Mono docs just don't answer anything, as they use to.
UPDATE: found this thread: http://mono.1490590.n4.nabble.com/Embedded-API-Method-signature-not-found-with-generic-parameter-td4660157.html which seems to say that no embedded API exists for what I want (i.e. they do not bother to expose mono_class_bind_generic_parameters). Can someone prove that it's correct? With that method, by the way, I get MonoReflectionType* and no way to get back MonoType* from it - while it is as easy to as getting ->type from the structure - which is internal and access via functions to it is internal. Mono Embedded should be called "Mono Internal" instead.
UPDATE: another method is to hack mono_class_inflate_generic_type using copy of internal structures:
struct _MonoGenericInst {
uint32_t id; /* unique ID for debugging */
uint32_t type_argc : 22; /* number of type arguments */
uint32_t is_open : 1; /* if this is an open type */
MonoType *type_argv [1];
};
struct _MonoGenericContext {
/* The instantiation corresponding to the class generic parameters */
MonoGenericInst *class_inst;
/* The instantiation corresponding to the method generic parameters */
void *method_inst;
};
_MonoGenericInst clsctx;
clsctx.type_argc = 1;
clsctx.is_open = 0;
clsctx.type_argv[0] = mono_class_get_type(System::String::_SClass());
MonoGenericContext ctx;
ctx.method_inst = 0;
ctx.class_inst = &clsctx;
MonoType* lt = mono_class_inflate_generic_type(
mono_class_get_type(System::Collections::Generic::List<System::String>::_SClass()),
&ctx);
This doesn't require static link to .a but is even a worse hack. And mono_class_inflate_generic_type is marked as DEPRECATED - so, if this is deprecated, then which is the modern one?
In many cases a mono embedding conundrum can be resolved by using a managed helper method. This is the approach used here.
So we have:
A managed helper method that accepts a generic type definition and an array of generic parameter types.
A client method that accepts a generic type definition name (e.g.: System.Collections.Generic.List`1), an assembly image that contains the type (or use an Assembly Qualified name) and an object of the required generic parameter type. We retrieve the underlying monoType for the object.
Note that when passing type info into the managed layer it has to be an instance of MonoReflectionType as obtained from mono_type_get_object().
The managed helper method is trivial and does the actual instantiation:
public static object CreateInstanceOfGenericType(Type genericTypeDefinition, Type[] parms)
{
// construct type from definition
Type constructedType = genericTypeDefinition.MakeGenericType(parms);
// create instance of constructed type
object obj = Activator.CreateInstance(constructedType);
return obj;
}
The helper code is called, in this case, from Objective-C:
+ (id)createInstanceOfGenericTypeDefinition:(char *)genericTypeDefinitionName monoImage:(MonoImage *)monoImage itemObject:(id)itemObject
{
// get the contained item monoType
MonoType *monoType = [DBType monoTypeForMonoObject:[itemObject monoObject]];
MonoReflectionType *monoReflectionType = mono_type_get_object([DBManagedEnvironment currentDomain], monoType);
// build a System.Array of item types
DBManagedObject *argType = [[DBManagedObject alloc] initWithMonoObject:(MonoObject *)monoReflectionType];
NSArray *argTypes = #[argType];
DBSystem_Array *dbsAargTypes = [argTypes dbsArrayWithTypeName:#"System.Type"];
// get the generic type definition
//
// Retrieves a MonoType from given name. If the name is not fully qualified,
// it defaults to get the type from the image or, if image is NULL or loading
// from it fails, uses corlib.
// This is the embedded equivalent of System.Type.GetType();
MonoType *monoGenericTypeDefinition = mono_reflection_type_from_name(genericTypeDefinitionName, monoImage);
// create instance using helper method
MonoMethod *helperMethod = [DBManagedEnvironment dubrovnikMonoMethodWithName:"CreateInstanceOfGenericType" className:"Dubrovnik.FrameworkHelper.GenericHelper" argCount:2];
void *hargs [2];
hargs[0] = mono_type_get_object([DBManagedEnvironment currentDomain], monoGenericTypeDefinition);
hargs[1] = [dbsAargTypes monoArray]; // a monoArray *
MonoObject *monoException = NULL;
MonoObject *monoObject = mono_runtime_invoke(helperMethod, NULL, hargs, &monoException);
if (monoException) NSRaiseExceptionFromMonoException(monoException);
id object = [System_Object subclassObjectWithMonoObject:monoObject];
return object;
}
For the complete code see Dubrovnik on Github