This commit is contained in:
lovebird 2021-07-24 13:30:56 +02:00
parent 16ba9b5400
commit cee4adf86d
34 changed files with 113745 additions and 9933 deletions

42
Readme.md Normal file
View File

@ -0,0 +1,42 @@
# Magento Typescript client
## Installation
```bash
npm i @plastichub/magento
```
## Usage
```typescript
import { Magento } from '@plastichub/magento';
process.on('unhandledRejection', (reason: string) => {
console.error('Unhandled rejection, reason: ', reason);
});
// init with profile.json : {
// "username":"admin",
// "password":"password"
//}
await Magento.initWithProfile('~/.magento.json', 'https://shop.plastic-hub.com/rest/all');
// await Magento.init('https://shop.plastic-hub.com/rest/all', 'admin', 'password');
console.log('Magento API Config', Magento.apiConfig);
const storeApi = new StoreStoreRepositoryV1Api(Magento.apiConfig);
const stores = await storeApi.storeStoreRepositoryV1GetListGet({});
console.log('stores', stores);
```
### Re-generate API via Swagger
1. Grab your swagger config from (make sure you are logged in) [https://shop.plastic-hub.com/swagger](https://shop.plastic-hub.com/swagger)
2. Drop the content at [https://app.swaggerhub.com/](https://app.swaggerhub.com/)
3. Export client -> typescrip-node-fetch-client
4. Include the generated api.ts
5. Drop the typescript compiler error output in a file, eg ```tsc -p . > shop_errors```
6. Run [./tools/clean_magento](./tools/clean_magento) to fix the swagger-io bugs for unresolved types
7. Done ;-)

31393
api.d.ts vendored Normal file

File diff suppressed because it is too large Load Diff

33079
api.js Normal file

File diff suppressed because one or more lines are too long

1
api.js.map Normal file

File diff suppressed because one or more lines are too long

View File

@ -1,14 +0,0 @@
{
"products_path": "../../products/products",
"fragments_path": "../../products/bazar/fragments",
"vendor_name": "Plastic Hub",
"vendor_website": "www.precious-plastic.org",
"vendor_products_external": "https://github.com/plastic-hub/products/tree/master/products/",
"vendor_instagram": "https://www.instagram.com/plastichubcat",
"vendor_youtube": "https://www.youtube.com/channel/UCuWDxJtV2pf5BefHEy09Cew/featured?view_as=subscriber",
"vendor_github": "https://github.com/plastic-hub",
"vendor_contact_email": "mailto://cgoflyn@gmail.com",
"vendor_whatsapp": "tel://0034666894789",
"vendor_facebook" : "https://precious-plastic.org/library/machines/",
"vendor_blog" : "https://precious-plastic.org/"
}

55
configuration.d.ts vendored Normal file
View File

@ -0,0 +1,55 @@
/**
* Magento Community
* No description provided (generated by Swagger Codegen https://github.com/swagger-api/swagger-codegen)
*
* OpenAPI spec version: 2.4
*
*
* NOTE: This class is auto generated by the swagger code generator program.
* https://github.com/swagger-api/swagger-codegen.git
* Do not edit the class manually.
*/
export interface ConfigurationParameters {
apiKey?: string | ((name: string) => string);
username?: string;
password?: string;
accessToken?: string | ((name: string, scopes?: string[]) => string);
basePath?: string;
}
export declare class Configuration {
/**
* parameter for apiKey security
* @param name security name
* @memberof Configuration
*/
apiKey?: string | ((name: string) => string);
/**
* parameter for basic security
*
* @type {string}
* @memberof Configuration
*/
username?: string;
/**
* parameter for basic security
*
* @type {string}
* @memberof Configuration
*/
password?: string;
/**
* parameter for oauth2 security
* @param name security name
* @param scopes oauth2 scope
* @memberof Configuration
*/
accessToken?: string | ((name: string, scopes?: string[]) => string);
/**
* override base path
*
* @type {string}
* @memberof Configuration
*/
basePath?: string;
constructor(param?: ConfigurationParameters);
}

26
configuration.js Normal file
View File

@ -0,0 +1,26 @@
"use strict";
// tslint:disable
/**
* Magento Community
* No description provided (generated by Swagger Codegen https://github.com/swagger-api/swagger-codegen)
*
* OpenAPI spec version: 2.4
*
*
* NOTE: This class is auto generated by the swagger code generator program.
* https://github.com/swagger-api/swagger-codegen.git
* Do not edit the class manually.
*/
Object.defineProperty(exports, "__esModule", { value: true });
exports.Configuration = void 0;
class Configuration {
constructor(param = {}) {
this.apiKey = param.apiKey;
this.username = param.username;
this.password = param.password;
this.accessToken = param.accessToken;
this.basePath = param.basePath;
}
}
exports.Configuration = Configuration;
//# sourceMappingURL=configuration.js.map

1
configuration.js.map Normal file
View File

@ -0,0 +1 @@
{"version":3,"file":"configuration.js","sourceRoot":"","sources":["src/configuration.ts"],"names":[],"mappings":";AAAA,iBAAiB;AACjB;;;;;;;;;;GAUG;;;AAWH,MAAa,aAAa;IAoCtB,YAAY,QAAiC,EAAE;QAC3C,IAAI,CAAC,MAAM,GAAG,KAAK,CAAC,MAAM,CAAC;QAC3B,IAAI,CAAC,QAAQ,GAAG,KAAK,CAAC,QAAQ,CAAC;QAC/B,IAAI,CAAC,QAAQ,GAAG,KAAK,CAAC,QAAQ,CAAC;QAC/B,IAAI,CAAC,WAAW,GAAG,KAAK,CAAC,WAAW,CAAC;QACrC,IAAI,CAAC,QAAQ,GAAG,KAAK,CAAC,QAAQ,CAAC;IACnC,CAAC;CACJ;AA3CD,sCA2CC"}

9
index.d.ts vendored Normal file
View File

@ -0,0 +1,9 @@
export declare const getToken: (url: any, user: any, password: any) => Promise<string>;
export declare class Magento {
static token: any;
static apiConfig: any;
static init: (baseUrl: string, username: string, password: string) => Promise<any>;
static initWithProfile: (profilePath: string, baseUrl: any) => Promise<any>;
}
export declare const test: () => Promise<void>;
export * as API from './api';

75
index.js Normal file
View File

@ -0,0 +1,75 @@
"use strict";
/*
export * from './paths';
export * from './format';
export * from './log';
export * from './types';
export * from './formatter';
export * from './main';
export * from './test';
*/
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.test = exports.Magento = exports.getToken = void 0;
const configuration = require("./configuration");
const os_1 = require("os");
const read_1 = require("@plastichub/fs/read");
const path = require("path");
const api_1 = require("./api");
exports.getToken = (url, user, password) => __awaiter(void 0, void 0, void 0, function* () {
const api = new api_1.IntegrationAdminTokenServiceV1Api({
basePath: url
});
return api.integrationAdminTokenServiceV1CreateAdminAccessTokenPost({
username: user,
password: password
});
});
class Magento {
}
exports.Magento = Magento;
Magento.token = null;
Magento.apiConfig = null;
Magento.init = (baseUrl, username, password) => __awaiter(void 0, void 0, void 0, function* () {
const token = yield exports.getToken(baseUrl, username, password);
api_1.setAuth({
headers: {
'Authorization': `Bearer ${token}`
}
});
Magento.token = token;
Magento.apiConfig = new configuration.Configuration({
basePath: baseUrl,
accessToken: token
});
return Magento.token;
});
Magento.initWithProfile = (profilePath, baseUrl) => __awaiter(void 0, void 0, void 0, function* () {
if (profilePath[0] === '~') {
profilePath = path.join(os_1.homedir(), profilePath.slice(1));
}
const profile = read_1.sync(path.resolve(profilePath), 'json') || {};
return Magento.init(baseUrl || profile.baseUrl, profile.username, profile.password);
});
exports.test = () => __awaiter(void 0, void 0, void 0, function* () {
process.on('unhandledRejection', (reason) => {
console.error('Unhandled rejection, reason: ', reason);
});
yield Magento.initWithProfile('~/.magento.json', 'https://shop.plastic-hub.com/rest/all');
// await Magento.init('https://shop.plastic-hub.com/rest/all', 'admin', '');
console.log('Magento API Config', Magento.apiConfig);
const storeApi = new api_1.StoreStoreRepositoryV1Api(Magento.apiConfig);
const stores = yield storeApi.storeStoreRepositoryV1GetListGet({});
console.log('stores', stores);
});
exports.API = require("./api");
exports.test();
//# sourceMappingURL=index.js.map

1
index.js.map Normal file
View File

@ -0,0 +1 @@
{"version":3,"file":"index.js","sourceRoot":"","sources":["src/index.ts"],"names":[],"mappings":";AAAA;;;;;;;;EAQE;;;;;;;;;;;;AAEF,iDAAiD;AAEjD,2BAA6B;AAC7B,8CAAmD;AACnD,6BAA6B;AAE7B,+BAGc;AAGD,QAAA,QAAQ,GAAG,CAAO,GAAG,EAAE,IAAI,EAAE,QAAQ,EAAmB,EAAE;IAEnE,MAAM,GAAG,GAAG,IAAI,uCAAiC,CAAC;QAC9C,QAAQ,EAAE,GAAG;KAChB,CAAC,CAAC;IACH,OAAO,GAAG,CAAC,wDAAwD,CAAC;QAChE,QAAQ,EAAE,IAAI;QACd,QAAQ,EAAE,QAAQ;KACrB,CAAC,CAAC;AACP,CAAC,CAAA,CAAA;AAED,MAAa,OAAO;;AAApB,0BAyBC;AAxBU,aAAK,GAAG,IAAI,CAAC;AACb,iBAAS,GAAG,IAAI,CAAC;AACjB,YAAI,GAAG,CAAO,OAAe,EAAE,QAAgB,EAAE,QAAgB,EAAE,EAAE;IACxE,MAAM,KAAK,GAAG,MAAM,gBAAQ,CAAC,OAAO,EAAE,QAAQ,EAAE,QAAQ,CAAC,CAAC;IAC1D,aAAO,CAAC;QACJ,OAAO,EAAE;YACL,eAAe,EAAE,UAAU,KAAK,EAAE;SACrC;KACJ,CAAC,CAAC;IACH,OAAO,CAAC,KAAK,GAAG,KAAK,CAAC;IACtB,OAAO,CAAC,SAAS,GAAG,IAAI,aAAa,CAAC,aAAa,CAAC;QAChD,QAAQ,EAAE,OAAO;QACjB,WAAW,EAAE,KAAK;KACrB,CAAC,CAAC;IACH,OAAO,OAAO,CAAC,KAAK,CAAC;AACzB,CAAC,CAAA,CAAA;AAEM,uBAAe,GAAG,CAAO,WAAmB,EAAE,OAAO,EAAE,EAAE;IAC5D,IAAI,WAAW,CAAC,CAAC,CAAC,KAAK,GAAG,EAAE;QACxB,WAAW,GAAG,IAAI,CAAC,IAAI,CAAC,YAAO,EAAE,EAAE,WAAW,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;KAC5D;IACD,MAAM,OAAO,GAAQ,WAAI,CAAC,IAAI,CAAC,OAAO,CAAC,WAAW,CAAC,EAAE,MAAM,CAAC,IAAI,EAAE,CAAC;IACnE,OAAO,OAAO,CAAC,IAAI,CAAC,OAAO,IAAI,OAAO,CAAC,OAAO,EAAE,OAAO,CAAC,QAAQ,EAAE,OAAO,CAAC,QAAQ,CAAC,CAAC;AACxF,CAAC,CAAA,CAAA;AAEQ,QAAA,IAAI,GAAG,GAAS,EAAE;IAE3B,OAAO,CAAC,EAAE,CAAC,oBAAoB,EAAE,CAAC,MAAc,EAAE,EAAE;QAChD,OAAO,CAAC,KAAK,CAAC,+BAA+B,EAAE,MAAM,CAAC,CAAC;IAC3D,CAAC,CAAC,CAAC;IAEH,MAAM,OAAO,CAAC,eAAe,CAAC,iBAAiB,EAAE,uCAAuC,CAAC,CAAC;IAC1F,4EAA4E;IAC5E,OAAO,CAAC,GAAG,CAAC,oBAAoB,EAAE,OAAO,CAAC,SAAS,CAAC,CAAC;IACrD,MAAM,QAAQ,GAAG,IAAI,+BAAyB,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;IAClE,MAAM,MAAM,GAAG,MAAM,QAAQ,CAAC,gCAAgC,CAAC,EAAE,CAAC,CAAC;IACnE,OAAO,CAAC,GAAG,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC;AAClC,CAAC,CAAA,CAAA;AAED,+BAA6B;AAE7B,YAAI,EAAE,CAAC"}

View File

@ -1,112 +1,49 @@
{
"name": "@plastichub/cli",
"version": "1.0.10",
"name": "@plastichub/magento",
"version": "1.0.13",
"description": "",
"main": "./build/main.js",
"main": "./main.js",
"types": "./index.d.ts",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"help": "node build/main.js --help",
"build": "tsc -p .",
"typings": "tsc -p . --declaration",
"dev": "tsc -w -p ."
},
"repository": {
"type": "git",
"url": "git+https://github.com/plastic-hub/lang.git"
"url": "git+https://git.osr-plastic.org/osr-plastic/magento-ts-client.git"
},
"author": "",
"bin": {
"ph-cli": "build/main.js"
"magento-client": "build/main.js"
},
"license": "ISC",
"bugs": {
"url": "https://github.com/plastic-hub/lang/issues"
"url": "https://git.osr-plastic.org/osr-plastic/magento-ts-client/issues"
},
"homepage": "https://github.com/plastic-hub/lang#readme",
"homepage": "https://git.osr-plastic.org/osr-plastic/magento-ts-client",
"dependencies": {
"@plastichub/fs": "^0.13.21",
"@plastichub/osr-sync": "0.0.22",
"@types/bluebird": "^3.5.29",
"add": "^2.0.6",
"apify": "^0.17.0",
"axios": "^0.21.1",
"bluebird": "^3.7.2",
"@plastichub/core": "^0.1.4",
"@plastichub/fs": "^0.13.25",
"chalk": "^2.4.1",
"cheerio": "^1.0.0-rc.3",
"chokidar": "^3.3.1",
"discourser": "^1.0.0",
"download": "^8.0.0",
"duration-timestamp": "^2.3.0",
"errlop": "^2.1.0",
"escape-html": "^1.0.3",
"cli-spinners": "^2.6.0",
"defaults": "^1.0.3",
"fast-glob": "^3.1.1",
"filenamify": "^4.1.0",
"googleapis": "^39.2.0",
"inline-css": "^2.6.2",
"isomorphic-unfetch": "^3.0.0",
"js-beautify": "^1.11.0",
"jsome": "^2.5.0",
"json-to-pretty-yaml": "^1.2.2",
"lodash": "^4.17.10",
"markdown-table": "^2.0.0",
"moment": "^2.26.0",
"monocle-ts": "^1.2.0",
"native-promise-pool": "^3.0.0",
"ora": "^2.1.0",
"partial.lenses": "^13.13.2",
"pretty": "^2.0.0",
"puppeteer": "^5.2.1",
"ramda": "^0.25.0",
"portable-fetch": "^3.0.0",
"readline": "^1.3.0",
"regexp.escape": "^1.1.0",
"sanitize-filename": "^1.6.3",
"showdown": "^1.9.1",
"simple-git": "^2.6.0",
"slash": "^3.0.0",
"slugify": "^1.4.6",
"source-map-support": "^0.5.16",
"ts-node-dev": "^1.0.0-pre.44",
"tslint": "^5.10.0",
"turndown": "^7.0.0",
"typescript": "^3.7.4",
"which": "^2.0.2",
"yargonaut": "^1.1.4",
"yargs": "^15.0.2"
"yargs": "^15.0.2",
"yarn": "^1.22.10"
},
"devDependencies": {
"@bevry/links": "^1.1.1",
"@bevry/update-contributors": "^1.0.1",
"@types/node-fetch": "^2.5.7",
"@typescript-eslint/eslint-plugin": "^2.30.0",
"@typescript-eslint/parser": "^2.30.0",
"@types/chalk": "^2.2.0",
"@types/cheerio": "^0.22.15",
"@types/chokidar": "^2.1.3",
"@types/download": "^6.2.4",
"@types/inline-css": "0.0.32",
"@types/js-beautify": "^1.8.2",
"@types/lodash": "^4.14.110",
"@types/moment": "^2.13.0",
"@types/node": "^13.1.1",
"@types/ora": "^1.3.4",
"@types/pretty": "^2.0.0",
"@types/puppeteer": "^1.5.0",
"@types/ramda": "^0.25.51",
"@types/showdown": "^1.9.3",
"@types/which": "^1.3.2",
"@types/yargs": "^13.0.4",
"@xblox/core": "^0.0.19",
"assert-helpers": "^6.1.0",
"eslint": "^6.8.0",
"eslint-config-bevry": "^3.3.0",
"eslint-config-prettier": "^6.11.0",
"eslint-plugin-prettier": "^3.1.3",
"jsdom": "^16.2.2",
"kava": "^4.4.0",
"prettier": "^2.0.5",
"projectz": "^1.19.1",
"surge": "^0.21.3",
"typedoc": "^0.17.6",
"valid-directory": "^1.6.0",
"valid-module": "^1.0.0"
"@types/yargs": "^13.0.4"
}
}

