chore(repo): move files to new repo name

This commit is contained in:
Daniel Sogl
2021-09-27 17:07:03 +02:00
parent 3ae573b632
commit 15c441cc2a
246 changed files with 484 additions and 523 deletions
@@ -0,0 +1,26 @@
export function checkReady() {
if (typeof process === 'undefined') {
const win: any = typeof window !== 'undefined' ? window : {};
const DEVICE_READY_TIMEOUT = 5000;
// To help developers using cordova, we listen for the device ready event and
// log an error if it didn't fire in a reasonable amount of time. Generally,
// when this happens, developers should remove and reinstall plugins, since
// an inconsistent plugin is often the culprit.
const before = Date.now();
let didFireReady = false;
win.document.addEventListener('deviceready', () => {
console.log(`Ionic Native: deviceready event fired after ${Date.now() - before} ms`);
didFireReady = true;
});
setTimeout(() => {
if (!didFireReady && win.cordova) {
console.warn(
`Ionic Native: deviceready did not fire within ${DEVICE_READY_TIMEOUT}ms. This can happen when plugins are in an inconsistent state. Try removing plugins from plugins/ and reinstalling them.`
);
}
}, DEVICE_READY_TIMEOUT);
}
}
@@ -0,0 +1,100 @@
import { callCordovaPlugin, wrapPromise } from './common';
declare const window: any;
class MockPlugin {
static getPluginRef(): string {
return 'mockPlugin';
}
static getPluginName(): string {
return 'MockPlugin';
}
static getPluginInstallName(): string {
return '';
}
create(): MockInstancePluginObject {
return new MockInstancePluginObject();
}
}
class MockInstancePluginObject {
_pluginInstance: MockCordovaPlugin;
constructor() {
this._pluginInstance = new MockCordovaPlugin();
}
}
class MockCordovaPlugin {
static ping = jest.fn((arg: string) => 'pong');
static pingAsync = jest.fn((arg: string, success: Function, error: Function) => success('pong'));
ping = jest.fn((arg: string) => 'pong');
pingAsync = jest.fn((arg: string, success: Function, error: Function) => success('pong'));
}
describe('Common decorator functions', () => {
let plugin: MockPlugin, instancePluginObject: MockInstancePluginObject;
beforeAll(() => {
window.mockPlugin = MockCordovaPlugin;
plugin = new MockPlugin();
instancePluginObject = plugin.create();
});
describe('callCordovaPlugin', () => {
test('should return value from cordova plugin', () => {
expect(callCordovaPlugin(plugin, 'ping', ['pingpong'])).toBe('pong');
});
test('original method should have been called', () => {
expect(MockCordovaPlugin.ping.mock.calls.length).toBe(1);
});
test('original method should have received args', () => {
expect(MockCordovaPlugin.ping.mock.calls[0][0]).toBe('pingpong');
});
});
describe('wrapPromise', () => {
test('should return a promise that resolves with a value', async () => {
expect(await wrapPromise(plugin, 'pingAsync', ['pingpong'])).toBe('pong');
});
test('original method should have been called', () => {
expect(MockCordovaPlugin.pingAsync.mock.calls.length).toBe(1);
});
test('original method should have received args', () => {
expect(MockCordovaPlugin.pingAsync.mock.calls[0][0]).toBe('pingpong');
expect(typeof MockCordovaPlugin.pingAsync.mock.calls[0][1]).toBe('function');
expect(typeof MockCordovaPlugin.pingAsync.mock.calls[0][2]).toBe('function');
});
});
describe('wrapObservable', () => {
test('should return an observable that emits a value', async () => {});
test('original method should have been called', () => {});
test('original method should have received args', () => {});
});
describe('wrapEventObservable', () => {
test('should return an observable that wraps an event listener', async () => {});
});
describe('callInstance', () => {
test('should call an instance method', async () => {});
test('original method should have been called', () => {
// expect(instancePluginObject._pluginInstance.ping.mock.calls.length).toBe(1);
});
test('original method should have received args', () => {
// expect(instancePluginObject._pluginInstance.ping.mock.calls[0][0]).toBe('pingpong');
});
});
});
@@ -0,0 +1,485 @@
import { fromEvent, Observable } from 'rxjs';
import { CordovaOptions } from './interfaces';
declare const window: any;
export const ERR_CORDOVA_NOT_AVAILABLE = { error: 'cordova_not_available' };
export const ERR_PLUGIN_NOT_INSTALLED = { error: 'plugin_not_installed' };
export function getPromise<T>(callback: (resolve: Function, reject?: Function) => any): Promise<T> {
const tryNativePromise = () => {
if (Promise) {
return new Promise<T>((resolve, reject) => {
callback(resolve, reject);
});
} else {
console.error(
'No Promise support or polyfill found. To enable Ionic Native support, please add the es6-promise polyfill before this script, or run with a library like Angular or on a recent browser.'
);
}
};
if (typeof window !== 'undefined' && window.angular) {
const doc = window.document;
const injector = window.angular.element(doc.querySelector('[ng-app]') || doc.body).injector();
if (injector) {
const $q = injector.get('$q');
return $q((resolve: Function, reject: Function) => {
callback(resolve, reject);
});
}
console.warn(
`Angular 1 was detected but $q couldn't be retrieved. This is usually when the app is not bootstrapped on the html or body tag. Falling back to native promises which won't trigger an automatic digest when promises resolve.`
);
}
return tryNativePromise();
}
export function wrapPromise(pluginObj: any, methodName: string, args: any[], opts: CordovaOptions = {}) {
let pluginResult: any, rej: Function;
const p = getPromise((resolve: Function, reject: Function) => {
if (opts.destruct) {
pluginResult = callCordovaPlugin(
pluginObj,
methodName,
args,
opts,
(...args: any[]) => resolve(args),
(...args: any[]) => reject(args)
);
} else {
pluginResult = callCordovaPlugin(pluginObj, methodName, args, opts, resolve, reject);
}
rej = reject;
});
// Angular throws an error on unhandled rejection, but in this case we have already printed
// a warning that Cordova is undefined or the plugin is uninstalled, so there is no reason
// to error
if (pluginResult && pluginResult.error) {
p.catch(() => {});
typeof rej === 'function' && rej(pluginResult.error);
}
return p;
}
function wrapOtherPromise(pluginObj: any, methodName: string, args: any[], opts: any = {}) {
return getPromise((resolve: Function, reject: Function) => {
const pluginResult = callCordovaPlugin(pluginObj, methodName, args, opts);
if (pluginResult) {
if (pluginResult.error) {
reject(pluginResult.error);
} else if (pluginResult.then) {
pluginResult.then(resolve).catch(reject);
}
} else {
reject({ error: 'unexpected_error' });
}
});
}
function wrapObservable(pluginObj: any, methodName: string, args: any[], opts: any = {}) {
return new Observable(observer => {
let pluginResult;
if (opts.destruct) {
pluginResult = callCordovaPlugin(
pluginObj,
methodName,
args,
opts,
(...args: any[]) => observer.next(args),
(...args: any[]) => observer.error(args)
);
} else {
pluginResult = callCordovaPlugin(
pluginObj,
methodName,
args,
opts,
observer.next.bind(observer),
observer.error.bind(observer)
);
}
if (pluginResult && pluginResult.error) {
observer.error(pluginResult.error);
observer.complete();
}
return () => {
try {
if (opts.clearFunction) {
if (opts.clearWithArgs) {
return callCordovaPlugin(
pluginObj,
opts.clearFunction,
args,
opts,
observer.next.bind(observer),
observer.error.bind(observer)
);
}
return callCordovaPlugin(pluginObj, opts.clearFunction, []);
}
} catch (e) {
console.warn(
'Unable to clear the previous observable watch for',
pluginObj.constructor.getPluginName(),
methodName
);
console.warn(e);
}
};
});
}
/**
* Wrap the event with an observable
* @private
* @param event event name
* @param element The element to attach the event listener to
* @returns {Observable}
*/
function wrapEventObservable(event: string, element: any): Observable<any> {
element =
typeof window !== 'undefined' && element
? get(window, element)
: element || (typeof window !== 'undefined' ? window : {});
return fromEvent(element, event);
}
/**
* Checks if plugin/cordova is available
* @return {boolean | { error: string } }
* @private
*/
export function checkAvailability(
pluginRef: string,
methodName?: string,
pluginName?: string
): boolean | { error: string };
export function checkAvailability(
pluginObj: any,
methodName?: string,
pluginName?: string
): boolean | { error: string };
export function checkAvailability(plugin: any, methodName?: string, pluginName?: string): boolean | { error: string } {
let pluginRef, pluginInstance, pluginPackage;
if (typeof plugin === 'string') {
pluginRef = plugin;
} else {
pluginRef = plugin.constructor.getPluginRef();
pluginName = plugin.constructor.getPluginName();
pluginPackage = plugin.constructor.getPluginInstallName();
}
pluginInstance = getPlugin(pluginRef);
if (!pluginInstance || (!!methodName && typeof pluginInstance[methodName] === 'undefined')) {
if (typeof window === 'undefined' || !window.cordova) {
cordovaWarn(pluginName, methodName);
return ERR_CORDOVA_NOT_AVAILABLE;
}
pluginWarn(pluginName, pluginPackage, methodName);
return ERR_PLUGIN_NOT_INSTALLED;
}
return true;
}
/**
* Checks if _objectInstance exists and has the method/property
* @private
*/
export function instanceAvailability(pluginObj: any, methodName?: string): boolean {
return pluginObj._objectInstance && (!methodName || typeof pluginObj._objectInstance[methodName] !== 'undefined');
}
export function setIndex(args: any[], opts: any = {}, resolve?: Function, reject?: Function): any {
// ignore resolve and reject in case sync
if (opts.sync) {
return args;
}
// If the plugin method expects myMethod(success, err, options)
if (opts.callbackOrder === 'reverse') {
// Get those arguments in the order [resolve, reject, ...restOfArgs]
args.unshift(reject);
args.unshift(resolve);
} else if (opts.callbackStyle === 'node') {
args.push((err: any, result: any) => {
if (err) {
reject(err);
} else {
resolve(result);
}
});
} else if (opts.callbackStyle === 'object' && opts.successName && opts.errorName) {
const obj: any = {};
obj[opts.successName] = resolve;
obj[opts.errorName] = reject;
args.push(obj);
} else if (typeof opts.successIndex !== 'undefined' || typeof opts.errorIndex !== 'undefined') {
const setSuccessIndex = () => {
// If we've specified a success/error index
if (opts.successIndex > args.length) {
args[opts.successIndex] = resolve;
} else {
args.splice(opts.successIndex, 0, resolve);
}
};
const setErrorIndex = () => {
// We don't want that the reject cb gets spliced into the position of an optional argument that has not been
// defined and thus causing non expected behavior.
if (opts.errorIndex > args.length) {
args[opts.errorIndex] = reject; // insert the reject fn at the correct specific index
} else {
args.splice(opts.errorIndex, 0, reject); // otherwise just splice it into the array
}
};
if (opts.successIndex > opts.errorIndex) {
setErrorIndex();
setSuccessIndex();
} else {
setSuccessIndex();
setErrorIndex();
}
} else {
// Otherwise, let's tack them on to the end of the argument list
// which is 90% of cases
args.push(resolve);
args.push(reject);
}
return args;
}
export function callCordovaPlugin(
pluginObj: any,
methodName: string,
args: any[],
opts: any = {},
resolve?: Function,
reject?: Function
) {
// Try to figure out where the success/error callbacks need to be bound
// to our promise resolve/reject handlers.
args = setIndex(args, opts, resolve, reject);
const availabilityCheck = checkAvailability(pluginObj, methodName);
if (availabilityCheck === true) {
const pluginInstance = getPlugin(pluginObj.constructor.getPluginRef());
return pluginInstance[methodName].apply(pluginInstance, args);
} else {
return availabilityCheck;
}
}
export function callInstance(
pluginObj: any,
methodName: string,
args: any[],
opts: any = {},
resolve?: Function,
reject?: Function
) {
args = setIndex(args, opts, resolve, reject);
if (instanceAvailability(pluginObj, methodName)) {
return pluginObj._objectInstance[methodName].apply(pluginObj._objectInstance, args);
}
}
export function getPlugin(pluginRef: string): any {
if (typeof window !== 'undefined') {
return get(window, pluginRef);
}
return null;
}
export function get(element: Element | Window, path: string) {
const paths: string[] = path.split('.');
let obj: any = element;
for (let i = 0; i < paths.length; i++) {
if (!obj) {
return null;
}
obj = obj[paths[i]];
}
return obj;
}
export function pluginWarn(pluginName: string, plugin?: string, method?: string): void {
if (method) {
console.warn(
'Native: tried calling ' + pluginName + '.' + method + ', but the ' + pluginName + ' plugin is not installed.'
);
} else {
console.warn(`Native: tried accessing the ${pluginName} plugin but it's not installed.`);
}
if (plugin) {
console.warn(`Install the ${pluginName} plugin: 'ionic cordova plugin add ${plugin}'`);
}
}
/**
* @private
* @param pluginName
* @param method
*/
export function cordovaWarn(pluginName: string, method?: string): void {
if (typeof process === 'undefined') {
if (method) {
console.warn(
'Native: tried calling ' +
pluginName +
'.' +
method +
', but Cordova is not available. Make sure to include cordova.js or run in a device/simulator'
);
} else {
console.warn(
'Native: tried accessing the ' +
pluginName +
' plugin but Cordova is not available. Make sure to include cordova.js or run in a device/simulator'
);
}
}
}
// Fixes a bug in TypeScript 2.9.2 where the ...args is being converted into args: {} and
// causing compilation issues
export type WrapFn = (...args: any[]) => any;
/**
* @private
*/
export const wrap = (pluginObj: any, methodName: string, opts: CordovaOptions = {}): WrapFn => {
return (...args: any[]) => {
if (opts.sync) {
// Sync doesn't wrap the plugin with a promise or observable, it returns the result as-is
return callCordovaPlugin(pluginObj, methodName, args, opts);
} else if (opts.observable) {
return wrapObservable(pluginObj, methodName, args, opts);
} else if (opts.eventObservable && opts.event) {
return wrapEventObservable(opts.event, opts.element);
} else if (opts.otherPromise) {
return wrapOtherPromise(pluginObj, methodName, args, opts);
} else {
return wrapPromise(pluginObj, methodName, args, opts);
}
};
};
/**
* @private
*/
export function wrapInstance(pluginObj: any, methodName: string, opts: any = {}): Function {
return (...args: any[]) => {
if (opts.sync) {
return callInstance(pluginObj, methodName, args, opts);
} else if (opts.observable) {
return new Observable(observer => {
let pluginResult;
if (opts.destruct) {
pluginResult = callInstance(
pluginObj,
methodName,
args,
opts,
(...args: any[]) => observer.next(args),
(...args: any[]) => observer.error(args)
);
} else {
pluginResult = callInstance(
pluginObj,
methodName,
args,
opts,
observer.next.bind(observer),
observer.error.bind(observer)
);
}
if (pluginResult && pluginResult.error) {
observer.error(pluginResult.error);
}
return () => {
try {
if (opts.clearWithArgs) {
return callInstance(
pluginObj,
opts.clearFunction,
args,
opts,
observer.next.bind(observer),
observer.error.bind(observer)
);
}
return callInstance(pluginObj, opts.clearFunction, []);
} catch (e) {
console.warn(
'Unable to clear the previous observable watch for',
pluginObj.constructor.getPluginName(),
methodName
);
console.warn(e);
}
};
});
} else if (opts.otherPromise) {
return getPromise((resolve: Function, reject: Function) => {
let result;
if (opts.destruct) {
result = callInstance(
pluginObj,
methodName,
args,
opts,
(...args: any[]) => resolve(args),
(...args: any[]) => reject(args)
);
} else {
result = callInstance(pluginObj, methodName, args, opts, resolve, reject);
}
if (result && result.then) {
result.then(resolve, reject);
} else {
reject();
}
});
} else {
let pluginResult: any, rej: Function;
const p = getPromise((resolve: Function, reject: Function) => {
if (opts.destruct) {
pluginResult = callInstance(
pluginObj,
methodName,
args,
opts,
(...args: any[]) => resolve(args),
(...args: any[]) => reject(args)
);
} else {
pluginResult = callInstance(pluginObj, methodName, args, opts, resolve, reject);
}
rej = reject;
});
// Angular throws an error on unhandled rejection, but in this case we have already printed
// a warning that Cordova is undefined or the plugin is uninstalled, so there is no reason
// to error
if (pluginResult && pluginResult.error) {
p.catch(() => {});
typeof rej === 'function' && rej(pluginResult.error);
}
return p;
}
};
}
@@ -0,0 +1,22 @@
import { Observable, Observer } from 'rxjs';
import { checkAvailability, getPlugin } from './common';
function overrideFunction(pluginObj: any, methodName: string): Observable<any> {
return new Observable((observer: Observer<any>) => {
const availabilityCheck = checkAvailability(pluginObj, methodName);
if (availabilityCheck === true) {
const pluginInstance = getPlugin(pluginObj.constructor.getPluginRef());
pluginInstance[methodName] = observer.next.bind(observer);
return () => (pluginInstance[methodName] = () => {});
} else {
observer.error(availabilityCheck);
observer.complete();
}
});
}
export function cordovaFunctionOverride(pluginObj: any, methodName: string, args: IArguments | any[] = []) {
return overrideFunction(pluginObj, methodName);
}
@@ -0,0 +1,7 @@
import { wrapInstance } from './common';
import { CordovaOptions } from './interfaces';
export function cordovaInstance(pluginObj: any, methodName: string, config: CordovaOptions, args: IArguments | any[]) {
args = Array.from(args);
return wrapInstance(pluginObj, methodName, config).apply(this, args);
}
@@ -0,0 +1,14 @@
import { checkAvailability, getPlugin } from './common';
export function cordovaPropertyGet(pluginObj: any, key: string) {
if (checkAvailability(pluginObj, key) === true) {
return getPlugin(pluginObj.constructor.getPluginRef())[key];
}
return null;
}
export function cordovaPropertySet(pluginObj: any, key: string, value: any) {
if (checkAvailability(pluginObj, key) === true) {
getPlugin(pluginObj.constructor.getPluginRef())[key] = value;
}
}
@@ -0,0 +1,6 @@
import { wrap } from './common';
import { CordovaOptions } from './interfaces';
export function cordova(pluginObj: any, methodName: string, config: CordovaOptions, args: IArguments | any[]) {
return wrap(pluginObj, methodName, config).apply(this, args);
}
@@ -0,0 +1,12 @@
export function instancePropertyGet(pluginObj: any, key: string) {
if (pluginObj._objectInstance && pluginObj._objectInstance[key]) {
return pluginObj._objectInstance[key];
}
return null;
}
export function instancePropertySet(pluginObj: any, key: string, value: any) {
if (pluginObj._objectInstance) {
pluginObj._objectInstance[key] = value;
}
}
@@ -0,0 +1,111 @@
export interface PluginConfig {
/**
* Plugin name, this should match the class name
*/
pluginName: string;
/**
* Plugin NPM package name
*/
plugin: string;
/**
* Plugin object reference
*/
pluginRef?: string;
/**
* Github repository URL
*/
repo?: string;
/**
* Custom install command
*/
install?: string;
/**
* Available installation variables
*/
installVariables?: string[];
/**
* Supported platforms
*/
platforms?: string[];
[key: string]: any;
}
export interface CordovaOptions {
destruct?: boolean;
/**
* If the method-name of the cordova plugin is different from the wrappers one, it can be defined here
*/
methodName?: string;
/**
* Set to true if the wrapped method is a sync function
*/
sync?: boolean;
/**
* Callback order. Set to reverse if the success/error callbacks are the first 2 arguments that the wrapped method
* takes.
*/
callbackOrder?: 'reverse';
/**
* Callback style
*/
callbackStyle?: 'node' | 'object';
/**
* Set a custom index for the success callback function. This doesn't work if callbackOrder or callbackStyle are set.
*/
successIndex?: number;
/**
* Set a custom index for the error callback function. This doesn't work if callbackOrder or callbackStyle are set.
*/
errorIndex?: number;
/**
* Success function property name. This must be set if callbackStyle is set to object.
*/
successName?: string;
/**
* Error function property name. This must be set if callbackStyle is set to object.
*/
errorName?: string;
/**
* Set to true to return an observable
*/
observable?: boolean;
/**
* If observable is set to true, this can be set to a different function name that will cancel the observable.
*/
clearFunction?: string;
/**
* This can be used if clearFunction is set. Set this to true to call the clearFunction with the same arguments used
* in the initial function.
*/
clearWithArgs?: boolean;
/**
* Creates an observable that wraps a global event. Replaces document.addEventListener
*/
eventObservable?: boolean;
/**
* Event name, this must be set if eventObservable is set to true
*/
event?: string;
/**
* Element to attach the event listener to, this is optional, defaults to `window`
*/
element?: any;
/**
* Set to true if the wrapped method returns a promise
*/
otherPromise?: boolean;
/**
* Supported platforms
*/
platforms?: string[];
}
export declare const Plugin: (config: PluginConfig) => ClassDecorator;
export declare const Cordova: (config?: CordovaOptions) => MethodDecorator;
export declare const CordovaProperty: () => PropertyDecorator;
export declare const CordovaInstance: (config?: CordovaOptions) => MethodDecorator;
export declare const InstanceProperty: () => PropertyDecorator;
export declare const CordovaCheck: (config?: CordovaOptions) => MethodDecorator;
export declare const InstanceCheck: (config?: CordovaOptions) => MethodDecorator;
export declare const CordovaFunctionOverride: () => MethodDecorator;
@@ -0,0 +1,14 @@
import { checkReady } from './bootstrap';
export { IonicNativePlugin } from './ionic-native-plugin';
// Decorators
export { checkAvailability, instanceAvailability, wrap, getPromise } from './decorators/common';
export * from './decorators/cordova';
export * from './decorators/cordova-function-override';
export * from './decorators/cordova-instance';
export * from './decorators/cordova-property';
export * from './decorators/instance-property';
export * from './decorators/interfaces';
checkReady();
@@ -0,0 +1,62 @@
import { checkAvailability } from './decorators/common';
import { get } from './util';
export class IonicNativePlugin {
static pluginName = '';
static pluginRef = '';
static plugin = '';
static repo = '';
static platforms: string[] = [];
static install = '';
/**
* Returns a boolean that indicates whether the plugin is installed
* @return {boolean}
*/
static installed(): boolean {
const isAvailable = checkAvailability(this.pluginRef) === true;
return isAvailable;
}
/**
* Returns the original plugin object
*/
static getPlugin(): any {
if (typeof window !== 'undefined') {
return get(window, this.pluginRef);
}
return null;
}
/**
* Returns the plugin's name
*/
static getPluginName(): string {
const pluginName = this.pluginName;
return pluginName;
}
/**
* Returns the plugin's reference
*/
static getPluginRef(): string {
const pluginRef = this.pluginRef;
return pluginRef;
}
/**
* Returns the plugin's install name
*/
static getPluginInstallName(): string {
const plugin = this.plugin;
return plugin;
}
/**
* Returns the plugin's supported platforms
*/
static getSupportedPlatforms(): string[] {
const platform = this.platforms;
return platform;
}
}
+27
View File
@@ -0,0 +1,27 @@
declare const window: any;
/**
* Initialize the ionic.native Angular module if we're running in ng1.
* This iterates through the list of registered plugins and dynamically
* creates Angular 1 services of the form $cordovaSERVICE, ex: $cordovaStatusBar.
*/
export function initAngular1(plugins: any) {
if (typeof window !== 'undefined' && window.angular) {
const ngModule = window.angular.module('ionic.native', []);
for (const name in plugins) {
const serviceName = '$cordova' + name;
const cls = plugins[name];
((serviceName, cls, name) => {
ngModule.service(serviceName, [
() => {
const funcs = window.angular.copy(cls);
funcs.__proto__['name'] = name;
return funcs;
},
]);
})(serviceName, cls, name);
}
}
}
+35
View File
@@ -0,0 +1,35 @@
declare const window: any;
/**
* @private
*/
export function get(element: Element | Window, path: string) {
const paths: string[] = path.split('.');
let obj: any = element;
for (let i = 0; i < paths.length; i++) {
if (!obj) {
return null;
}
obj = obj[paths[i]];
}
return obj;
}
/**
* @private
*/
export function getPromise(callback: Function = () => {}): Promise<any> {
const tryNativePromise = () => {
if (typeof Promise === 'function' || (typeof window !== 'undefined' && window.Promise)) {
return new Promise<any>((resolve, reject) => {
callback(resolve, reject);
});
} else {
console.error(
'No Promise support or polyfill found. To enable Ionic Native support, please add the es6-promise polyfill before this script, or run with a library like Angular or on a recent browser.'
);
}
};
return tryNativePromise();
}