mirror of
https://github.com/NativeScript/NativeScript.git
synced 2025-11-05 13:26:48 +08:00
Add parsers for the background css shorthand property, make ViewBase unit testable in node environment
Add background parser and linear-gradient parser
Use sticky regexes
Simplify some types, introduce generic Parsed<T> instead of & TokenRange
Apply each parser to return a { start, end, value } object
Move the css selector parser to the css/parser and unify types
Add the first steps toward building homegrown css parser
Add somewhat standards compliant tokenizer, add baseline, rework and shady css parsers
Enable all tests again, skip flaky perf test
Improve css parser tokenizer by converting some char token types to simple string
Implement 'parse a stylesheet'
Add gonzales css-parser
Add parseLib and css-tree perf
Add a thin parser layer that will convert CSS3 tokens to values, for now output is compatible with rework
Make root tsc green
Return the requires of tns-core-modules to use relative paths for webpack to work
Implement support for '@import 'url-string';
Fix function parser, function-token is no-longer neglected
Make the style-scope be able to load from "css" and "css-ast" modules
Add a loadAppCss event so theme can be added to snapshot separately from loaded
288 lines
8.7 KiB
TypeScript
288 lines
8.7 KiB
TypeScript
declare var __startCPUProfiler: any;
|
|
declare var __stopCPUProfiler: any;
|
|
|
|
import { TimerInfo as TimerInfoDefinition, InstrumentationMode } from ".";
|
|
|
|
export function uptime() {
|
|
return global.android ? (<any>org).nativescript.Process.getUpTime() : (<any>global).__tns_uptime();
|
|
}
|
|
|
|
interface TimerInfo extends TimerInfoDefinition {
|
|
totalTime: number;
|
|
lastTime?: number;
|
|
count: number;
|
|
currentStart: number;
|
|
/**
|
|
* Counts the number of entry and exits a function had.
|
|
*/
|
|
runCount: number;
|
|
}
|
|
|
|
// Use object instead of map as it is a bit faster
|
|
const timers: { [index: string]: TimerInfo } = {};
|
|
const anyGlobal = <any>global;
|
|
const profileNames: string[] = [];
|
|
|
|
export const time = (<any>global).__time || Date.now;
|
|
|
|
export function start(name: string): void {
|
|
let info = timers[name];
|
|
|
|
if (info) {
|
|
info.currentStart = time();
|
|
info.runCount++;
|
|
} else {
|
|
info = {
|
|
totalTime: 0,
|
|
count: 0,
|
|
currentStart: time(),
|
|
runCount: 1
|
|
};
|
|
timers[name] = info;
|
|
}
|
|
}
|
|
|
|
export function stop(name: string): TimerInfo {
|
|
const info = timers[name];
|
|
|
|
if (!info) {
|
|
throw new Error(`No timer started: ${name}`);
|
|
}
|
|
|
|
if (info.runCount) {
|
|
info.runCount--;
|
|
if (info.runCount) {
|
|
info.count++;
|
|
} else {
|
|
info.lastTime = time() - info.currentStart;
|
|
info.totalTime += info.lastTime;
|
|
info.count++;
|
|
info.currentStart = 0;
|
|
}
|
|
} else {
|
|
throw new Error(`Timer ${name} paused more times than started.`);
|
|
}
|
|
|
|
return info;
|
|
}
|
|
|
|
export function timer(name: string): TimerInfo {
|
|
return timers[name];
|
|
}
|
|
|
|
export function print(name: string): TimerInfo {
|
|
const info = timers[name];
|
|
if (!info) {
|
|
throw new Error(`No timer started: ${name}`);
|
|
}
|
|
|
|
console.log(`---- [${name}] STOP total: ${info.totalTime} count:${info.count}`);
|
|
return info;
|
|
}
|
|
|
|
export function isRunning(name: string): boolean {
|
|
const info = timers[name];
|
|
return !!(info && info.runCount);
|
|
}
|
|
|
|
function countersProfileFunctionFactory<F extends Function>(fn: F, name: string, type: MemberType = MemberType.Instance): F {
|
|
profileNames.push(name);
|
|
return <any>function() {
|
|
start(name);
|
|
try {
|
|
return fn.apply(this, arguments);
|
|
} finally {
|
|
stop(name);
|
|
}
|
|
}
|
|
}
|
|
|
|
function timelineProfileFunctionFactory<F extends Function>(fn: F, name: string, type: MemberType = MemberType.Instance): F {
|
|
return type === MemberType.Instance ? <any>function() {
|
|
const start = time();
|
|
try {
|
|
return fn.apply(this, arguments);
|
|
} finally {
|
|
const end = time();
|
|
console.log(`Timeline: Modules: ${name} ${this} (${start}ms. - ${end}ms.)`);
|
|
}
|
|
} : function() {
|
|
const start = time();
|
|
try {
|
|
return fn.apply(this, arguments);
|
|
} finally {
|
|
const end = time();
|
|
console.log(`Timeline: Modules: ${name} (${start}ms. - ${end}ms.)`);
|
|
}
|
|
};
|
|
}
|
|
|
|
const enum MemberType {
|
|
Static,
|
|
Instance
|
|
}
|
|
|
|
let profileFunctionFactory: <F extends Function>(fn: F, name: string, type?: MemberType) => F;
|
|
export function enable(mode: InstrumentationMode = "counters") {
|
|
profileFunctionFactory = mode && {
|
|
counters: countersProfileFunctionFactory,
|
|
timeline: timelineProfileFunctionFactory
|
|
}[mode];
|
|
}
|
|
|
|
try {
|
|
const appConfig = require("~/package.json");
|
|
if (appConfig && appConfig.profiling) {
|
|
enable(appConfig.profiling);
|
|
}
|
|
} catch(e1) {
|
|
try {
|
|
console.log("Profiling startup failed to figure out defaults from package.json, error: " + e1);
|
|
} catch(e2) {
|
|
// We can get here if an exception is thrown in the mksnapshot as there is no console there.
|
|
}
|
|
}
|
|
|
|
export function disable() {
|
|
profileFunctionFactory = undefined;
|
|
}
|
|
|
|
function profileFunction<F extends Function>(fn: F, customName?: string): F {
|
|
return profileFunctionFactory(fn, customName || fn.name);
|
|
}
|
|
|
|
const profileMethodUnnamed = (target, key, descriptor) => {
|
|
// save a reference to the original method this way we keep the values currently in the
|
|
// descriptor and don't overwrite what another decorator might have done to the descriptor.
|
|
if (descriptor === undefined) {
|
|
descriptor = Object.getOwnPropertyDescriptor(target, key);
|
|
}
|
|
var originalMethod = descriptor.value;
|
|
|
|
let className = "";
|
|
if (target && target.constructor && target.constructor.name) {
|
|
className = target.constructor.name + ".";
|
|
}
|
|
|
|
let name = className + key;
|
|
|
|
//editing the descriptor/value parameter
|
|
descriptor.value = profileFunctionFactory(originalMethod, name, MemberType.Instance);
|
|
|
|
// return edited descriptor as opposed to overwriting the descriptor
|
|
return descriptor;
|
|
}
|
|
|
|
const profileStaticMethodUnnamed = (ctor, key, descriptor) => {
|
|
// save a reference to the original method this way we keep the values currently in the
|
|
// descriptor and don't overwrite what another decorator might have done to the descriptor.
|
|
if (descriptor === undefined) {
|
|
descriptor = Object.getOwnPropertyDescriptor(ctor, key);
|
|
}
|
|
var originalMethod = descriptor.value;
|
|
|
|
let className = "";
|
|
if (ctor && ctor.name) {
|
|
className = ctor.name + ".";
|
|
}
|
|
let name = className + key;
|
|
|
|
//editing the descriptor/value parameter
|
|
descriptor.value = profileFunctionFactory(originalMethod, name, MemberType.Static);
|
|
|
|
// return edited descriptor as opposed to overwriting the descriptor
|
|
return descriptor;
|
|
}
|
|
|
|
function profileMethodNamed(name: string): MethodDecorator {
|
|
return (target, key, descriptor: PropertyDescriptor) => {
|
|
|
|
// save a reference to the original method this way we keep the values currently in the
|
|
// descriptor and don't overwrite what another decorator might have done to the descriptor.
|
|
if (descriptor === undefined) {
|
|
descriptor = Object.getOwnPropertyDescriptor(target, key);
|
|
}
|
|
var originalMethod = descriptor.value;
|
|
|
|
//editing the descriptor/value parameter
|
|
descriptor.value = profileFunctionFactory(originalMethod, name);
|
|
|
|
// return edited descriptor as opposed to overwriting the descriptor
|
|
return descriptor;
|
|
}
|
|
}
|
|
|
|
const voidMethodDecorator = () => {
|
|
// no op
|
|
};
|
|
|
|
export function profile(nameFnOrTarget?: string | Function | Object, fnOrKey?: Function | string | symbol, descriptor?: PropertyDescriptor): Function | MethodDecorator {
|
|
if (typeof nameFnOrTarget === "object" && (typeof fnOrKey === "string" || typeof fnOrKey === "symbol")) {
|
|
if (!profileFunctionFactory) {
|
|
return;
|
|
}
|
|
return profileMethodUnnamed(nameFnOrTarget, fnOrKey, descriptor);
|
|
} else if (typeof nameFnOrTarget === "function" && (typeof fnOrKey === "string" || typeof fnOrKey === "symbol")) {
|
|
if (!profileFunctionFactory) {
|
|
return;
|
|
}
|
|
return profileStaticMethodUnnamed(nameFnOrTarget, fnOrKey, descriptor);
|
|
} else if (typeof nameFnOrTarget === "string" && typeof fnOrKey === "function") {
|
|
if (!profileFunctionFactory) {
|
|
return fnOrKey;
|
|
}
|
|
return profileFunction(fnOrKey, nameFnOrTarget);
|
|
} else if (typeof nameFnOrTarget === "function") {
|
|
if (!profileFunctionFactory) {
|
|
return nameFnOrTarget;
|
|
}
|
|
return profileFunction(nameFnOrTarget);
|
|
} else if (typeof nameFnOrTarget === "string") {
|
|
if (!profileFunctionFactory) {
|
|
return voidMethodDecorator;
|
|
}
|
|
return profileMethodNamed(nameFnOrTarget);
|
|
} else {
|
|
if (!profileFunctionFactory) {
|
|
return voidMethodDecorator;
|
|
}
|
|
return profileMethodUnnamed;
|
|
}
|
|
}
|
|
|
|
export function dumpProfiles(): void {
|
|
profileNames.forEach(function (name) {
|
|
const info = timers[name];
|
|
if (info) {
|
|
console.log("---- [" + name + "] STOP total: " + info.totalTime + " count:" + info.count);
|
|
}
|
|
else {
|
|
console.log("---- [" + name + "] Never called");
|
|
}
|
|
});
|
|
}
|
|
|
|
export function resetProfiles(): void {
|
|
profileNames.forEach(function (name) {
|
|
const info = timers[name];
|
|
if (info) {
|
|
if (info.runCount) {
|
|
console.log("---- timer with name [" + name + "] is currently running and won't be reset");
|
|
} else {
|
|
timers[name] = undefined;
|
|
}
|
|
}
|
|
});
|
|
}
|
|
|
|
export function startCPUProfile(name: string) {
|
|
if (anyGlobal.android) {
|
|
__startCPUProfiler(name);
|
|
}
|
|
}
|
|
|
|
export function stopCPUProfile(name: string) {
|
|
if (anyGlobal.android) {
|
|
__stopCPUProfiler(name);
|
|
}
|
|
} |