57618
src/api.ts

File diff suppressed because it is too large Load Diff

66
src/configuration.ts Normal file
View File

@ -0,0 +1,66 @@
// tslint:disable
/**
* Magento Community
* No description provided (generated by Swagger Codegen https://github.com/swagger-api/swagger-codegen)
*
* OpenAPI spec version: 2.4
*
*
* NOTE: This class is auto generated by the swagger code generator program.
* https://github.com/swagger-api/swagger-codegen.git
* Do not edit the class manually.
*/
export interface ConfigurationParameters {
apiKey?: string | ((name: string) => string);
username?: string;
password?: string;
accessToken?: string | ((name: string, scopes?: string[]) => string);
basePath?: string;
}
export class Configuration {
/**
* parameter for apiKey security
* @param name security name
* @memberof Configuration
*/
apiKey?: string | ((name: string) => string);
/**
* parameter for basic security
*
* @type {string}
* @memberof Configuration
*/
username?: string;
/**
* parameter for basic security
*
* @type {string}
* @memberof Configuration
*/
password?: string;
/**
* parameter for oauth2 security
* @param name security name
* @param scopes oauth2 scope
* @memberof Configuration
*/
accessToken?: string | ((name: string, scopes?: string[]) => string);
/**
* override base path
*
* @type {string}
* @memberof Configuration
*/
basePath?: string;
constructor(param: ConfigurationParameters = {}) {
this.apiKey = param.apiKey;
this.username = param.username;
this.password = param.password;
this.accessToken = param.accessToken;
this.basePath = param.basePath;
}
}

2
src/custom.d.ts vendored Normal file
View File

@ -0,0 +1,2 @@
declare module 'portable-fetch';
declare module 'url';

View File

@ -1,52 +0,0 @@
#!/bin/sh
# ref: https://help.github.com/articles/adding-an-existing-project-to-github-using-the-command-line/
#
# Usage example: /bin/sh ./git_push.sh wing328 swagger-petstore-perl "minor update"
git_user_id=$1
git_repo_id=$2
release_note=$3
if [ "$git_user_id" = "" ]; then
git_user_id=""
echo "[INFO] No command line input provided. Set \$git_user_id to $git_user_id"
fi
if [ "$git_repo_id" = "" ]; then
git_repo_id=""
echo "[INFO] No command line input provided. Set \$git_repo_id to $git_repo_id"
fi
if [ "$release_note" = "" ]; then
release_note=""
echo "[INFO] No command line input provided. Set \$release_note to $release_note"
fi
# Initialize the local directory as a Git repository
git init
# Adds the files in the local repository and stages them for commit.
git add .
# Commits the tracked changes and prepares them to be pushed to a remote repository.
git commit -m "$release_note"
# Sets the new remote
git_remote=`git remote`
if [ "$git_remote" = "" ]; then # git remote not defined
if [ "$GIT_TOKEN" = "" ]; then
echo "[INFO] \$GIT_TOKEN (environment variable) is not set. Using the git credential in your environment."
git remote add origin https://github.com/${git_user_id}/${git_repo_id}.git
else
git remote add origin https://${git_user_id}:${GIT_TOKEN}@github.com/${git_user_id}/${git_repo_id}.git
fi
fi
git pull origin master
# Pushes (Forces) the changes in the local repository up to the remote repository
echo "Git pushing to https://github.com/${git_user_id}/${git_repo_id}.git"
git push origin master 2>&1 | grep -v 'To https'

View File

@ -1,6 +1,76 @@
/*
export * from './paths';
export * from './format';
export * from './log';
export * from './types';
export * from './formatter';
export * from './main';
export * from './test';
*/
import * as configuration from './configuration';
import * as debug from '@plastichub/core/debug';
import { homedir } from 'os';
import { sync as read } from '@plastichub/fs/read';
import * as path from 'path';
import {
setAuth, StoreStoreRepositoryV1Api,
IntegrationAdminTokenServiceV1Api
} from './api'
export const getToken = async (url, user, password): Promise<string> => {
const api = new IntegrationAdminTokenServiceV1Api({
basePath: url
});
return api.integrationAdminTokenServiceV1CreateAdminAccessTokenPost({
username: user,
password: password
});
}
export class Magento {
static token = null;
static apiConfig = null;
static init = async (baseUrl: string, username: string, password: string) => {
const token = await getToken(baseUrl, username, password);
setAuth({
headers: {
'Authorization': `Bearer ${token}`
}
});
Magento.token = token;
Magento.apiConfig = new configuration.Configuration({
basePath: baseUrl,
accessToken: token
});
return Magento.token;
}
static initWithProfile = async (profilePath: string, baseUrl) => {
if (profilePath[0] === '~') {
profilePath = path.join(homedir(), profilePath.slice(1));
}
const profile: any = read(path.resolve(profilePath), 'json') || {};
return Magento.init(baseUrl || profile.baseUrl, profile.username, profile.password);
}
}
export const test = async () => {
process.on('unhandledRejection', (reason: string) => {
console.error('Unhandled rejection, reason: ', reason);
});
await Magento.initWithProfile('~/.magento.json', 'https://shop.plastic-hub.com/rest/all');
// await Magento.init('https://shop.plastic-hub.com/rest/all', 'admin', '');
console.log('Magento API Config', Magento.apiConfig);
const storeApi = new StoreStoreRepositoryV1Api(Magento.apiConfig);
const stores = await storeApi.storeStoreRepositoryV1GetListGet({});
console.log('stores', stores);
}
export * as API from './api';
test();

View File

@ -1,66 +1,5 @@
import * as debug from '../..';
import * as path from 'path';
import { isArray, isString } from 'util';
import { files, read, csvToMarkdown, toHTML, md2html, exists } from '../../lib/';
import { html_beautify } from 'js-beautify';
import { sync as mkdir } from '@plastichub/fs/dir';
import { substitute } from '../common/strings';
const md_tables = require('markdown-table');
export const parse_config = (config, root) => {
if (Object.keys(config)) {
for (const key in config) {
let val = config[key];
if (isArray(val)) {
if (key !== 'authors') {
config[key] = md2html(md_tables(val));
}
} else if (isString(val)) {
if (val.endsWith('.csv')) {
const parsed = path.parse(root);
let csv = path.resolve(`${parsed.dir}/${parsed.base}/${val}`) as any;
debug.info("Parsing CSV " + csv);
if (exists(csv)) {
csv = read(csv) || "";
try {
csv = md2html(csvToMarkdown(csv));
config[key] = csv;
} catch (e) {
debug.error(`Error converting csv to md ${val}`);
}
} else {
debug.error(`Can't find CSV file at ${csv}`, parsed);
}
}
}
}
}
}
export const md_edit_wrap = (content, f, prefix = '', context = '') => {
return html_beautify(`<div prefix="${prefix}" file="${path.parse(f).base}" context="${context}" class="fragment">${content}</div>`);
}
export const read_fragments = (src, config, prefix = '', context = '') => {
if (!exists(src)) {
debug.warn(`Create template folder ${src}`);
mkdir(src);
}
let fragments = files(src, '*.html');
fragments.map((f) => {
config[path.parse(f).name] = md_edit_wrap(toHTML(f, true), f, prefix, context);
});
fragments = files(src, '*.md');
fragments.map((f) => {
config[path.parse(f).name] = md_edit_wrap(toHTML(f, false), f, prefix, context);
});
return config;
}
const _resolve = (config) => {
for (const key in config) {
if (config[key] && typeof config[key] == 'string') {

View File

@ -1,31 +1,16 @@
#!/usr/bin/env node
import { defaults } from './_cli'; defaults();
import * as cli from 'yargs';
import { register as registerMarkdown } from './commands/markdown'; registerMarkdown(cli);
import { register as registerPDF2JPG } from './commands/pdf2jpg'; registerPDF2JPG(cli);
import { register as registerSVG2JPG } from './commands/svg2jpg'; registerSVG2JPG(cli);
import { register as registerWatch } from './commands/watch'; registerWatch(cli);
import { register as registerAcademy } from './commands/academy'; registerAcademy(cli);
import { register as registerOneArmy } from './commands/forumDownloader'; registerOneArmy(cli);
import { register as registerTest } from './commands/tests'; registerTest(cli);
import { register as registerV4Bom } from './commands/v4/bom'; registerV4Bom(cli);
import { register as registerBazarProduct } from './commands/bazar/product'; registerBazarProduct(cli);
import { register as registerBazarVendor } from './commands/bazar/vendor'; registerBazarVendor(cli);
import { register as registerLibrary } from './commands/library'; registerLibrary(cli);
import { register as registerSanitize } from './commands/common/sanitize-filename'; registerSanitize(cli);
import { register as registerGHPIndex } from './commands/github/jekyll_machine'; registerGHPIndex(cli);
import { register as registerGHProduct } from './commands/github/jekyll_product'; registerGHProduct(cli);
import { register as registerProductDataSheet } from './commands/github/jekyll_product_datasheet'; registerProductDataSheet(cli);
import { register as registerGHProjectIndex } from './commands/github/project_index'; registerGHProjectIndex(cli);
import { register as registerMD_Thumbs } from './commands/github/md_thumbs'; registerMD_Thumbs(cli);
import { register as registerMD_Page } from './commands/github/page'; registerMD_Page(cli);
import { register as registerHowtoBackup } from './commands/howto'; registerHowtoBackup(cli);
import { register as registerOADownload } from './commands/onearmy/download'; registerOADownload(cli);
import { register as registerDiscourse } from './commands/forum/discourse'; registerDiscourse(cli);
import * as cli from 'yargs';
// import { register as registerMarkdown } from './commands/markdown'; registerMarkdown(cli);
const argv = cli.argv;
// import { test } from './test';
// test();
if (argv.h || argv.help) {
cli.showHelp();
process.exit();

View File

@ -1,106 +0,0 @@
const Registry = require('rage-edit').Registry;
const SOFTWARE_CLASSES = 'HKCU\\Software\\Classes\\';
export const registerCommand = async options => {
if (!options) throw new Error('options are empty');
const { name, icon, command, menu } = options;
if (!name) throw new Error('name is not specified');
if (!command) throw new Error('command is not specified');
if (!menu) throw new Error('menuName is not specified');
try {
await Registry.set(`${SOFTWARE_CLASSES}*\\shell\\${name}`);
await Registry.set(`${SOFTWARE_CLASSES}*\\shell\\${name}`, '', menu);
if (icon) await Registry.set(`${SOFTWARE_CLASSES}*\\shell\\${name}`, 'Icon', (icon.endsWith('.exe') ? `${icon},0` : icon));
await Registry.set(`${SOFTWARE_CLASSES}*\\shell\\${name}\\command`, '', `"${command}" "%1"`);
} catch (e) {
return Promise.reject(e);
}
return Promise.resolve();
};
export const registerDirectoryCommand = async options => {
if (!options) throw new Error('options are empty');
const { name, icon, command, menu } = options;
if (!name) throw new Error('name is not specified');
if (!command) throw new Error('command is not specified');
if (!menu) throw new Error('menu is not specified');
try {
await Registry.set(`${SOFTWARE_CLASSES}Directory\\shell\\${name}`);
await Registry.set(`${SOFTWARE_CLASSES}Directory\\shell\\${name}`, '', menu);
if (icon) await Registry.set(`${SOFTWARE_CLASSES}Directory\\shell\\${name}`, 'Icon', (icon.endsWith('.exe') ? `${icon},0` : icon));
await Registry.set(`${SOFTWARE_CLASSES}Directory\\shell\\${name}\\command`, '', `"${command}" "%1"`);
} catch (e) {
return Promise.reject(e);
}
return Promise.resolve();
};
export const registerOpenWithCommand = async (extensions, options) => {
if (!extensions || !extensions.length) throw new Error('extensions is not specified');
if (!options) throw new Error('options are empty');
const { name, command } = options;
if (!name) throw new Error('name is not specified');
if (!command) throw new Error('command is not specified');
try {
await Promise.all((await findExtensionNames(extensions)).map(async n => {
await Registry.set(`${SOFTWARE_CLASSES}${n}`);
await Registry.set(`${SOFTWARE_CLASSES}${n}\\shell\\${name}`);
await Registry.set(`${SOFTWARE_CLASSES}${n}\\shell\\${name}\\command`, '', `"${command}" "%1"`);
}));
} catch (e) {
return Promise.reject(e);
}
return Promise.resolve();
};
export const removeCommand = async name => {
if (!name) throw new Error('name is not specified');
try {
await Registry.delete(`${SOFTWARE_CLASSES}*\\shell\\${name}`);
} catch (e) {
return Promise.reject(e);
}
return Promise.resolve();
};
export const removeDirectoryCommand = async name => {
if (!name) throw new Error('name is not specified');
try {
await Registry.delete(`${SOFTWARE_CLASSES}Directory\\shell\\${name}`);
} catch (e) {
return Promise.reject(e);
}
return Promise.resolve();
};
export const removeOpenWithCommand = async (extensions, name) => {
if (!extensions) throw new Error('extensions is not specified');
if (!name) throw new Error('name is not specified');
try {
await Promise.all((await findExtensionNames(extensions)).map(async n => await Registry.delete(`${SOFTWARE_CLASSES}${n}\\shell\\${name}`)));
} catch (e) {
return Promise.reject(e);
}
return Promise.resolve();
};
async function findExtensionNames (exts) {
const { ses_root } = await Registry.get('HKCR');
return Promise.all(Object.keys(ses_root).filter(e => exts.includes(e)).map(async k => (await Registry.get(`HKCR\\${k}`)).$values['']));
}

View File

@ -1,95 +0,0 @@
import { Browser, launch, Page, Response } from 'puppeteer';
import { inspect, error, debug } from '../../log';
import { capture_requests, capture_responses } from './network';
let instance: Scope;
import * as path from 'path';
import { URL } from 'url';
export const STATS_SUFFIX = '_stats.json';
export const SESSION_EVENTS_SUFFIX = '_session.json';
export const TRACE_SUFFIX = '_trace.json';
const included_categories = ['devtools.timeline'];
const _url_short = (url: string) =>
new URL(url).hostname;
const _date_suffix = () =>
new Date().toLocaleTimeString().replace(/:/g, '_');
const _random_suffix = () =>
Math.random() * 100;
const _default_filename = (url: string) =>
`${_url_short(url)}_${_random_suffix()}`;
export const default_path = (cwd: string, url: string) =>
`${path.join(cwd, _default_filename(url))}${STATS_SUFFIX}`;
export const default_session_events_path = (cwd: string, url: string) =>
`${path.join(cwd || process.cwd(), 'sessions', _default_filename(url))}${SESSION_EVENTS_SUFFIX}`;
export const default_trace_path = (cwd: string, url: string) =>
`${path.join(cwd, _default_filename(url))}${TRACE_SUFFIX}`;
export class Scope {
browser!: Browser;
context!: any;
page!: Page;
args!: any;
requests: any[] = [];
responses: Response[] = [];
eventBeacons: any[] = [];
mutationBeacons: any[] = [];
sessionSuffix: string = '';
onResponse;
onRequest;
async init() {
this.sessionSuffix = ' - ' + new Date().getTime();
const args = [
'--no-sandbox',
'--disable-setuid-sandbox',
'--disable-infobars',
'--window-position=0,0',
'--ignore-certifcate-errors',
'--ignore-certifcate-errors-spki-list',
'--user-agent="Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3312.0 Safari/537.36"'
];
this.browser = await launch({ headless: this.args.headless === 'true', devtools: true,args:args});
// const context = await this.browser.createIncognitoBrowserContext();
this.page = await this.browser.newPage();
// this.page = await context.newPage();
this.page.on('console', msg => {
// error('Browser error:', msg);
});
this.page.on('error', msg => error('Browser Error:', msg));
// this.page.on('pageerror', msg => error('Browser Page Error:', msg));
// this.page.on('requestfailed', msg => error('Browser Page Request Error:', msg));
//capture_requests(this, this.page);
//capture_responses(this, this.page);
// this.args.disableRequests !== 'true' && capture_requests(this, this.page);
// this.args.disableResponses !== 'true' && capture_requests(this, this.page);
// capture_responses(this, this.page);
const page2 = this.page as any;
//page2.setCacheEnabled(false);
/*
await page2._client.send('Security.setOverrideCertificateErrors', {
override: true
});
*/
await page2._client.on('Security.certificateError', (event: any) => {
page2._client.send('Security.handleCertificateError', {
eventId: event.eventId,
action: 'continue' // ignore error and continue request
})
})
}
}
export const getScope = (cliArgs?: any) => {
if (!instance) {
instance = new Scope();
instance.args = cliArgs;
}
return instance;
}

View File

@ -1,25 +0,0 @@
import { NavigationOptions } from 'puppeteer';
export const defaultTenant = 1;
export const userSessionsTab = (base: string) => `${base}/e/${defaultTenant}/#usersearchoverview;gtf=l_2_HOURS`;
export const loginUrl = (base: string) => `${base}/login`;
export const loginUrlDemoDev = () => `https://proxy-dev.dynatracelabs.com/sso/ProxyLocator.jsp`;
export const defaultPageOptions = (): NavigationOptions => {
return {
timeout: 5000,
waitUntil: 'networkidle2'
}
}
export const replay_api_overview = 'uemshareddetails/rumoverviewdata/usersearchoverview';
const ts = () => {
const d = new Date();
return d.getHours() + '_' + d.getMinutes() + '_' + d.getSeconds();
}
export const sessionName = (url?: string) => `Pupeteer :${ts()}`;
export const maxSessionWaitingTime = 1000 * 60 * 3;
export const responseRetryTime = 1000 * 8;
export const defaultMutationRoot = '#mutationsRoot';
export const defaultMutationTag = 'div';
export const defaultHeavyMutations = 2000;
export const defaultMediumMutations = 500;

View File

@ -1,186 +0,0 @@
import { launch, Page } from 'puppeteer'
import { readFileSync } from 'fs';
import * as moment from 'moment';
import { sync as unlink } from '@plastichub/fs/remove';
import { async as iterator } from '@plastichub/fs/iterator';
import {
debug, inspect,
Options, TraceEntry, TraceTiming,
default_trace_path,
ReportEntry,
NetworkReportEntry,
sizeToString,
log,
spinner,
STATS_SUFFIX,
TRACE_SUFFIX
} from '../../';
import { end_time } from './times';
import { find_time } from './trace';
import { rl } from './stdin';
import { report, find_report, get_report } from './report';
import { IProcessingNode } from '@plastichub/fs/interfaces';
const included_categories = ['devtools.timeline'];
export class Puppeteer {
static clean(url: string, options: Options) {
iterator(options.cwd, {
matching: [`*${STATS_SUFFIX}`, `*${TRACE_SUFFIX}`]
}).then((it) => {
let node: IProcessingNode = null;
while (node = it.next()) {
unlink(node.path);
}
})
}
static async begin(url: string, options: Options) {
const browser = await launch({
headless: options.headless,
devtools: false
});
return await browser.newPage();
}
static async crawler(url: string, options?: Options) {
const page = await this.begin(url, options);
}
static async repl(url: string, options?: Options) {
const page = await this.begin(url, options);
page.on('console', msg => inspect('Console Message:', msg.text()));
await page.goto(url, {
timeout: 600000,
waitUntil: 'networkidle0'
});
const readline = rl(`${url}#`, (line: string) => {
page.evaluate(line).then((results) => {
inspect(`Did evaluate ${line} to `, results);
})
}, () => this.end(page));
}
static async end(page: Page) {
const browser = await page.browser();
await page.close();
await browser.close();
}
static async summary(url: string, options?: Options) {
const browser = await launch({
headless: options.headless,
devtools: true
});
const page = await browser.newPage();
await page.goto(url, {
timeout: 600000,
waitUntil: 'networkidle0'
});
const metrics = await page.metrics();
await this.end(page);
return metrics;
}
static async detail(url: string, options?: Options) {
const network_stats = report();
const ReceivedTotal = get_report(network_stats, 'Received Total');
const ReceivedStyleSheets = get_report(network_stats, 'Received Stylesheets');
const ReceivedScripts = get_report(network_stats, 'Received Scripts');
const ReceivedHTML = get_report(network_stats, 'Received HTML');
const ReceivedImages = get_report(network_stats, 'Received Images');
const ReceivedJSON = get_report(network_stats, 'Received JSON');
const ReceivedFonts = get_report(network_stats, 'Received Fonts');
const ReceivedBinary = get_report(network_stats, 'Received Binary');
const MimeMap = {
'application/javascript': ReceivedScripts,
'text/javascript': ReceivedScripts,
'text/css': ReceivedStyleSheets,
'text/html': ReceivedHTML,
'image/png': ReceivedImages,
'image/gif': ReceivedImages,
'image/svg+xml': ReceivedImages,
'application/json': ReceivedJSON,
'application/octet-stream': ReceivedBinary,
'font/woff2': ReceivedFonts,
'application/font-woff2': ReceivedFonts
}
const traceFile = default_trace_path(options.cwd, url);
const page = await this.begin(url, options);
await page.tracing.start({
path: traceFile,
categories: included_categories
});
await page.goto(url, {
timeout: 600000,
waitUntil: 'networkidle0'
});
const metrics = await (page as any)._client.send('Performance.getMetrics');
const nowTs = new Date().getTime();
// const navigationStart = getTimeFromMetrics(metrics, 'NavigationStart');
const navigationStart = find_time(metrics, 'Timestamp') + nowTs;
await page.tracing.stop();
// --- extracting data from trace.json ---
const tracing = JSON.parse(readFileSync(traceFile, 'utf8'));
const dataReceivedEvents = tracing.traceEvents.filter(x => x.name === 'ResourceReceivedData');
const dataResponseEvents = tracing.traceEvents.filter(x => x.name === 'ResourceReceiveResponse');
// find resource in responses or return default empty
const content_response = (requestId: string): TraceEntry => dataResponseEvents.find((x) =>
x.args.data.requestId === requestId)
|| { args: { data: { encodedDataLength: 0 } } };
const report_per_mime = (mime: string): NetworkReportEntry => MimeMap[mime] || get_report(network_stats, mime);
// our iteration over the trace
// @TODO: convert to a better tree structure to avoid O(n) lookups
// @TODO: emit to extensions: events & aspects
// @TODO: calculate times
// @TODO: filter
// @TODO: options.mask
// @TODO: this iterator might get async
ReceivedTotal.value = dataReceivedEvents.reduce((first, x) => {
const content = content_response(x.args.data.requestId);
const data = content.args.data;
const report = report_per_mime(data.mimeType);
if (data.fromCache === false) {
report.value += x.args.data.encodedDataLength
report.count++;
} else {
report.cached_count++;
}
ReceivedTotal.count++;
return first + x.args.data.encodedDataLength;
}, ReceivedTotal.value);
// calulate finals
[ReceivedTotal, ReceivedHTML, ReceivedImages, ReceivedJSON,
ReceivedScripts, ReceivedFonts, ReceivedBinary
].forEach((r) => r.formatted = sizeToString(r.value))
// --- end extracting data from trace.json ---
let results = [];
// lights off
await this.end(page);
return {
times: [],
network: network_stats
}
}
}

View File

@ -1,176 +0,0 @@
import { Page, Request, Response } from 'puppeteer';
import { sessionName, maxSessionWaitingTime, defaultPageOptions, userSessionsTab } from './constants';
import * as debug from '../../log';
import { Scope } from './Scope';
import { parse } from 'url';
import { navigateToUserSessions } from './processes';
const debugRequests = true;
const debugResponses = false;
export const default_postdata = (request: Request): any => request.postData && request.postData() || {};
export type ResponseMatch = (request: any) => boolean;
export const HasUserSessions = (request: Request) => (default_postdata(request).users)
export const MyUserSessions = (url: string, request: Request) => SessionWithName(request, sessionName(url));
export const SessionWithName = (request: Request, name: string) => {
const data = default_postdata(request).users || [];
return data.find((user: any) => user.id === name)
}
export type ResponseResolve = Response & {
data: any;
}
const default_prepare = (requests: Request[]): Request[] => {
return requests;
};
const default_filter_json = (r: Request) => ((r.headers()['content-type'] || '').startsWith('application/json;')) === true;
const responses = async function (requests: Request[]) { return Promise.all(requests.map(r => r.response()!.json())) };
export const findRequest = (url: string, requests: Request[], match?: ResponseMatch): Request[] => {
url = decodeURIComponent(url);
if (!match) {
return requests.filter((request) => request.url().indexOf(url) !== -1);
} else {
const results = requests.filter((request) => request.url().indexOf(url) !== -1);
return results.filter((r) => match!(r));
}
}
export function waitForResponse(url: string, scope: Scope, match: ResponseMatch, timeout: number = 5000): Promise<any[]> {
return new Promise((resolve, reject) => {
setTimeout(() => {
try {
let requests = default_prepare(scope.requests).filter(default_filter_json).filter(r => r.response() != null);
requests = requests.filter((request) => request.url().indexOf(url) !== -1);
responses(requests).then((responses) => {
const ret = responses.filter(match);
if (ret.length) {
resolve(ret);
} else {
reject('cant find anything yet');
}
});
} catch (error) {
debug.error('waitForResponse Error ', error);
}
}, timeout);
})
}
export function waitForResponseNTimes(url: string, scope: Scope, match: ResponseMatch, timeout: number = 5000) {
return new Promise((resolve, reject) => {
const maxTime = maxSessionWaitingTime;
const retryTime = 8000;
let reachedTimeOut = false;
let interval: any = null;
interval = setInterval(() => {
if (reachedTimeOut) {
clearInterval(interval);
debug.error('reached max');
reject('reached maximum timeout');
return;
}
onReload(scope).then(() => {
scope.page.reload().then(() => {
debug.info('retry ');
waitForResponse(url, scope, match, retryTime).then((session) => {
debug.inspect('got my session', session);
clearInterval(interval);
resolve(session);
}).catch((e) => {
debug.error('found nothing');
})
}).catch((e) => {
console.error('error loading page : ', e);
});
});
}, retryTime);
setTimeout(() => {
reachedTimeOut = true;
clearInterval(interval);
reject('max timeout reached');
}, maxTime);
});
};
export async function capture_request(where: any[], request: Request) {
debugRequests && debug.inspect('Request', { url: request.url(), data: request.postData() });
where.push({ url: request.url(), data: await request.postData(), request: request });
debugRequests && debug.inspect('requests', where.map(r => r.url));
}
export async function capture_response(where: any[], response: Response) {
debugResponses && debug.inspect('Response', { url: response.url(), data: await response.json() });
where.push(response);
}
export async function capture_requests(scope: Scope, page: Page) {
await page.setRequestInterception(true);
scope.requests = [];
page.on('request', (interceptedRequest: Request) => {
if(scope.onRequest){
scope.onRequest(interceptedRequest, scope);
return;
}
try {
const url = decodeURIComponent(interceptedRequest.url());
const parsed = parse(url, true);
if (url.includes('.css') || url.includes('.svg')) {
interceptedRequest.abort();
return;
}
const query = parsed.query;
const isJson = (interceptedRequest.headers()['content-type'] || '').startsWith('application/json') === true;
if (isJson) {
// capture_request(scope.requests, interceptedRequest);
//debugRequests && debug.inspect('q ' + query['contentType'] + ' ' + url);
}
interceptedRequest.continue();
} catch (e) {
debug.error('error parsing request ', e);
}
});
}
export async function capture_responses(scope: Scope, page: Page) {
try {
// await page.setRequestInterception(true);
} catch (e) {
debug.error('error intercepting responses', e);
}
scope.responses = [];
page.on('response', response => {
try {
const isJson = (response.headers()['content-type'] || '').startsWith('application/json;') === true;
const url = response.url();
if (response.status() === 200) {
if (isJson) {
capture_response(scope.responses, response);
}
if (scope.onResponse) {
scope.onResponse(response, scope);
}
} else {
debugResponses && debug.error(`Error loading ${url} : ${response.status()}`);
}
} catch (e) {
debugResponses && debug.error('Error parsing response');
}
});
}
export async function onReload(scope: Scope) {
scope.requests = [];
try {
await scope.page.setRequestInterception(false);
} catch (e) {
}
await scope.page.setRequestInterception(true);
}

View File

@ -1,78 +0,0 @@
import { Page, Request } from 'puppeteer';
import { Options } from './types';
import { loginUrl, defaultPageOptions, userSessionsTab, loginUrlDemoDev } from './constants';
export async function loginFrontEnd(page: Page, options: Options) {
// await page.goto(loginUrl(options.dynatraceUrl), defaultPageOptions());
await page.type('#user', 'admin');
await page.type('#password', 'admin');
await page.click('#login-form > .maindiv > .logindiv > .submitdiv > .button');
await page.waitForSelector('.tenant-selector');
await page.click('.textboxdiv > .tenant-selector:nth-child(2)');
}
export async function loginDemoDev(page: Page, options: Options) {
await page.goto(loginUrlDemoDev(), defaultPageOptions());
await page.type('#IDToken1', 'guenter.baumgart@ruxit.com');
await page.click('.maindiv > .logindiv > form > div > #formsubmit');
return new Promise((resolve) => {
setTimeout(() => {
resolve(1);
console.log('time out');
}, 20 * 1000)
});
console.log('logged in 1/2!');
/*
const puppeteer = require('puppeteer');
(async () => {
const browser = await puppeteer.launch()
const page = await browser.newPage()
await page.waitForSelector('.logindiv > form > .textboxdiv > .emailLoginIcon > #IDToken1')
await page.click('.logindiv > form > .textboxdiv > .emailLoginIcon > #IDToken1')
await page.waitForSelector('.maindiv > .logindiv > form > div > #formsubmit')
await page.click('.maindiv > .logindiv > form > div > #formsubmit')
const navigationPromise = page.waitForNavigation()
await navigationPromise
await page.waitForSelector('.logindiv > form > .margin-bottom\3A > .passwordIcon > #IDToken2')
await page.click('.logindiv > form > .margin-bottom\3A > .passwordIcon > #IDToken2')
await page.waitForSelector('.logindiv > form > fieldset > div > #IDToken3')
await page.click('.logindiv > form > fieldset > div > #IDToken3')
await page.waitForSelector('form > fieldset > #button-base > div > #loginButton_0')
await page.click('form > fieldset > #button-base > div > #loginButton_0')
await navigationPromise
await navigationPromise
await navigationPromise
await browser.close()
})()
*/
//await page.type('#password', 'admin');
//await page.click('#login-form > .maindiv > .logindiv > .submitdiv > .button');
//await page.waitForSelector('.tenant-selector');
//await page.click('.textboxdiv > .tenant-selector:nth-child(2)');
}
export async function navigateToUserSessions(page: Page, options: Options) {
// await page.goto(userSessionsTab(options.dynatraceUrl), defaultPageOptions());
}
export async function navigateToUserLocalhost(page: Page, options?: Options) {
// await page.goto('http://localhost/', defaultPageOptions());
}

View File

@ -1,40 +0,0 @@
import { NetworkReportEntry } from './types';
const report_item = (name: string): NetworkReportEntry => {
return {
name: name,
value: 0,
formatted: '',
count: 0,
cached_count: 0,
external_count: 0,
local_count: 0,
times: {
end: 0,
formatted: ''
}
}
}
export const report = () => {
return [
report_item('Received Total'),
report_item('Received Stylesheets'),
report_item('Received Scripts'),
report_item('Received HTML'),
report_item('Received JSON'),
report_item('Received Images'),
report_item('Received Fonts'),
report_item('Received Binary')
]
}
export const find_report = (where: any[], name: string) => where.find((media) => media.name === name);
export const get_report = (where: any[], type: string) => {
let record = find_report(where, type);
if (!record) {
record = report_item(type);
where.push(record);
}
return record;
}

View File

@ -1,31 +0,0 @@
import { createInterface, ReadLine } from 'readline';
import { Page } from 'puppeteer';
import chalk from 'chalk';
export const rl = (prompt: string, onLine?: (line: string) => void, onClose?: () => {}) => {
const rl = createInterface({
input: process.stdin,
output: process.stdout,
prompt: chalk.green(prompt)
})
console.log('start stdin: ' + prompt);
rl.prompt()
rl.on('line', (line) => {
if(!line){
return;
}
try {
onLine(line);
} catch (e) {
console.error(e)
rl.prompt()
}
})
rl.on('close', () => {
rl.close()
onClose();
});
return rl;
}

View File

@ -1,12 +0,0 @@
import { TraceEntry } from './types'
export const end_time = (entry: TraceEntry): number => {
const timing = entry.args.data.timing;
const start = timing.requestTime;
const received = entry.ts;
//it might be more accurate to calc this with the header times
const headersReceived = start + timing.receiveHeadersEnd / 1000;
let responseReceived = headersReceived;
responseReceived = Math.min(responseReceived, headersReceived);
responseReceived = Math.max(responseReceived, start);
return Math.max(-1, responseReceived);
}

View File

@ -1,57 +0,0 @@
import { NetworkReportEntry, TraceEntry } from "./types";
export const find_time = (metrics, name) =>
metrics.metrics.find(x => x.name === name).value;
export const all_with_name = (where: NetworkReportEntry[], name: string) =>
where.filter((entry) => entry.name === name);
/*
export const tree = (entries: TraceEntry[]) => {
const tasks = [];
let currentTask;
for (const event of entries) {
// Only look at X (Complete), B (Begin), and E (End) events as they have most data
if (event.ph !== 'X' && event.ph !== 'B' && event.ph !== 'E') continue;
// Update currentTask based on the elapsed time.
// The next event may be after currentTask has ended.
while (
currentTask &&
Number.isFinite(currentTask.endTime) &&
currentTask.endTime <= event.ts
) {
currentTask = currentTask.parent;
}
if (!currentTask) {
// We can't start a task with an end event
if (event.ph === 'E') {
throw new Error('Fatal trace logic error');
}
currentTask = entries._createNewTaskNode(event);
tasks.push(currentTask);
continue;
}
if (event.ph === 'X' || event.ph === 'B') {
// We're starting a nested event, create it as a child and make it the currentTask
const newTask = entries._createNewTaskNode(event, currentTask);
tasks.push(newTask);
currentTask = newTask;
} else {
if (currentTask.event.ph !== 'B') {
throw new Error('Fatal trace logic error');
}
// We're ending an event, update the end time and the currentTask to its parent
currentTask.endTime = event.ts;
currentTask = currentTask.parent;
}
}
return tasks;
}
*/

View File

@ -1,124 +0,0 @@
/////////////////////////////////////////////////////
//
// Application types
//
export enum OutputTarget {
STDOUT = 'console',
FILE = 'file'
}
export enum OutputFormat {
text = 'text',
json = 'json'
}
export interface Options {
// @TODO: support many
url?: string;
format?: OutputFormat;
// @TODO: support many
target?: OutputTarget;
headless?: boolean;
// output path
path?: string;
// @TODO: required to pick profile/config files
cwd?: string;
// @TODO: time of sesssion, mapped to Puppeteer waitUntil, if it's a number, the session will be opened for that
// time window, time=-1 means infinity, useful for repl. sessions
time?: number;
// @TODO: reload interval
reload?: number;
// @TODO: repl. --repl=true=interactive or repl=path to specify script
repl?: string | boolean;
// TODO: colored ouput
colors?: boolean;
}
// options for certain categories as network, rendering,...
export interface OptionEx {
include?: string | string[];
exclude?: string | string[];
query?: string | string[];
}
export type OptionsEx = Options & {
launchOptions?: {
// puppeteer launch options
}
waitOptions?: {
// puppeteer wait options: wait for selector,...
}
replOptions?: {
script?: string;
}
}
export type OutputResult = boolean;
export interface ReportEntry {
name: string;
}
export type NetworkReportEntry = ReportEntry & {
value: number;
formatted: string;
count: number;
cached_count: number;
external_count: number;
local_count: number;
times?: {
end: number,
formatted: string;
}
}
/////////////////////////////////////////////////////
//
// Foreign data types (trace data)
//
// type for a network resource's timing
export interface TraceTiming {
requestTime: number;
proxyStart: number;
proxyEnd: number;
dnsStart: number;
dnsEnd: number;
connectStart: number;
connectEnd: number;
sslStart: number;
sslEnd: number;
workerStart: number;
workerReady: number;
sendStart: number;
sendEnd: number;
receiveHeadersEnd: number;
pushStart: number;
pushEnd: number;
}
export interface TraceData {
requestId: string;
frame: string;
statusCode: number;
mimeType: string;
encodedDataLength: number;
fromCache: boolean;
fromServiceWorker: boolean;
timing: TraceTiming;
}
export interface TraceArgs {
data: TraceData;
}
export interface TraceEntry {
pid: number;
tid: number;
ts: number;
ph: string; // B: begin, | E: end; For async events: S: start, F: finish
cat: string;
name: string;
args: TraceArgs;
tts: number;
s: string;
}

13
src/test.ts Normal file
View File

@ -0,0 +1,13 @@
import * as debug from '@plastichub/core/debug';
import { sync as read } from '@plastichub/fs/read';
import { homedir } from 'os';
import * as path from 'path';
export const test = () => {
debug.error('home dir ' + homedir());
}
test();

42
tools/clean_magento.js Normal file
View File

@ -0,0 +1,42 @@
const read = require('@plastichub/fs/read').sync;
const path = require('path');
const write = require('@plastichub/fs/write').sync;
const content = read('./shop_errors.txt').split('\n');
let api = read('./src/shop/api.ts');
var lineReader = require('readline').createInterface({
input: require('fs').createReadStream('shop_errors.txt')
});
var types = {};
lineReader.on('line', function (line) {
// create a map of the unresolved types
if (line.indexOf('src/shop/api.ts')) {
const type = line.split("'")[1];
if (type) {
if (!types[type]) {
types[type] = false;
}
}
}
});
String.prototype.replaceAll = function (search, replacement) {
var target = this;
return target.split(search).join(replacement);
};
lineReader.on('close', function (e) {
for (var t in types) {
t = t.replace(/[^\x00-\x7F]/g, ""); // non ascii
t = t.replace(/[\u0000-\u001F\u007F-\u009F]/g, "");//typescript term characters
t = t.replace(/[\u{0080}-\u{FFFF}]/gu,"");//terminal plugin special characters
api = api.replaceAll(t, 'any');
}
write('./src/shop/api.ts', api);
});

View File

@ -7,7 +7,7 @@
"noImplicitThis": false,
"alwaysStrict": true,
"sourceMap": true,
"outDir": "./build",
"outDir": "./",
"experimentalDecorators": true,
"emitDecoratorMetadata": true,
"pretty": true,