hotstaq 0.5.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.dockerignore +123 -0
- package/.eslintignore +17 -0
- package/.eslintrc.js +11 -0
- package/.vscode/launch.json +201 -0
- package/.vscode/settings.json +2 -0
- package/.vscode/tasks.json +88 -0
- package/CONTRIBUTING.md +157 -0
- package/LICENSE +21 -0
- package/README.md +128 -0
- package/bin/hotstaq +3 -0
- package/bin/hotstaq.cmd +1 -0
- package/build/src/Hot.d.ts +167 -0
- package/build/src/Hot.d.ts.map +1 -0
- package/build/src/Hot.js +365 -0
- package/build/src/Hot.js.map +1 -0
- package/build/src/HotAPI.d.ts +137 -0
- package/build/src/HotAPI.d.ts.map +1 -0
- package/build/src/HotAPI.js +353 -0
- package/build/src/HotAPI.js.map +1 -0
- package/build/src/HotAgentAPI.d.ts +22 -0
- package/build/src/HotAgentAPI.d.ts.map +1 -0
- package/build/src/HotAgentAPI.js +85 -0
- package/build/src/HotAgentAPI.js.map +1 -0
- package/build/src/HotAgentRoute.d.ts +17 -0
- package/build/src/HotAgentRoute.d.ts.map +1 -0
- package/build/src/HotAgentRoute.js +109 -0
- package/build/src/HotAgentRoute.js.map +1 -0
- package/build/src/HotBuilder.d.ts +52 -0
- package/build/src/HotBuilder.d.ts.map +1 -0
- package/build/src/HotBuilder.js +242 -0
- package/build/src/HotBuilder.js.map +1 -0
- package/build/src/HotClient.d.ts +31 -0
- package/build/src/HotClient.d.ts.map +1 -0
- package/build/src/HotClient.js +19 -0
- package/build/src/HotClient.js.map +1 -0
- package/build/src/HotComponent.d.ts +118 -0
- package/build/src/HotComponent.d.ts.map +1 -0
- package/build/src/HotComponent.js +89 -0
- package/build/src/HotComponent.js.map +1 -0
- package/build/src/HotCreator.d.ts +88 -0
- package/build/src/HotCreator.d.ts.map +1 -0
- package/build/src/HotCreator.js +445 -0
- package/build/src/HotCreator.js.map +1 -0
- package/build/src/HotDB.d.ts +69 -0
- package/build/src/HotDB.d.ts.map +1 -0
- package/build/src/HotDB.js +29 -0
- package/build/src/HotDB.js.map +1 -0
- package/build/src/HotDBConnectionInterface.d.ts +40 -0
- package/build/src/HotDBConnectionInterface.d.ts.map +1 -0
- package/build/src/HotDBConnectionInterface.js +3 -0
- package/build/src/HotDBConnectionInterface.js.map +1 -0
- package/build/src/HotFile.d.ts +134 -0
- package/build/src/HotFile.d.ts.map +1 -0
- package/build/src/HotFile.js +454 -0
- package/build/src/HotFile.js.map +1 -0
- package/build/src/HotGenerator.d.ts +80 -0
- package/build/src/HotGenerator.d.ts.map +1 -0
- package/build/src/HotGenerator.js +342 -0
- package/build/src/HotGenerator.js.map +1 -0
- package/build/src/HotHTTPServer.d.ts +162 -0
- package/build/src/HotHTTPServer.d.ts.map +1 -0
- package/build/src/HotHTTPServer.js +863 -0
- package/build/src/HotHTTPServer.js.map +1 -0
- package/build/src/HotIO.d.ts +47 -0
- package/build/src/HotIO.d.ts.map +1 -0
- package/build/src/HotIO.js +232 -0
- package/build/src/HotIO.js.map +1 -0
- package/build/src/HotLog.d.ts +60 -0
- package/build/src/HotLog.d.ts.map +1 -0
- package/build/src/HotLog.js +126 -0
- package/build/src/HotLog.js.map +1 -0
- package/build/src/HotPage.d.ts +125 -0
- package/build/src/HotPage.d.ts.map +1 -0
- package/build/src/HotPage.js +178 -0
- package/build/src/HotPage.js.map +1 -0
- package/build/src/HotRoute.d.ts +82 -0
- package/build/src/HotRoute.d.ts.map +1 -0
- package/build/src/HotRoute.js +83 -0
- package/build/src/HotRoute.js.map +1 -0
- package/build/src/HotRouteMethod.d.ts +129 -0
- package/build/src/HotRouteMethod.d.ts.map +1 -0
- package/build/src/HotRouteMethod.js +84 -0
- package/build/src/HotRouteMethod.js.map +1 -0
- package/build/src/HotServer.d.ts +152 -0
- package/build/src/HotServer.d.ts.map +1 -0
- package/build/src/HotServer.js +109 -0
- package/build/src/HotServer.js.map +1 -0
- package/build/src/HotSetAsWeb.d.ts +2 -0
- package/build/src/HotSetAsWeb.d.ts.map +1 -0
- package/build/src/HotSetAsWeb.js +5 -0
- package/build/src/HotSetAsWeb.js.map +1 -0
- package/build/src/HotStaq.d.ts +603 -0
- package/build/src/HotStaq.d.ts.map +1 -0
- package/build/src/HotStaq.js +1260 -0
- package/build/src/HotStaq.js.map +1 -0
- package/build/src/HotStaqWeb.d.ts +18 -0
- package/build/src/HotStaqWeb.d.ts.map +1 -0
- package/build/src/HotStaqWeb.js +44 -0
- package/build/src/HotStaqWeb.js.map +1 -0
- package/build/src/HotTestDriver.d.ts +63 -0
- package/build/src/HotTestDriver.d.ts.map +1 -0
- package/build/src/HotTestDriver.js +187 -0
- package/build/src/HotTestDriver.js.map +1 -0
- package/build/src/HotTestElement.d.ts +71 -0
- package/build/src/HotTestElement.d.ts.map +1 -0
- package/build/src/HotTestElement.js +37 -0
- package/build/src/HotTestElement.js.map +1 -0
- package/build/src/HotTestMap.d.ts +83 -0
- package/build/src/HotTestMap.d.ts.map +1 -0
- package/build/src/HotTestMap.js +58 -0
- package/build/src/HotTestMap.js.map +1 -0
- package/build/src/HotTestSeleniumDriver.d.ts +86 -0
- package/build/src/HotTestSeleniumDriver.d.ts.map +1 -0
- package/build/src/HotTestSeleniumDriver.js +400 -0
- package/build/src/HotTestSeleniumDriver.js.map +1 -0
- package/build/src/HotTester.d.ts +188 -0
- package/build/src/HotTester.d.ts.map +1 -0
- package/build/src/HotTester.js +622 -0
- package/build/src/HotTester.js.map +1 -0
- package/build/src/HotTesterAPI.d.ts +15 -0
- package/build/src/HotTesterAPI.d.ts.map +1 -0
- package/build/src/HotTesterAPI.js +161 -0
- package/build/src/HotTesterAPI.js.map +1 -0
- package/build/src/HotTesterMocha.d.ts +50 -0
- package/build/src/HotTesterMocha.d.ts.map +1 -0
- package/build/src/HotTesterMocha.js +205 -0
- package/build/src/HotTesterMocha.js.map +1 -0
- package/build/src/HotTesterMochaSelenium.d.ts +70 -0
- package/build/src/HotTesterMochaSelenium.d.ts.map +1 -0
- package/build/src/HotTesterMochaSelenium.js +257 -0
- package/build/src/HotTesterMochaSelenium.js.map +1 -0
- package/build/src/HotTesterServer.d.ts +114 -0
- package/build/src/HotTesterServer.d.ts.map +1 -0
- package/build/src/HotTesterServer.js +575 -0
- package/build/src/HotTesterServer.js.map +1 -0
- package/build/src/api copy.d.ts +2 -0
- package/build/src/api copy.d.ts.map +1 -0
- package/build/src/api copy.js +153 -0
- package/build/src/api copy.js.map +1 -0
- package/build/src/api-web.d.ts +2 -0
- package/build/src/api-web.d.ts.map +1 -0
- package/build/src/api-web.js +45 -0
- package/build/src/api-web.js.map +1 -0
- package/build/src/api.d.ts +33 -0
- package/build/src/api.d.ts.map +1 -0
- package/build/src/api.js +78 -0
- package/build/src/api.js.map +1 -0
- package/build/src/cli.d.ts +2 -0
- package/build/src/cli.d.ts.map +1 -0
- package/build/src/cli.js +1040 -0
- package/build/src/cli.js.map +1 -0
- package/build/src/schemas/HotDBInflux.d.ts +63 -0
- package/build/src/schemas/HotDBInflux.d.ts.map +1 -0
- package/build/src/schemas/HotDBInflux.js +239 -0
- package/build/src/schemas/HotDBInflux.js.map +1 -0
- package/build/src/schemas/HotDBMigration.d.ts +19 -0
- package/build/src/schemas/HotDBMigration.d.ts.map +1 -0
- package/build/src/schemas/HotDBMigration.js +15 -0
- package/build/src/schemas/HotDBMigration.js.map +1 -0
- package/build/src/schemas/HotDBMySQL.d.ts +65 -0
- package/build/src/schemas/HotDBMySQL.d.ts.map +1 -0
- package/build/src/schemas/HotDBMySQL.js +387 -0
- package/build/src/schemas/HotDBMySQL.js.map +1 -0
- package/build/src/schemas/HotDBSchema.d.ts +15 -0
- package/build/src/schemas/HotDBSchema.d.ts.map +1 -0
- package/build/src/schemas/HotDBSchema.js +19 -0
- package/build/src/schemas/HotDBSchema.js.map +1 -0
- package/build/src/schemas/influx/InfluxSchema.d.ts +14 -0
- package/build/src/schemas/influx/InfluxSchema.d.ts.map +1 -0
- package/build/src/schemas/influx/InfluxSchema.js +33 -0
- package/build/src/schemas/influx/InfluxSchema.js.map +1 -0
- package/build/src/schemas/mysql/MySQLSchema.d.ts +39 -0
- package/build/src/schemas/mysql/MySQLSchema.d.ts.map +1 -0
- package/build/src/schemas/mysql/MySQLSchema.js +151 -0
- package/build/src/schemas/mysql/MySQLSchema.js.map +1 -0
- package/build/src/schemas/mysql/MySQLSchemaField.d.ts +168 -0
- package/build/src/schemas/mysql/MySQLSchemaField.d.ts.map +1 -0
- package/build/src/schemas/mysql/MySQLSchemaField.js +260 -0
- package/build/src/schemas/mysql/MySQLSchemaField.js.map +1 -0
- package/build/src/schemas/mysql/MySQLSchemaTable.d.ts +49 -0
- package/build/src/schemas/mysql/MySQLSchemaTable.d.ts.map +1 -0
- package/build/src/schemas/mysql/MySQLSchemaTable.js +310 -0
- package/build/src/schemas/mysql/MySQLSchemaTable.js.map +1 -0
- package/build-web/HotStaq.js +2 -0
- package/build-web/HotStaq.min.js +119 -0
- package/build-web/HotStaqTests_HelloWorldAPI.js +133 -0
- package/builder/docker/Dockerfile.linux.gen +42 -0
- package/builder/docker/README.md +36 -0
- package/builder/docker/app/start.sh +8 -0
- package/builder/docker/dockerignore +3 -0
- package/builder/docker/scripts/build.bat +11 -0
- package/builder/docker/scripts/build.sh +11 -0
- package/builder/docker/scripts/start-app.bat +7 -0
- package/builder/docker/scripts/start-app.sh +7 -0
- package/builder/docker/scripts/stop-app.bat +5 -0
- package/builder/docker/scripts/stop-app.sh +5 -0
- package/builder/docker-compose/docker-compose.gen.yaml +41 -0
- package/builder/docker-compose/env-skeleton +4 -0
- package/creator/project/.vscode/launch.json +59 -0
- package/creator/project/README.md +20 -0
- package/creator/project/gitignore +118 -0
- package/creator/project/npmignore +118 -0
- package/creator/public/api-test.hott +28 -0
- package/creator/public/index.hott +12 -0
- package/creator/ts/src/AppAPI.ts +30 -0
- package/creator/ts/src/HelloWorld.ts +39 -0
- package/creator/ts/src/WebExport.ts +7 -0
- package/creator/ts/tsconfig-web.json +73 -0
- package/creator/ts/tsconfig.json +73 -0
- package/creator/ts/webpack-api.config.js +57 -0
- package/dbstart.sh +19 -0
- package/dbstop.sh +4 -0
- package/docs/.nojekyll +1 -0
- package/docs/README.md +130 -0
- package/docs/classes/Hot.md +477 -0
- package/docs/classes/HotAPI.md +369 -0
- package/docs/classes/HotClient.md +95 -0
- package/docs/classes/HotComponent.md +279 -0
- package/docs/classes/HotDB.md +247 -0
- package/docs/classes/HotDBInflux.md +404 -0
- package/docs/classes/HotDBMigration.md +80 -0
- package/docs/classes/HotDBMySQL.md +310 -0
- package/docs/classes/HotDBSchema.md +51 -0
- package/docs/classes/HotFile.md +353 -0
- package/docs/classes/HotHTTPServer.md +700 -0
- package/docs/classes/HotLog.md +162 -0
- package/docs/classes/HotPage.md +357 -0
- package/docs/classes/HotRoute.md +312 -0
- package/docs/classes/HotRouteMethod.md +271 -0
- package/docs/classes/HotServer.md +311 -0
- package/docs/classes/HotStaq.md +1155 -0
- package/docs/classes/HotTestDestination.md +58 -0
- package/docs/classes/HotTestDriver.md +332 -0
- package/docs/classes/HotTestElement.md +88 -0
- package/docs/classes/HotTestElementOptions.md +71 -0
- package/docs/classes/HotTestMap.md +92 -0
- package/docs/classes/HotTestSeleniumDriver.md +542 -0
- package/docs/classes/HotTester.md +653 -0
- package/docs/classes/HotTesterAPI.md +493 -0
- package/docs/classes/HotTesterMocha.md +843 -0
- package/docs/classes/HotTesterMochaSelenium.md +896 -0
- package/docs/classes/HotTesterServer.md +633 -0
- package/docs/classes/InfluxSchema.md +74 -0
- package/docs/classes/MySQLSchema.md +199 -0
- package/docs/classes/MySQLSchemaField.md +330 -0
- package/docs/classes/MySQLSchemaTable.md +176 -0
- package/docs/enums/ConnectionStatus.md +43 -0
- package/docs/enums/DeveloperMode.md +38 -0
- package/docs/enums/EventExecutionType.md +43 -0
- package/docs/enums/HTTPMethod.md +32 -0
- package/docs/enums/HotDBGenerationType.md +30 -0
- package/docs/enums/HotLogLevel.md +88 -0
- package/docs/interfaces/HotDBConnectionInterface.md +116 -0
- package/docs/interfaces/HotDestination.md +62 -0
- package/docs/interfaces/HotSite.md +187 -0
- package/docs/interfaces/HotSiteMapPath.md +37 -0
- package/docs/interfaces/HotSiteRoute.md +79 -0
- package/docs/interfaces/HotStartOptions.md +115 -0
- package/docs/interfaces/HotTestPage.md +44 -0
- package/docs/interfaces/HotTestStop.md +62 -0
- package/docs/interfaces/IHotComponent.md +135 -0
- package/docs/interfaces/IHotStaq.md +118 -0
- package/docs/interfaces/IHotTestElement.md +54 -0
- package/docs/interfaces/IHotTestElementOptions.md +43 -0
- package/docs/interfaces/MySQLResults.md +43 -0
- package/docs/interfaces/MySQLSchemaFieldResult.md +75 -0
- package/docs/modules.md +182 -0
- package/package.json +65 -0
- package/selenium-start.sh +7 -0
- package/selenium-stop.sh +3 -0
- package/src/Hot.ts +319 -0
- package/src/HotAPI.ts +386 -0
- package/src/HotAgentAPI.ts +43 -0
- package/src/HotAgentRoute.ts +44 -0
- package/src/HotBuilder.ts +221 -0
- package/src/HotClient.ts +40 -0
- package/src/HotComponent.ts +158 -0
- package/src/HotCreator.ts +470 -0
- package/src/HotDB.ts +79 -0
- package/src/HotDBConnectionInterface.ts +40 -0
- package/src/HotFile.ts +617 -0
- package/src/HotGenerator.ts +446 -0
- package/src/HotHTTPServer.ts +954 -0
- package/src/HotIO.ts +160 -0
- package/src/HotLog.ts +158 -0
- package/src/HotPage.ts +206 -0
- package/src/HotRoute.ts +137 -0
- package/src/HotRouteMethod.ts +216 -0
- package/src/HotServer.ts +211 -0
- package/src/HotSetAsWeb.ts +3 -0
- package/src/HotStaq.ts +1881 -0
- package/src/HotTestDriver.ts +171 -0
- package/src/HotTestElement.ts +97 -0
- package/src/HotTestMap.ts +130 -0
- package/src/HotTestSeleniumDriver.ts +381 -0
- package/src/HotTester.ts +696 -0
- package/src/HotTesterAPI.ts +126 -0
- package/src/HotTesterMocha.ts +133 -0
- package/src/HotTesterMochaSelenium.ts +189 -0
- package/src/HotTesterServer.ts +551 -0
- package/src/api-web.ts +48 -0
- package/src/api.ts +103 -0
- package/src/cli.ts +1225 -0
- package/src/schemas/HotDBInflux.ts +211 -0
- package/src/schemas/HotDBMigration.ts +24 -0
- package/src/schemas/HotDBMySQL.ts +312 -0
- package/src/schemas/HotDBSchema.ts +21 -0
- package/src/schemas/influx/InfluxSchema.ts +19 -0
- package/src/schemas/mysql/MySQLSchema.ts +90 -0
- package/src/schemas/mysql/MySQLSchemaField.ts +408 -0
- package/src/schemas/mysql/MySQLSchemaTable.ts +353 -0
- package/temp/HotStaqWeb.ts +59 -0
- package/tsconfig-generator.json +17 -0
- package/tsconfig-web.json +74 -0
- package/tsconfig.json +73 -0
- package/webpack.config.generator.js +41 -0
- package/webpack.config.js +53 -0
- package/webpack.config.tests.js +56 -0
package/src/HotStaq.ts
ADDED
|
@@ -0,0 +1,1881 @@
|
|
|
1
|
+
import * as fs from "fs";
|
|
2
|
+
import * as ppath from "path";
|
|
3
|
+
|
|
4
|
+
import fetch from "cross-fetch";
|
|
5
|
+
import validateModuleName from "validate-npm-package-name";
|
|
6
|
+
|
|
7
|
+
import { HotPage } from "./HotPage";
|
|
8
|
+
import { HotFile } from "./HotFile";
|
|
9
|
+
|
|
10
|
+
import { HotComponent } from "./HotComponent";
|
|
11
|
+
import { HotLog, HotLogLevel } from "./HotLog";
|
|
12
|
+
import { HotAPI } from "./HotAPI";
|
|
13
|
+
import { HotServer } from "./HotServer";
|
|
14
|
+
import { DeveloperMode } from "./Hot";
|
|
15
|
+
import { HotClient } from "./HotClient";
|
|
16
|
+
|
|
17
|
+
import { HotTester } from "./HotTester";
|
|
18
|
+
import { HotTesterAPI } from "./HotTesterAPI";
|
|
19
|
+
import { HotTestDriver } from "./HotTestDriver";
|
|
20
|
+
import { HotTestDestination, HotTestMap } from "./HotTestMap";
|
|
21
|
+
|
|
22
|
+
var HotTesterMocha: any = null;
|
|
23
|
+
var HotTesterMochaSelenium: any = null;
|
|
24
|
+
var HotTestSeleniumDriver: any = null;
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* A map path for testing.
|
|
28
|
+
*/
|
|
29
|
+
export interface HotSiteMapPath
|
|
30
|
+
{
|
|
31
|
+
/**
|
|
32
|
+
* If set to true, this will start automatically when tests start.
|
|
33
|
+
* The default is true.
|
|
34
|
+
*/
|
|
35
|
+
autoStart?: boolean;
|
|
36
|
+
/**
|
|
37
|
+
* The path to the
|
|
38
|
+
*/
|
|
39
|
+
path?: string;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* A route used in a HotSite.
|
|
44
|
+
*/
|
|
45
|
+
export interface HotSiteRoute
|
|
46
|
+
{
|
|
47
|
+
/**
|
|
48
|
+
* The name of the route. Will appear in the title.
|
|
49
|
+
*/
|
|
50
|
+
name: string;
|
|
51
|
+
/**
|
|
52
|
+
* The url to the file to load.
|
|
53
|
+
*/
|
|
54
|
+
url: string;
|
|
55
|
+
/**
|
|
56
|
+
* The name of the API to interface with.
|
|
57
|
+
*/
|
|
58
|
+
api?: string;
|
|
59
|
+
/**
|
|
60
|
+
* The order in which destinations are supposed to execute. This is
|
|
61
|
+
* ignored if the destinations are an array.
|
|
62
|
+
*/
|
|
63
|
+
destinationOrder?: string[];
|
|
64
|
+
/**
|
|
65
|
+
* The HotTesterMap to use. This can be the name of an
|
|
66
|
+
* existing one attached to the selected tester, or
|
|
67
|
+
* can be an array of destinations that will be used to
|
|
68
|
+
* create a new map.
|
|
69
|
+
*/
|
|
70
|
+
map?: string | string[] | { [name: string]: string | HotSiteMapPath; } | HotSiteMapPath[];
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* A HotSite to load. This SHOULD NOT contain any private secret keys, passwords,
|
|
75
|
+
* or database connection information related to the server. As such, future
|
|
76
|
+
* versions of the HotSite interface should not contain any database related
|
|
77
|
+
* connection info.
|
|
78
|
+
*/
|
|
79
|
+
export interface HotSite
|
|
80
|
+
{
|
|
81
|
+
/**
|
|
82
|
+
* The name of this HotSite.
|
|
83
|
+
*/
|
|
84
|
+
name: string;
|
|
85
|
+
/**
|
|
86
|
+
* The path to the current HotSite. This is filled in during parsing.
|
|
87
|
+
*/
|
|
88
|
+
hotsitePath?: string;
|
|
89
|
+
/**
|
|
90
|
+
* Additional web server configuration.
|
|
91
|
+
*/
|
|
92
|
+
server?: {
|
|
93
|
+
/**
|
|
94
|
+
* The default name for a served Hott file.
|
|
95
|
+
*/
|
|
96
|
+
name?: string;
|
|
97
|
+
/**
|
|
98
|
+
* Serve hott files when requested.
|
|
99
|
+
*/
|
|
100
|
+
serveHottFiles?: boolean;
|
|
101
|
+
/**
|
|
102
|
+
* The name of the API to interface with across all pages.
|
|
103
|
+
*/
|
|
104
|
+
globalApi?: string;
|
|
105
|
+
/**
|
|
106
|
+
* The base url for the server.
|
|
107
|
+
*/
|
|
108
|
+
url?: string;
|
|
109
|
+
/**
|
|
110
|
+
* The JavaScript source path.
|
|
111
|
+
*/
|
|
112
|
+
jsSrcPath?: string;
|
|
113
|
+
/**
|
|
114
|
+
* The ports to use.
|
|
115
|
+
*/
|
|
116
|
+
ports?: {
|
|
117
|
+
/**
|
|
118
|
+
* The HTTP port to serve on.
|
|
119
|
+
*/
|
|
120
|
+
http?: number;
|
|
121
|
+
/**
|
|
122
|
+
* The HTTPS port to serve on.
|
|
123
|
+
*/
|
|
124
|
+
https?: number;
|
|
125
|
+
/**
|
|
126
|
+
* If set to true, this will redirect from HTTP to HTTPS.
|
|
127
|
+
*/
|
|
128
|
+
redirectHTTPtoHTTPS?: boolean;
|
|
129
|
+
};
|
|
130
|
+
/**
|
|
131
|
+
* The list of directory to serve to the client from the server.
|
|
132
|
+
*/
|
|
133
|
+
serveDirectories?: {
|
|
134
|
+
/**
|
|
135
|
+
* The web route to take.
|
|
136
|
+
*/
|
|
137
|
+
route: string;
|
|
138
|
+
/**
|
|
139
|
+
* The local filesystem path to serve pages from.
|
|
140
|
+
*/
|
|
141
|
+
localPath: string;
|
|
142
|
+
}[];
|
|
143
|
+
};
|
|
144
|
+
/**
|
|
145
|
+
* Testing related functionality.
|
|
146
|
+
*/
|
|
147
|
+
testing?: {
|
|
148
|
+
web?: {
|
|
149
|
+
/**
|
|
150
|
+
* The tester class to use. EX: HotTesterMochaSelenium
|
|
151
|
+
*/
|
|
152
|
+
tester?: string;
|
|
153
|
+
/**
|
|
154
|
+
* The name of the tester to use.
|
|
155
|
+
*/
|
|
156
|
+
testerName?: string;
|
|
157
|
+
/**
|
|
158
|
+
* If set to true, this will create a new tester.
|
|
159
|
+
* Default Value: true
|
|
160
|
+
*/
|
|
161
|
+
createNewTester?: boolean;
|
|
162
|
+
/**
|
|
163
|
+
* The url that connects to the tester api server.
|
|
164
|
+
*/
|
|
165
|
+
testerAPIUrl?: string;
|
|
166
|
+
/**
|
|
167
|
+
* The name of the test driver to use.
|
|
168
|
+
*/
|
|
169
|
+
driver?: string;
|
|
170
|
+
/**
|
|
171
|
+
* The url to the html that loads the hott files.
|
|
172
|
+
*/
|
|
173
|
+
launchpadUrl?: string;
|
|
174
|
+
/**
|
|
175
|
+
* The maps to test in order.
|
|
176
|
+
*/
|
|
177
|
+
maps?: string[];
|
|
178
|
+
},
|
|
179
|
+
api?: {
|
|
180
|
+
/**
|
|
181
|
+
* The tester class to use. EX: HotTesterMocha
|
|
182
|
+
*/
|
|
183
|
+
tester?: string;
|
|
184
|
+
/**
|
|
185
|
+
* The name of the tester to use.
|
|
186
|
+
*/
|
|
187
|
+
testerName?: string;
|
|
188
|
+
/**
|
|
189
|
+
* If set to true, this will create a new tester.
|
|
190
|
+
* Default Value: true
|
|
191
|
+
*/
|
|
192
|
+
createNewTester?: boolean;
|
|
193
|
+
/**
|
|
194
|
+
* The url that connects to the tester api server.
|
|
195
|
+
*/
|
|
196
|
+
testerAPIUrl?: string;
|
|
197
|
+
/**
|
|
198
|
+
* The name of the test driver to use.
|
|
199
|
+
*/
|
|
200
|
+
driver?: string;
|
|
201
|
+
/**
|
|
202
|
+
* The url to the html that loads the hott files.
|
|
203
|
+
*/
|
|
204
|
+
launchpadUrl?: string;
|
|
205
|
+
/**
|
|
206
|
+
* The maps to test in order.
|
|
207
|
+
*/
|
|
208
|
+
maps?: string[];
|
|
209
|
+
}
|
|
210
|
+
};
|
|
211
|
+
/**
|
|
212
|
+
* The routes to load.
|
|
213
|
+
*/
|
|
214
|
+
routes?: {
|
|
215
|
+
[routeName: string]: HotSiteRoute;
|
|
216
|
+
};
|
|
217
|
+
/**
|
|
218
|
+
* The available APIs on the server. The server must already have these
|
|
219
|
+
* loaded.
|
|
220
|
+
*/
|
|
221
|
+
apis?: {
|
|
222
|
+
[name: string]: {
|
|
223
|
+
/**
|
|
224
|
+
* The JS API file to load.
|
|
225
|
+
*/
|
|
226
|
+
jsapi?: string;
|
|
227
|
+
/**
|
|
228
|
+
* The exported JS library name to use.
|
|
229
|
+
*/
|
|
230
|
+
libraryName?: string;
|
|
231
|
+
/**
|
|
232
|
+
* The name of the api to use.
|
|
233
|
+
*/
|
|
234
|
+
apiName?: string;
|
|
235
|
+
/**
|
|
236
|
+
* The port to use.
|
|
237
|
+
*/
|
|
238
|
+
port?: number;
|
|
239
|
+
/**
|
|
240
|
+
* The public base url for the api.
|
|
241
|
+
*/
|
|
242
|
+
url?: string;
|
|
243
|
+
/**
|
|
244
|
+
* The server-side filepath for the api.
|
|
245
|
+
*/
|
|
246
|
+
filepath?: string;
|
|
247
|
+
/**
|
|
248
|
+
* The maps to test in order.
|
|
249
|
+
*/
|
|
250
|
+
map?: string[];
|
|
251
|
+
};
|
|
252
|
+
};
|
|
253
|
+
/**
|
|
254
|
+
* Secrets that can be publicly embedded into the page.
|
|
255
|
+
*/
|
|
256
|
+
publicSecrets?: {
|
|
257
|
+
[name: string]: string | {
|
|
258
|
+
/**
|
|
259
|
+
* The key of an API secret to pass to the site to
|
|
260
|
+
* be used publicly.
|
|
261
|
+
*/
|
|
262
|
+
passSecretFromAPI?: string;
|
|
263
|
+
/**
|
|
264
|
+
* Get the public secret from an environment variable.
|
|
265
|
+
*/
|
|
266
|
+
env?: string;
|
|
267
|
+
};
|
|
268
|
+
};
|
|
269
|
+
/**
|
|
270
|
+
* The components to load and register.
|
|
271
|
+
*/
|
|
272
|
+
components?: {
|
|
273
|
+
[name: string]: {
|
|
274
|
+
/**
|
|
275
|
+
* The url to the component to load and register.
|
|
276
|
+
*/
|
|
277
|
+
url: string;
|
|
278
|
+
};
|
|
279
|
+
};
|
|
280
|
+
/**
|
|
281
|
+
* The files to load and save in memory.
|
|
282
|
+
*/
|
|
283
|
+
files?: {
|
|
284
|
+
[name: string]: {
|
|
285
|
+
/**
|
|
286
|
+
* The url to the file to load.
|
|
287
|
+
*/
|
|
288
|
+
url: string;
|
|
289
|
+
};
|
|
290
|
+
};
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
/**
|
|
294
|
+
* The options to use when starting a page.
|
|
295
|
+
*/
|
|
296
|
+
export interface HotStartOptions
|
|
297
|
+
{
|
|
298
|
+
/**
|
|
299
|
+
* The Hott site to load.
|
|
300
|
+
*/
|
|
301
|
+
url: string;
|
|
302
|
+
/**
|
|
303
|
+
* The name of the page to load.
|
|
304
|
+
*/
|
|
305
|
+
name?: string;
|
|
306
|
+
/**
|
|
307
|
+
* The processor to use to load the page.
|
|
308
|
+
*/
|
|
309
|
+
processor?: HotStaq;
|
|
310
|
+
/**
|
|
311
|
+
* Any arguments to pass to the new page.
|
|
312
|
+
*/
|
|
313
|
+
args?: any;
|
|
314
|
+
/**
|
|
315
|
+
* The name of the tester to use.
|
|
316
|
+
*/
|
|
317
|
+
testerName?: string;
|
|
318
|
+
/**
|
|
319
|
+
* The name of the tester map to use.
|
|
320
|
+
*/
|
|
321
|
+
testerMap?: string;
|
|
322
|
+
/**
|
|
323
|
+
* The base url for the tester api.
|
|
324
|
+
*/
|
|
325
|
+
testerAPIBaseUrl?: string;
|
|
326
|
+
/**
|
|
327
|
+
* The url to the html that loads the hott file that's
|
|
328
|
+
* pointed at the url above.
|
|
329
|
+
*/
|
|
330
|
+
testerLaunchpadUrl?: string;
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
/**
|
|
334
|
+
* The main class that handles all HTML preprocessing, then outputs the
|
|
335
|
+
* results.
|
|
336
|
+
*/
|
|
337
|
+
export interface IHotStaq
|
|
338
|
+
{
|
|
339
|
+
/**
|
|
340
|
+
* The api that's used to communicate with.
|
|
341
|
+
*/
|
|
342
|
+
api?: HotAPI;
|
|
343
|
+
/**
|
|
344
|
+
* The tester api that's used to communicate with.
|
|
345
|
+
*/
|
|
346
|
+
testerAPI?: HotAPI;
|
|
347
|
+
/**
|
|
348
|
+
* Indicates what type of execution this is.
|
|
349
|
+
*/
|
|
350
|
+
mode?: DeveloperMode;
|
|
351
|
+
/**
|
|
352
|
+
* The pages that can be constructed.
|
|
353
|
+
*/
|
|
354
|
+
pages?: { [name: string]: HotPage };
|
|
355
|
+
/**
|
|
356
|
+
* The components that can be constructed.
|
|
357
|
+
*/
|
|
358
|
+
components?: { [name: string]: HotComponent };
|
|
359
|
+
/**
|
|
360
|
+
* The files that can be stored for later use.
|
|
361
|
+
*/
|
|
362
|
+
files?: { [name: string]: HotFile };
|
|
363
|
+
/**
|
|
364
|
+
* The loaded hotsite.
|
|
365
|
+
*/
|
|
366
|
+
hotSite?: HotSite;
|
|
367
|
+
}
|
|
368
|
+
|
|
369
|
+
/**
|
|
370
|
+
* The main class that handles all HTML preprocessing, then outputs the
|
|
371
|
+
* results.
|
|
372
|
+
*/
|
|
373
|
+
export class HotStaq implements IHotStaq
|
|
374
|
+
{
|
|
375
|
+
/**
|
|
376
|
+
* Indicates if this is a web build.
|
|
377
|
+
*/
|
|
378
|
+
static isWeb: boolean = false;
|
|
379
|
+
/**
|
|
380
|
+
* Indicates if this is ready for testing.
|
|
381
|
+
*/
|
|
382
|
+
static isReadyForTesting: boolean = false;
|
|
383
|
+
/**
|
|
384
|
+
* Executes this event when this page is ready for testing.
|
|
385
|
+
*/
|
|
386
|
+
static onReadyForTesting: () => Promise<void> = null;
|
|
387
|
+
/**
|
|
388
|
+
* Indicates what type of execution this is.
|
|
389
|
+
*/
|
|
390
|
+
mode: DeveloperMode;
|
|
391
|
+
/**
|
|
392
|
+
* The api that's used to communicate with.
|
|
393
|
+
*/
|
|
394
|
+
api: HotAPI;
|
|
395
|
+
/**
|
|
396
|
+
* The tester api that's used to communicate with.
|
|
397
|
+
*/
|
|
398
|
+
testerAPI: HotAPI;
|
|
399
|
+
/**
|
|
400
|
+
* The pages that can be constructed.
|
|
401
|
+
*/
|
|
402
|
+
pages: { [name: string]: HotPage };
|
|
403
|
+
/**
|
|
404
|
+
* The components that can be constructed.
|
|
405
|
+
*/
|
|
406
|
+
components: { [name: string]: HotComponent };
|
|
407
|
+
/**
|
|
408
|
+
* The files that can be stored for later use.
|
|
409
|
+
*/
|
|
410
|
+
files: { [name: string]: HotFile };
|
|
411
|
+
/**
|
|
412
|
+
* The loaded hotsite.
|
|
413
|
+
*/
|
|
414
|
+
hotSite: HotSite;
|
|
415
|
+
/**
|
|
416
|
+
* The api content to use when about to load HotStaq.
|
|
417
|
+
*/
|
|
418
|
+
apiContent: string;
|
|
419
|
+
/**
|
|
420
|
+
* The tester api content to use when about to load HotStaq.
|
|
421
|
+
*/
|
|
422
|
+
testerApiContent: string;
|
|
423
|
+
/**
|
|
424
|
+
* The page content to use when about to load HotStaq.
|
|
425
|
+
*/
|
|
426
|
+
pageContent: string;
|
|
427
|
+
/**
|
|
428
|
+
* The logger.
|
|
429
|
+
*/
|
|
430
|
+
logger: HotLog;
|
|
431
|
+
/**
|
|
432
|
+
* The secrets that can be exposed publicly.
|
|
433
|
+
*/
|
|
434
|
+
publicSecrets: any;
|
|
435
|
+
/**
|
|
436
|
+
* The secrets that can be exposed publicly.
|
|
437
|
+
*/
|
|
438
|
+
testers: { [name: string]: HotTester };
|
|
439
|
+
|
|
440
|
+
constructor (copy: IHotStaq = {})
|
|
441
|
+
{
|
|
442
|
+
this.api = copy.api || null;
|
|
443
|
+
this.testerAPI = copy.testerAPI || null;
|
|
444
|
+
this.mode = copy.mode || DeveloperMode.Production;
|
|
445
|
+
this.pages = copy.pages || {};
|
|
446
|
+
this.components = copy.components || {};
|
|
447
|
+
this.files = copy.files || {};
|
|
448
|
+
this.hotSite = copy.hotSite || null;
|
|
449
|
+
this.apiContent = `
|
|
450
|
+
var %api_name% = %api_exported_name%.%api_name%;
|
|
451
|
+
var newHotClient = new HotClient (processor);
|
|
452
|
+
var newapi = new %api_name% (%base_url%, newHotClient);
|
|
453
|
+
newHotClient.api = newapi;
|
|
454
|
+
processor.api = newapi;`;
|
|
455
|
+
this.testerApiContent = `
|
|
456
|
+
var HotTesterAPI = HotStaqWeb.HotTesterAPI;
|
|
457
|
+
var newHotTesterClient = new HotClient (processor);
|
|
458
|
+
var newtesterapi = new HotTesterAPI (%base_tester_url%, newHotTesterClient);
|
|
459
|
+
newHotTesterClient.testerAPI = newtesterapi;
|
|
460
|
+
processor.testerAPI = newtesterapi;`;
|
|
461
|
+
this.pageContent =
|
|
462
|
+
`<!DOCTYPE html>
|
|
463
|
+
<html>
|
|
464
|
+
|
|
465
|
+
<head>
|
|
466
|
+
<title>%title%</title>
|
|
467
|
+
|
|
468
|
+
<script type = "text/javascript" src = "%hotstaq_js_src%"></script>
|
|
469
|
+
<script type = "text/javascript">
|
|
470
|
+
window.HotStaq = HotStaqWeb.HotStaq;
|
|
471
|
+
window.HotClient = HotStaqWeb.HotClient;
|
|
472
|
+
window.HotAPI = HotStaqWeb.HotAPI;
|
|
473
|
+
window.Hot = HotStaqWeb.Hot;
|
|
474
|
+
</script>
|
|
475
|
+
|
|
476
|
+
%apis_to_load%
|
|
477
|
+
|
|
478
|
+
<script type = "text/javascript">
|
|
479
|
+
function hotstaq_startApp ()
|
|
480
|
+
{
|
|
481
|
+
let tempMode = 0;
|
|
482
|
+
|
|
483
|
+
if (window["Hot"] != null)
|
|
484
|
+
tempMode = Hot.Mode;
|
|
485
|
+
|
|
486
|
+
%load_hot_site%
|
|
487
|
+
|
|
488
|
+
var processor = new HotStaq ();
|
|
489
|
+
var promises = [];
|
|
490
|
+
%developer_mode%
|
|
491
|
+
|
|
492
|
+
%api_code%
|
|
493
|
+
|
|
494
|
+
%public_secrets%
|
|
495
|
+
%tester_api%
|
|
496
|
+
%load_files%
|
|
497
|
+
|
|
498
|
+
processor.mode = tempMode;
|
|
499
|
+
|
|
500
|
+
Promise.all (promises).then (function ()
|
|
501
|
+
{
|
|
502
|
+
HotStaq.displayUrl ({
|
|
503
|
+
url: "%url%",
|
|
504
|
+
name: "%title%",
|
|
505
|
+
processor: processor,
|
|
506
|
+
args: %args%,
|
|
507
|
+
testerName: %tester_name%,
|
|
508
|
+
testerMap: %tester_map%,
|
|
509
|
+
testerAPIBaseUrl: %tester_api_base_url%,
|
|
510
|
+
testerLaunchpadUrl: %tester_launchpad_url%
|
|
511
|
+
});
|
|
512
|
+
});
|
|
513
|
+
}
|
|
514
|
+
|
|
515
|
+
hotstaq_startApp ();
|
|
516
|
+
</script>
|
|
517
|
+
</head>
|
|
518
|
+
|
|
519
|
+
<body>
|
|
520
|
+
</body>
|
|
521
|
+
|
|
522
|
+
</html>`;
|
|
523
|
+
this.logger = new HotLog (HotLogLevel.None);
|
|
524
|
+
this.publicSecrets = {};
|
|
525
|
+
this.testers = {};
|
|
526
|
+
}
|
|
527
|
+
|
|
528
|
+
/**
|
|
529
|
+
* Parse a boolean value.
|
|
530
|
+
*/
|
|
531
|
+
static parseBoolean (value: string): boolean
|
|
532
|
+
{
|
|
533
|
+
value = value.toLowerCase ();
|
|
534
|
+
|
|
535
|
+
if (value === "true")
|
|
536
|
+
return (true);
|
|
537
|
+
|
|
538
|
+
if (value === "false")
|
|
539
|
+
return (false);
|
|
540
|
+
|
|
541
|
+
if (value === "yes")
|
|
542
|
+
return (true);
|
|
543
|
+
|
|
544
|
+
if (value === "no")
|
|
545
|
+
return (false);
|
|
546
|
+
|
|
547
|
+
if (value === "yep")
|
|
548
|
+
return (true);
|
|
549
|
+
|
|
550
|
+
if (value === "nah")
|
|
551
|
+
return (false);
|
|
552
|
+
|
|
553
|
+
try
|
|
554
|
+
{
|
|
555
|
+
if (parseInt (value) != 0)
|
|
556
|
+
return (true);
|
|
557
|
+
}
|
|
558
|
+
catch (ex)
|
|
559
|
+
{
|
|
560
|
+
}
|
|
561
|
+
|
|
562
|
+
return (false);
|
|
563
|
+
}
|
|
564
|
+
|
|
565
|
+
/**
|
|
566
|
+
* Check if a required parameter exists inside an object. If it exists, return the value.
|
|
567
|
+
*/
|
|
568
|
+
static getParam (name: string, objWithParam: any, required: boolean = true, throwException: boolean = true): any
|
|
569
|
+
{
|
|
570
|
+
let value: any = objWithParam[name];
|
|
571
|
+
|
|
572
|
+
if (value == null)
|
|
573
|
+
{
|
|
574
|
+
if (required === true)
|
|
575
|
+
{
|
|
576
|
+
if (throwException === true)
|
|
577
|
+
throw new Error (`Missing required parameter ${name}.`);
|
|
578
|
+
}
|
|
579
|
+
}
|
|
580
|
+
|
|
581
|
+
if (typeof (value) === "string")
|
|
582
|
+
{
|
|
583
|
+
if (required === true)
|
|
584
|
+
{
|
|
585
|
+
if (value === "")
|
|
586
|
+
{
|
|
587
|
+
if (throwException === true)
|
|
588
|
+
throw new Error (`Missing required parameter ${name}.`);
|
|
589
|
+
}
|
|
590
|
+
}
|
|
591
|
+
}
|
|
592
|
+
|
|
593
|
+
return (value);
|
|
594
|
+
}
|
|
595
|
+
|
|
596
|
+
/**
|
|
597
|
+
* Check if a required parameter exists inside an object. If it exists, return the value.
|
|
598
|
+
* If it does not exist, return a default value instead.
|
|
599
|
+
*/
|
|
600
|
+
static getParamDefault (name: string, objWithParam: any, defaultValue: any): any
|
|
601
|
+
{
|
|
602
|
+
let value: any = objWithParam[name];
|
|
603
|
+
|
|
604
|
+
if (value == null)
|
|
605
|
+
return (defaultValue);
|
|
606
|
+
|
|
607
|
+
if (typeof (value) === "string")
|
|
608
|
+
{
|
|
609
|
+
if (value === "")
|
|
610
|
+
return (defaultValue);
|
|
611
|
+
}
|
|
612
|
+
|
|
613
|
+
return (value);
|
|
614
|
+
}
|
|
615
|
+
|
|
616
|
+
/**
|
|
617
|
+
* Wait for a number of milliseconds.
|
|
618
|
+
*/
|
|
619
|
+
static async wait (numMilliseconds: number): Promise<void>
|
|
620
|
+
{
|
|
621
|
+
return (await new Promise ((resolve, reject) =>
|
|
622
|
+
{
|
|
623
|
+
setTimeout (() =>
|
|
624
|
+
{
|
|
625
|
+
resolve ();
|
|
626
|
+
}, numMilliseconds);
|
|
627
|
+
}));
|
|
628
|
+
}
|
|
629
|
+
|
|
630
|
+
/**
|
|
631
|
+
* Add a page.
|
|
632
|
+
*/
|
|
633
|
+
addPage (page: HotPage): void
|
|
634
|
+
{
|
|
635
|
+
this.pages[page.name] = page;
|
|
636
|
+
}
|
|
637
|
+
|
|
638
|
+
/**
|
|
639
|
+
* Get a page to process.
|
|
640
|
+
*/
|
|
641
|
+
getPage (pageName: string): HotPage
|
|
642
|
+
{
|
|
643
|
+
return (this.pages[pageName]);
|
|
644
|
+
}
|
|
645
|
+
|
|
646
|
+
/**
|
|
647
|
+
* Add a file.
|
|
648
|
+
*/
|
|
649
|
+
addFile (file: HotFile): void
|
|
650
|
+
{
|
|
651
|
+
let name: string = file.name;
|
|
652
|
+
|
|
653
|
+
if (name === "")
|
|
654
|
+
name = file.localFile;
|
|
655
|
+
|
|
656
|
+
if (name === "")
|
|
657
|
+
name = file.url;
|
|
658
|
+
|
|
659
|
+
this.files[name] = file;
|
|
660
|
+
}
|
|
661
|
+
|
|
662
|
+
/**
|
|
663
|
+
* Get a file.
|
|
664
|
+
*/
|
|
665
|
+
getFile (name: string): HotFile
|
|
666
|
+
{
|
|
667
|
+
if (this.files[name] == null)
|
|
668
|
+
throw new Error (`Unable to find file ${name}`);
|
|
669
|
+
|
|
670
|
+
return (this.files[name]);
|
|
671
|
+
}
|
|
672
|
+
|
|
673
|
+
/**
|
|
674
|
+
* Add and register a component.
|
|
675
|
+
*/
|
|
676
|
+
addComponent (component: HotComponent): void
|
|
677
|
+
{
|
|
678
|
+
this.components[component.name] = component;
|
|
679
|
+
this.registerComponent (component);
|
|
680
|
+
}
|
|
681
|
+
|
|
682
|
+
/**
|
|
683
|
+
* Register a component for use as a HTML tag.
|
|
684
|
+
*/
|
|
685
|
+
registerComponent (component: HotComponent): void
|
|
686
|
+
{
|
|
687
|
+
customElements.define (component.tag, class extends HTMLElement
|
|
688
|
+
{
|
|
689
|
+
constructor ()
|
|
690
|
+
{
|
|
691
|
+
super ();
|
|
692
|
+
|
|
693
|
+
/// @fixme Is this bad? Could create race conditions.
|
|
694
|
+
(async () =>
|
|
695
|
+
{
|
|
696
|
+
this.onclick = component.click.bind (component);
|
|
697
|
+
|
|
698
|
+
for (let key in component.events)
|
|
699
|
+
{
|
|
700
|
+
let event = component.events[key];
|
|
701
|
+
|
|
702
|
+
// @ts-ignore
|
|
703
|
+
this.addEventListener (event.type, event.func, event.options);
|
|
704
|
+
}
|
|
705
|
+
|
|
706
|
+
component.htmlElement = await component.onCreated (this);
|
|
707
|
+
|
|
708
|
+
if (component.handleAttributes != null)
|
|
709
|
+
await component.handleAttributes (this.attributes);
|
|
710
|
+
else
|
|
711
|
+
{
|
|
712
|
+
for (let iIdx = 0; iIdx < this.attributes.length; iIdx++)
|
|
713
|
+
{
|
|
714
|
+
let attr: Attr = this.attributes[iIdx];
|
|
715
|
+
let attrName: string = attr.name.toLowerCase ();
|
|
716
|
+
let attrValue: string = attr.value;
|
|
717
|
+
|
|
718
|
+
if (attrName === "id")
|
|
719
|
+
component.name = attrValue;
|
|
720
|
+
|
|
721
|
+
if (attrName === "name")
|
|
722
|
+
component.name = attrValue;
|
|
723
|
+
|
|
724
|
+
if (attrName === "value")
|
|
725
|
+
component.value = attrValue;
|
|
726
|
+
}
|
|
727
|
+
}
|
|
728
|
+
|
|
729
|
+
let str: string = await component.output ();
|
|
730
|
+
let newDOM: Document = new DOMParser ().parseFromString (str, "text/html");
|
|
731
|
+
let shadow: ShadowRoot = this.attachShadow ({ mode: "open" });
|
|
732
|
+
|
|
733
|
+
for (let iIdx = 0; iIdx < newDOM.body.children.length; iIdx++)
|
|
734
|
+
{
|
|
735
|
+
let child = newDOM.body.children[iIdx];
|
|
736
|
+
shadow.appendChild (child);
|
|
737
|
+
}
|
|
738
|
+
})();
|
|
739
|
+
}
|
|
740
|
+
}, component.elementOptions);
|
|
741
|
+
}
|
|
742
|
+
|
|
743
|
+
/**
|
|
744
|
+
* Get a component to process.
|
|
745
|
+
*/
|
|
746
|
+
getComponent (name: string): HotComponent
|
|
747
|
+
{
|
|
748
|
+
return (this.components[name]);
|
|
749
|
+
}
|
|
750
|
+
|
|
751
|
+
/**
|
|
752
|
+
* Add a new HTML element(s) to the current document.
|
|
753
|
+
*/
|
|
754
|
+
static addHtml (parent: string | HTMLElement, html: string | HTMLElement): HTMLElement | HTMLElement[]
|
|
755
|
+
{
|
|
756
|
+
let foundParent: HTMLElement = null;
|
|
757
|
+
|
|
758
|
+
if (typeof (parent) === "string")
|
|
759
|
+
foundParent = document.querySelector (parent);
|
|
760
|
+
else
|
|
761
|
+
foundParent = parent;
|
|
762
|
+
|
|
763
|
+
if (foundParent == null)
|
|
764
|
+
throw new Error (`Unable to find parent ${parent}!`);
|
|
765
|
+
|
|
766
|
+
let result: HTMLElement = null;
|
|
767
|
+
|
|
768
|
+
if (typeof (html) === "string")
|
|
769
|
+
{
|
|
770
|
+
let newDOM: Document = new DOMParser ().parseFromString (html, "text/html");
|
|
771
|
+
let results: HTMLElement[] = [];
|
|
772
|
+
|
|
773
|
+
for (let iIdx = 0; iIdx < newDOM.body.children.length; iIdx++)
|
|
774
|
+
{
|
|
775
|
+
let child: HTMLElement = (<HTMLElement>newDOM.body.children[iIdx]);
|
|
776
|
+
|
|
777
|
+
results.push (foundParent.appendChild (child));
|
|
778
|
+
}
|
|
779
|
+
|
|
780
|
+
return (results);
|
|
781
|
+
}
|
|
782
|
+
else
|
|
783
|
+
result = foundParent.appendChild (html);
|
|
784
|
+
|
|
785
|
+
return (result);
|
|
786
|
+
}
|
|
787
|
+
|
|
788
|
+
/**
|
|
789
|
+
* Check if a HotSite's name is valid.
|
|
790
|
+
*/
|
|
791
|
+
static checkHotSiteName (hotsiteName: string, throwException: boolean = false): boolean
|
|
792
|
+
{
|
|
793
|
+
let throwTheException = () =>
|
|
794
|
+
{
|
|
795
|
+
if (throwException === true)
|
|
796
|
+
throw new Error (`HotSite ${hotsiteName} has an invalid name! The name cannot be empty and must have a valid NPM module name.`);
|
|
797
|
+
};
|
|
798
|
+
|
|
799
|
+
let results = validateModuleName (hotsiteName);
|
|
800
|
+
|
|
801
|
+
if (results.errors != null)
|
|
802
|
+
{
|
|
803
|
+
if (results.errors.length > 0)
|
|
804
|
+
throwTheException ();
|
|
805
|
+
}
|
|
806
|
+
|
|
807
|
+
return (true);
|
|
808
|
+
}
|
|
809
|
+
|
|
810
|
+
/**
|
|
811
|
+
* In the supplied content, replace a key in a ${KEY} with a value.
|
|
812
|
+
*
|
|
813
|
+
* @returns The content with the correct values.
|
|
814
|
+
*/
|
|
815
|
+
static replaceKey (content: string, key: string, value: string): string
|
|
816
|
+
{
|
|
817
|
+
const finalStr: string = content.replace (new RegExp (`\\$\\{${key}\\}`, "g"), value);
|
|
818
|
+
|
|
819
|
+
return (finalStr);
|
|
820
|
+
}
|
|
821
|
+
|
|
822
|
+
/**
|
|
823
|
+
* Get a value from a HotSite object.
|
|
824
|
+
*
|
|
825
|
+
* @returns Returns the value from the hotsite object. Returns null if it doesn't exist.
|
|
826
|
+
*/
|
|
827
|
+
static getValueFromHotSiteObj (hotsite: HotSite, params: string[]): any
|
|
828
|
+
{
|
|
829
|
+
let value: any = null;
|
|
830
|
+
|
|
831
|
+
if (hotsite != null)
|
|
832
|
+
{
|
|
833
|
+
let prevValue: any = hotsite;
|
|
834
|
+
|
|
835
|
+
// Go through each object in the list of parameters and
|
|
836
|
+
// get the value of the final parameter.
|
|
837
|
+
for (let iIdx = 0; iIdx < params.length; iIdx++)
|
|
838
|
+
{
|
|
839
|
+
let param: string = params[iIdx];
|
|
840
|
+
|
|
841
|
+
if (prevValue[param] == null)
|
|
842
|
+
{
|
|
843
|
+
prevValue = null;
|
|
844
|
+
|
|
845
|
+
break;
|
|
846
|
+
}
|
|
847
|
+
|
|
848
|
+
prevValue = prevValue[param];
|
|
849
|
+
}
|
|
850
|
+
|
|
851
|
+
if (prevValue != null)
|
|
852
|
+
value = prevValue;
|
|
853
|
+
}
|
|
854
|
+
|
|
855
|
+
return (value);
|
|
856
|
+
}
|
|
857
|
+
|
|
858
|
+
/**
|
|
859
|
+
* Load from a HotSite.json file. Be sure to load and attach any testers before
|
|
860
|
+
* loading a HotSite.
|
|
861
|
+
*/
|
|
862
|
+
async loadHotSite (path: string): Promise<void>
|
|
863
|
+
{
|
|
864
|
+
let jsonStr: string = "";
|
|
865
|
+
|
|
866
|
+
if (HotStaq.isWeb === true)
|
|
867
|
+
{
|
|
868
|
+
this.logger.info (`Retrieving HotSite ${path}`);
|
|
869
|
+
|
|
870
|
+
let res: any = await fetch (path);
|
|
871
|
+
|
|
872
|
+
this.logger.info (`Retrieved site ${path}`);
|
|
873
|
+
|
|
874
|
+
jsonStr = res.text ();
|
|
875
|
+
}
|
|
876
|
+
else
|
|
877
|
+
{
|
|
878
|
+
path = ppath.normalize (path);
|
|
879
|
+
|
|
880
|
+
this.logger.info (`Retrieving HotSite ${path}`);
|
|
881
|
+
|
|
882
|
+
jsonStr = await new Promise (
|
|
883
|
+
(resolve: any, reject: any): void =>
|
|
884
|
+
{
|
|
885
|
+
fs.readFile (path, (err: NodeJS.ErrnoException, data: Buffer): void =>
|
|
886
|
+
{
|
|
887
|
+
if (err != null)
|
|
888
|
+
throw err;
|
|
889
|
+
|
|
890
|
+
let content: string = data.toString ();
|
|
891
|
+
|
|
892
|
+
this.logger.info (`Retrieved site ${path}`);
|
|
893
|
+
|
|
894
|
+
resolve (content);
|
|
895
|
+
});
|
|
896
|
+
});
|
|
897
|
+
}
|
|
898
|
+
|
|
899
|
+
this.hotSite = JSON.parse (jsonStr);
|
|
900
|
+
|
|
901
|
+
HotStaq.checkHotSiteName (this.hotSite.name, true);
|
|
902
|
+
|
|
903
|
+
this.hotSite.hotsitePath = path;
|
|
904
|
+
let routes = this.hotSite.routes;
|
|
905
|
+
let testerUrl: string = "http://127.0.0.1:8182";
|
|
906
|
+
let tester: HotTester = null;
|
|
907
|
+
let driver: HotTestDriver = null;
|
|
908
|
+
|
|
909
|
+
if (HotStaq.isWeb === false)
|
|
910
|
+
{
|
|
911
|
+
if (this.mode === DeveloperMode.Development)
|
|
912
|
+
{
|
|
913
|
+
if (this.hotSite.testing != null)
|
|
914
|
+
{
|
|
915
|
+
let setupTester = (parentObj: any) =>
|
|
916
|
+
{
|
|
917
|
+
let createNewTester: boolean = true;
|
|
918
|
+
|
|
919
|
+
if (parentObj.createNewTester != null)
|
|
920
|
+
createNewTester = parentObj.createNewTester;
|
|
921
|
+
|
|
922
|
+
let testerName: string = "Tester";
|
|
923
|
+
|
|
924
|
+
if (parentObj.tester != null)
|
|
925
|
+
testerName = parentObj.tester;
|
|
926
|
+
|
|
927
|
+
if (parentObj.testerName != null)
|
|
928
|
+
testerName = parentObj.testerName;
|
|
929
|
+
|
|
930
|
+
if (createNewTester === true)
|
|
931
|
+
{
|
|
932
|
+
/// @fixme Find a way to securely allow devs to use their own drivers and testers...
|
|
933
|
+
/// @fixme Hack for dealing with WebPack's bs.
|
|
934
|
+
HotTesterMocha = require ("./HotTesterMocha").HotTesterMocha;
|
|
935
|
+
HotTesterMochaSelenium = require ("./HotTesterMochaSelenium").HotTesterMochaSelenium;
|
|
936
|
+
HotTestSeleniumDriver = require ("./HotTestSeleniumDriver").HotTestSeleniumDriver;
|
|
937
|
+
|
|
938
|
+
if (parentObj.testerAPIUrl === "")
|
|
939
|
+
testerUrl = parentObj.testerAPIUrl;
|
|
940
|
+
|
|
941
|
+
if (parentObj.driver === "HotTestSeleniumDriver")
|
|
942
|
+
driver = new HotTestSeleniumDriver ();
|
|
943
|
+
|
|
944
|
+
if (parentObj.tester === "HotTesterMocha")
|
|
945
|
+
tester = new HotTesterMocha (this, testerName, testerUrl, driver);
|
|
946
|
+
|
|
947
|
+
if (parentObj.tester === "HotTesterMochaSelenium")
|
|
948
|
+
tester = new HotTesterMochaSelenium (this, testerName, testerUrl);
|
|
949
|
+
}
|
|
950
|
+
else
|
|
951
|
+
tester = this.testers[testerName];
|
|
952
|
+
};
|
|
953
|
+
|
|
954
|
+
if (this.hotSite.testing.web != null)
|
|
955
|
+
setupTester (this.hotSite.testing.web);
|
|
956
|
+
|
|
957
|
+
if (this.hotSite.testing.api != null)
|
|
958
|
+
setupTester (this.hotSite.testing.api);
|
|
959
|
+
}
|
|
960
|
+
}
|
|
961
|
+
}
|
|
962
|
+
|
|
963
|
+
if (routes != null)
|
|
964
|
+
{
|
|
965
|
+
for (let key in routes)
|
|
966
|
+
{
|
|
967
|
+
let route: HotSiteRoute = routes[key];
|
|
968
|
+
let file: HotFile = new HotFile (route);
|
|
969
|
+
let page: HotPage = new HotPage ({
|
|
970
|
+
processor: this,
|
|
971
|
+
name: route.name || "",
|
|
972
|
+
route: key,
|
|
973
|
+
files: [file]
|
|
974
|
+
});
|
|
975
|
+
|
|
976
|
+
if (tester != null)
|
|
977
|
+
{
|
|
978
|
+
if (this.mode === DeveloperMode.Development)
|
|
979
|
+
{
|
|
980
|
+
let mapName: string = route.name;
|
|
981
|
+
let testMap: HotTestMap = null;
|
|
982
|
+
|
|
983
|
+
if (route.map != null)
|
|
984
|
+
{
|
|
985
|
+
if (typeof (route.map) === "string")
|
|
986
|
+
{
|
|
987
|
+
if (tester.testMaps[route.map] == null)
|
|
988
|
+
throw new Error (`Test map ${route.map} does not exist!`);
|
|
989
|
+
|
|
990
|
+
tester.testMaps[mapName] = tester.testMaps[route.map];
|
|
991
|
+
}
|
|
992
|
+
else
|
|
993
|
+
{
|
|
994
|
+
testMap = new HotTestMap ();
|
|
995
|
+
let destinations: HotTestDestination[] | { [name: string]: HotTestDestination } = null;
|
|
996
|
+
|
|
997
|
+
if (route.map instanceof Array)
|
|
998
|
+
{
|
|
999
|
+
destinations = [];
|
|
1000
|
+
|
|
1001
|
+
for (let iIdx = 0; iIdx < route.map.length; iIdx++)
|
|
1002
|
+
{
|
|
1003
|
+
let dest = route.map[iIdx];
|
|
1004
|
+
|
|
1005
|
+
destinations.push (new HotTestDestination (dest));
|
|
1006
|
+
}
|
|
1007
|
+
}
|
|
1008
|
+
else
|
|
1009
|
+
{
|
|
1010
|
+
destinations = {};
|
|
1011
|
+
|
|
1012
|
+
for (let key2 in route.map)
|
|
1013
|
+
{
|
|
1014
|
+
let dest = route.map[key2];
|
|
1015
|
+
|
|
1016
|
+
destinations[key2] = new HotTestDestination (dest);
|
|
1017
|
+
}
|
|
1018
|
+
}
|
|
1019
|
+
|
|
1020
|
+
testMap.destinations = destinations;
|
|
1021
|
+
}
|
|
1022
|
+
|
|
1023
|
+
tester.testMaps[mapName] = testMap;
|
|
1024
|
+
}
|
|
1025
|
+
|
|
1026
|
+
if (route.destinationOrder != null)
|
|
1027
|
+
tester.testMaps[mapName].destinationOrder = route.destinationOrder;
|
|
1028
|
+
}
|
|
1029
|
+
}
|
|
1030
|
+
|
|
1031
|
+
this.addPage (page);
|
|
1032
|
+
}
|
|
1033
|
+
}
|
|
1034
|
+
|
|
1035
|
+
if (this.hotSite.apis != null)
|
|
1036
|
+
{
|
|
1037
|
+
for (let key in this.hotSite.apis)
|
|
1038
|
+
{
|
|
1039
|
+
let api = this.hotSite.apis[key];
|
|
1040
|
+
|
|
1041
|
+
if (api.map == null)
|
|
1042
|
+
continue;
|
|
1043
|
+
|
|
1044
|
+
if (HotStaq.isWeb === false)
|
|
1045
|
+
{
|
|
1046
|
+
if (this.mode === DeveloperMode.Development)
|
|
1047
|
+
{
|
|
1048
|
+
let mapName: string = key;
|
|
1049
|
+
let testMap: HotTestMap = new HotTestMap ();
|
|
1050
|
+
|
|
1051
|
+
testMap.destinations = [];
|
|
1052
|
+
|
|
1053
|
+
for (let iIdx = 0; iIdx < api.map.length; iIdx++)
|
|
1054
|
+
{
|
|
1055
|
+
let map: string = api.map[iIdx];
|
|
1056
|
+
|
|
1057
|
+
testMap.destinations.push (new HotTestDestination (map));
|
|
1058
|
+
}
|
|
1059
|
+
|
|
1060
|
+
if (tester == null)
|
|
1061
|
+
throw new Error (`A tester was not created first! You must specify one in the CLI or in HotSite.json.`);
|
|
1062
|
+
|
|
1063
|
+
tester.testMaps[mapName] = testMap;
|
|
1064
|
+
}
|
|
1065
|
+
}
|
|
1066
|
+
}
|
|
1067
|
+
}
|
|
1068
|
+
|
|
1069
|
+
/// @fixme Allow this to work for server-side as well...
|
|
1070
|
+
if (HotStaq.isWeb === true)
|
|
1071
|
+
{
|
|
1072
|
+
for (let key in this.hotSite.components)
|
|
1073
|
+
{
|
|
1074
|
+
let component = this.hotSite.components[key];
|
|
1075
|
+
let componentUrl: string = component.url;
|
|
1076
|
+
|
|
1077
|
+
/// @fixme Create unit test for fetching, loading, and registering.
|
|
1078
|
+
let res: any = await fetch (componentUrl);
|
|
1079
|
+
let newComponent: HotComponent = eval (res);
|
|
1080
|
+
|
|
1081
|
+
this.addComponent (newComponent);
|
|
1082
|
+
}
|
|
1083
|
+
}
|
|
1084
|
+
|
|
1085
|
+
if (this.hotSite.routes == null)
|
|
1086
|
+
this.hotSite.routes = {};
|
|
1087
|
+
|
|
1088
|
+
await this.loadHotFiles (this.hotSite.files);
|
|
1089
|
+
|
|
1090
|
+
if (tester != null)
|
|
1091
|
+
this.addTester (tester);
|
|
1092
|
+
}
|
|
1093
|
+
|
|
1094
|
+
/**
|
|
1095
|
+
* Load an array of files. If a file already has content, it will not be reloaded
|
|
1096
|
+
* unless forceContentLoading is set to true.
|
|
1097
|
+
*/
|
|
1098
|
+
async loadHotFiles (files: { [name: string]: { url?: string; localFile?: string; content?: string; } },
|
|
1099
|
+
forceContentLoading: boolean = false): Promise<void>
|
|
1100
|
+
{
|
|
1101
|
+
for (let key in files)
|
|
1102
|
+
{
|
|
1103
|
+
let file = files[key];
|
|
1104
|
+
let newFile: HotFile = null;
|
|
1105
|
+
|
|
1106
|
+
if (HotStaq.isWeb === true)
|
|
1107
|
+
{
|
|
1108
|
+
newFile = new HotFile ({
|
|
1109
|
+
"name": key
|
|
1110
|
+
});
|
|
1111
|
+
}
|
|
1112
|
+
else
|
|
1113
|
+
{
|
|
1114
|
+
newFile = new HotFile ({
|
|
1115
|
+
"name": key
|
|
1116
|
+
});
|
|
1117
|
+
}
|
|
1118
|
+
|
|
1119
|
+
if (file.url != null)
|
|
1120
|
+
newFile.url = file.url;
|
|
1121
|
+
|
|
1122
|
+
if (HotStaq.isWeb === false)
|
|
1123
|
+
{
|
|
1124
|
+
if (file.localFile != null)
|
|
1125
|
+
newFile.localFile = file.localFile;
|
|
1126
|
+
}
|
|
1127
|
+
|
|
1128
|
+
let loadContent: boolean = true;
|
|
1129
|
+
|
|
1130
|
+
if (file.content != null)
|
|
1131
|
+
{
|
|
1132
|
+
newFile.content = file.content;
|
|
1133
|
+
loadContent = false;
|
|
1134
|
+
}
|
|
1135
|
+
|
|
1136
|
+
if (forceContentLoading === true)
|
|
1137
|
+
loadContent = true;
|
|
1138
|
+
|
|
1139
|
+
if (loadContent === true)
|
|
1140
|
+
await newFile.load ();
|
|
1141
|
+
|
|
1142
|
+
this.addFile (newFile);
|
|
1143
|
+
}
|
|
1144
|
+
}
|
|
1145
|
+
|
|
1146
|
+
/**
|
|
1147
|
+
* Generate the content to send to a client.
|
|
1148
|
+
*/
|
|
1149
|
+
generateContent (routeKey: string, name: string = "", url: string = "./",
|
|
1150
|
+
jsSrcPath: string = "./js/HotStaq.js", passArgs: boolean = true,
|
|
1151
|
+
args: any = null): string
|
|
1152
|
+
{
|
|
1153
|
+
let apiScripts: string = "";
|
|
1154
|
+
let apiCode: string = "";
|
|
1155
|
+
let publicSecrets: string = "";
|
|
1156
|
+
|
|
1157
|
+
/// @todo Optimize this function as much as possible.
|
|
1158
|
+
|
|
1159
|
+
// Load the API string.
|
|
1160
|
+
if (this.hotSite != null)
|
|
1161
|
+
{
|
|
1162
|
+
if (this.hotSite.server.globalApi != null)
|
|
1163
|
+
{
|
|
1164
|
+
if (this.hotSite.server.globalApi !== "")
|
|
1165
|
+
{
|
|
1166
|
+
const globalApi = this.hotSite.apis[this.hotSite.server.globalApi];
|
|
1167
|
+
|
|
1168
|
+
if (globalApi == null)
|
|
1169
|
+
this.logger.warning (`API with name ${this.hotSite.server.globalApi} doesn't exist!`);
|
|
1170
|
+
else
|
|
1171
|
+
{
|
|
1172
|
+
let sendJSContent: boolean = true;
|
|
1173
|
+
|
|
1174
|
+
if (globalApi.jsapi == null)
|
|
1175
|
+
{
|
|
1176
|
+
sendJSContent = false;
|
|
1177
|
+
this.logger.warning (`API with name ${this.hotSite.server.globalApi} doesn't have a jsapi set. Will not send js content to client.`);
|
|
1178
|
+
}
|
|
1179
|
+
|
|
1180
|
+
if (globalApi.libraryName == null)
|
|
1181
|
+
{
|
|
1182
|
+
sendJSContent = false;
|
|
1183
|
+
this.logger.warning (`API with name ${this.hotSite.server.globalApi} doesn't have a libraryName set. Will not send js content to client.`);
|
|
1184
|
+
}
|
|
1185
|
+
|
|
1186
|
+
if (globalApi.apiName == null)
|
|
1187
|
+
{
|
|
1188
|
+
sendJSContent = false;
|
|
1189
|
+
this.logger.warning (`API with name ${this.hotSite.server.globalApi} doesn't have a apiName set. Will not send js content to client.`);
|
|
1190
|
+
}
|
|
1191
|
+
|
|
1192
|
+
if (sendJSContent === true)
|
|
1193
|
+
{
|
|
1194
|
+
apiScripts += `\t<script type = "text/javascript" src = "${globalApi.jsapi}"></script>\n`;
|
|
1195
|
+
|
|
1196
|
+
let baseUrl: string = "\"\"";
|
|
1197
|
+
|
|
1198
|
+
if (this.api != null)
|
|
1199
|
+
baseUrl = `\"${this.api.baseUrl}\"`;
|
|
1200
|
+
|
|
1201
|
+
let tempAPIContent: string = this.apiContent;
|
|
1202
|
+
tempAPIContent = tempAPIContent.replace (/\%api\_name\%/g, globalApi.apiName);
|
|
1203
|
+
tempAPIContent = tempAPIContent.replace (/\%api\_exported\_name\%/g, globalApi.libraryName);
|
|
1204
|
+
tempAPIContent = tempAPIContent.replace (/\%base\_url\%/g, baseUrl);
|
|
1205
|
+
|
|
1206
|
+
apiCode += tempAPIContent;
|
|
1207
|
+
}
|
|
1208
|
+
}
|
|
1209
|
+
}
|
|
1210
|
+
}
|
|
1211
|
+
|
|
1212
|
+
if (this.hotSite.apis != null)
|
|
1213
|
+
{
|
|
1214
|
+
let route = this.hotSite.routes[routeKey];
|
|
1215
|
+
|
|
1216
|
+
if (route != null)
|
|
1217
|
+
{
|
|
1218
|
+
if (route.api != null)
|
|
1219
|
+
{
|
|
1220
|
+
let api = this.hotSite.apis[route.api];
|
|
1221
|
+
|
|
1222
|
+
if (api == null)
|
|
1223
|
+
throw new Error (`Unable to find API ${route.api}`);
|
|
1224
|
+
|
|
1225
|
+
let sendJSContent: boolean = true;
|
|
1226
|
+
|
|
1227
|
+
if (api.jsapi == null)
|
|
1228
|
+
{
|
|
1229
|
+
sendJSContent = false;
|
|
1230
|
+
this.logger.warning (`API with name ${route.api} doesn't have a jsapi set. Will not send js content to client.`);
|
|
1231
|
+
}
|
|
1232
|
+
|
|
1233
|
+
if (api.libraryName == null)
|
|
1234
|
+
{
|
|
1235
|
+
sendJSContent = false;
|
|
1236
|
+
this.logger.warning (`API with name ${route.api} doesn't have a libraryName set. Will not send js content to client.`);
|
|
1237
|
+
}
|
|
1238
|
+
|
|
1239
|
+
if (api.apiName == null)
|
|
1240
|
+
{
|
|
1241
|
+
sendJSContent = false;
|
|
1242
|
+
this.logger.warning (`API with name ${route.api} doesn't have a apiName set. Will not send js content to client.`);
|
|
1243
|
+
}
|
|
1244
|
+
|
|
1245
|
+
if (sendJSContent === true)
|
|
1246
|
+
{
|
|
1247
|
+
let jsapipath = api.jsapi;
|
|
1248
|
+
apiScripts += `\t<script type = "text/javascript" src = "${jsapipath}"></script>\n`;
|
|
1249
|
+
|
|
1250
|
+
let baseUrl: string = "\"\"";
|
|
1251
|
+
|
|
1252
|
+
if (this.api != null)
|
|
1253
|
+
baseUrl = `\"${this.api.baseUrl}\"`;
|
|
1254
|
+
|
|
1255
|
+
let tempAPIContent: string = this.apiContent;
|
|
1256
|
+
tempAPIContent = tempAPIContent.replace (/\%api\_name\%/g, api.apiName);
|
|
1257
|
+
tempAPIContent = tempAPIContent.replace (/\%api\_exported\_name\%/g, api.libraryName);
|
|
1258
|
+
tempAPIContent = tempAPIContent.replace (/\%base\_url\%/g, baseUrl);
|
|
1259
|
+
|
|
1260
|
+
apiCode += tempAPIContent;
|
|
1261
|
+
}
|
|
1262
|
+
}
|
|
1263
|
+
}
|
|
1264
|
+
}
|
|
1265
|
+
|
|
1266
|
+
if (this.hotSite.server != null)
|
|
1267
|
+
{
|
|
1268
|
+
if (this.hotSite.server.jsSrcPath != null)
|
|
1269
|
+
jsSrcPath = this.hotSite.server.jsSrcPath;
|
|
1270
|
+
}
|
|
1271
|
+
|
|
1272
|
+
if (this.hotSite.publicSecrets != null)
|
|
1273
|
+
{
|
|
1274
|
+
for (let key in this.hotSite.publicSecrets)
|
|
1275
|
+
{
|
|
1276
|
+
let secret = this.hotSite.publicSecrets[key];
|
|
1277
|
+
let value: string = undefined;
|
|
1278
|
+
|
|
1279
|
+
if (typeof (secret) === "string")
|
|
1280
|
+
value = JSON.stringify (secret);
|
|
1281
|
+
else
|
|
1282
|
+
{
|
|
1283
|
+
if (HotStaq.isWeb === false)
|
|
1284
|
+
{
|
|
1285
|
+
if (this.api != null)
|
|
1286
|
+
{
|
|
1287
|
+
if (this.api.connection == null)
|
|
1288
|
+
throw new Error (`Cannot pass secrets from the API if there's no connection!`);
|
|
1289
|
+
|
|
1290
|
+
let serverConn: HotServer = (<HotServer>this.api.connection);
|
|
1291
|
+
|
|
1292
|
+
if (secret.passSecretFromAPI != null)
|
|
1293
|
+
value = JSON.stringify (serverConn.secrets[key]);
|
|
1294
|
+
}
|
|
1295
|
+
|
|
1296
|
+
if (secret.env != null)
|
|
1297
|
+
{
|
|
1298
|
+
/// @fixme @secvul Is this a security vulnerability? Need to verify that
|
|
1299
|
+
/// only the server has access to this. At this point, I think only the
|
|
1300
|
+
/// server has access.
|
|
1301
|
+
const envKey: string = secret.env;
|
|
1302
|
+
|
|
1303
|
+
value = JSON.stringify (process.env[envKey]);
|
|
1304
|
+
}
|
|
1305
|
+
}
|
|
1306
|
+
}
|
|
1307
|
+
|
|
1308
|
+
publicSecrets += `processor.publicSecrets["${key}"] = ${value};\n`;
|
|
1309
|
+
}
|
|
1310
|
+
}
|
|
1311
|
+
}
|
|
1312
|
+
|
|
1313
|
+
let content: string = this.pageContent;
|
|
1314
|
+
let fixContent = (tempContent: string) =>
|
|
1315
|
+
{
|
|
1316
|
+
let developerModeStr: string = "";
|
|
1317
|
+
let testerAPIStr: string = "";
|
|
1318
|
+
|
|
1319
|
+
if (this.mode === DeveloperMode.Development)
|
|
1320
|
+
{
|
|
1321
|
+
developerModeStr = `tempMode = HotStaqWeb.DeveloperMode.Development;`;
|
|
1322
|
+
testerAPIStr = this.testerApiContent;
|
|
1323
|
+
|
|
1324
|
+
if (this.hotSite != null)
|
|
1325
|
+
{
|
|
1326
|
+
if (this.hotSite.testing != null)
|
|
1327
|
+
{
|
|
1328
|
+
if (this.hotSite.testing.web.testerAPIUrl == null)
|
|
1329
|
+
this.hotSite.testing.web.testerAPIUrl = "http://127.0.0.1:8182";
|
|
1330
|
+
|
|
1331
|
+
testerAPIStr = testerAPIStr.replace (/\%base\_tester\_url\%/g, `\"${this.hotSite.testing.web.testerAPIUrl}\"`);
|
|
1332
|
+
}
|
|
1333
|
+
}
|
|
1334
|
+
}
|
|
1335
|
+
|
|
1336
|
+
let loadFiles: string = "";
|
|
1337
|
+
|
|
1338
|
+
if (Object.keys (this.files).length > 0)
|
|
1339
|
+
{
|
|
1340
|
+
loadFiles += `var files = {};\n\n`;
|
|
1341
|
+
|
|
1342
|
+
for (let key in this.files)
|
|
1343
|
+
{
|
|
1344
|
+
let file = this.files[key];
|
|
1345
|
+
let fileUrl: string = `"${file.url}"`;
|
|
1346
|
+
let fileContent: string = "";
|
|
1347
|
+
|
|
1348
|
+
if (file.content !== "")
|
|
1349
|
+
{
|
|
1350
|
+
let escapedContent: string = JSON.stringify (file.content);
|
|
1351
|
+
|
|
1352
|
+
// Find any script tags and interrupt them so the HTML parsers
|
|
1353
|
+
// don't get confused.
|
|
1354
|
+
escapedContent = escapedContent.replace (new RegExp ("\\<script", "gmi"), "<scr\" + \"ipt");
|
|
1355
|
+
escapedContent = escapedContent.replace (new RegExp ("\\<\\/script", "gmi"), "</scr\" + \"ipt");
|
|
1356
|
+
|
|
1357
|
+
fileContent = `, "content": ${escapedContent}`;
|
|
1358
|
+
}
|
|
1359
|
+
|
|
1360
|
+
loadFiles += `\t\t\tfiles["${key}"] = { "url": ${fileUrl}${fileContent} };\n`;
|
|
1361
|
+
}
|
|
1362
|
+
|
|
1363
|
+
loadFiles += `\t\t\tpromises.push (processor.loadHotFiles (files));\n`;
|
|
1364
|
+
}
|
|
1365
|
+
|
|
1366
|
+
tempContent = tempContent.replace (/\%title\%/g, name);
|
|
1367
|
+
|
|
1368
|
+
if (passArgs === true)
|
|
1369
|
+
tempContent = tempContent.replace (/\%args\%/g, "Hot.Arguments");
|
|
1370
|
+
|
|
1371
|
+
if (args != null)
|
|
1372
|
+
tempContent = tempContent.replace (/\%args\%/g, JSON.stringify (args));
|
|
1373
|
+
|
|
1374
|
+
let testerMap: string = routeKey;
|
|
1375
|
+
let testerUrl: string = "";
|
|
1376
|
+
let testerLaunchpadUrl: string = "";
|
|
1377
|
+
let testerName: string = "Tester";
|
|
1378
|
+
|
|
1379
|
+
if (this.hotSite != null)
|
|
1380
|
+
{
|
|
1381
|
+
if (this.hotSite.testing != null)
|
|
1382
|
+
{
|
|
1383
|
+
if (this.hotSite.testing.web.tester != null)
|
|
1384
|
+
testerName = this.hotSite.testing.web.tester;
|
|
1385
|
+
|
|
1386
|
+
if (this.hotSite.testing.web.testerName != null)
|
|
1387
|
+
testerName = this.hotSite.testing.web.testerName;
|
|
1388
|
+
|
|
1389
|
+
if (this.hotSite.testing.web.testerAPIUrl != null)
|
|
1390
|
+
testerUrl = this.hotSite.testing.web.testerAPIUrl;
|
|
1391
|
+
|
|
1392
|
+
if (this.hotSite.testing.web.launchpadUrl != null)
|
|
1393
|
+
testerLaunchpadUrl = this.hotSite.testing.web.launchpadUrl;
|
|
1394
|
+
}
|
|
1395
|
+
|
|
1396
|
+
if (this.hotSite.routes != null)
|
|
1397
|
+
{
|
|
1398
|
+
if (this.hotSite.routes[routeKey] != null)
|
|
1399
|
+
{
|
|
1400
|
+
let route = this.hotSite.routes[routeKey];
|
|
1401
|
+
testerMap = route.name;
|
|
1402
|
+
}
|
|
1403
|
+
}
|
|
1404
|
+
}
|
|
1405
|
+
|
|
1406
|
+
tempContent = tempContent.replace (/\%hotstaq\_js\_src\%/g, jsSrcPath);
|
|
1407
|
+
tempContent = tempContent.replace (/\%developer\_mode\%/g, developerModeStr);
|
|
1408
|
+
tempContent = tempContent.replace (/\%tester\_api\%/g, testerAPIStr);
|
|
1409
|
+
tempContent = tempContent.replace (/\%apis\_to\_load\%/g, apiScripts);
|
|
1410
|
+
tempContent = tempContent.replace (/\%load\_hot\_site\%/g, ""); /// @fixme Should this only be done server-side?
|
|
1411
|
+
tempContent = tempContent.replace (/\%load\_files\%/g, loadFiles);
|
|
1412
|
+
tempContent = tempContent.replace (/\%api\_code\%/g, apiCode);
|
|
1413
|
+
tempContent = tempContent.replace (/\%public\_secrets\%/g, publicSecrets);
|
|
1414
|
+
tempContent = tempContent.replace (/\%url\%/g, url);
|
|
1415
|
+
tempContent = tempContent.replace (/\%tester\_name\%/g, `"${testerName}"`);
|
|
1416
|
+
tempContent = tempContent.replace (/\%tester\_map\%/g, `"${testerMap}"`);
|
|
1417
|
+
tempContent = tempContent.replace (/\%tester\_api\_base\_url\%/g, `"${testerUrl}"`);
|
|
1418
|
+
tempContent = tempContent.replace (/\%tester\_launchpad\_url\%/g, `"${testerLaunchpadUrl}"`);
|
|
1419
|
+
|
|
1420
|
+
return (tempContent);
|
|
1421
|
+
};
|
|
1422
|
+
content = fixContent (content);
|
|
1423
|
+
|
|
1424
|
+
return (content);
|
|
1425
|
+
}
|
|
1426
|
+
|
|
1427
|
+
/**
|
|
1428
|
+
* Create the Express routes from the given pages. Be sure to load the
|
|
1429
|
+
* pages first before doing this. This method is meant to be used for
|
|
1430
|
+
* customized Express applications. If you wish to use the loaded routes
|
|
1431
|
+
* from this HotStaq object with HotHTTPServer, be sure to use
|
|
1432
|
+
* the loadHotSite method in HotHTTPServer.
|
|
1433
|
+
*/
|
|
1434
|
+
createExpressRoutes (expressApp: any, jsSrcPath: string = "./js/HotStaq.js"): void
|
|
1435
|
+
{
|
|
1436
|
+
for (let key in this.pages)
|
|
1437
|
+
{
|
|
1438
|
+
let page: HotPage = this.pages[key];
|
|
1439
|
+
const content: string = this.generateContent (page.route, page.name, page.files[0].url, jsSrcPath);
|
|
1440
|
+
|
|
1441
|
+
expressApp.get (page.route, (req: any, res: any) =>
|
|
1442
|
+
{
|
|
1443
|
+
res.send (content);
|
|
1444
|
+
});
|
|
1445
|
+
}
|
|
1446
|
+
}
|
|
1447
|
+
|
|
1448
|
+
/**
|
|
1449
|
+
* Add a tester for use later.
|
|
1450
|
+
*/
|
|
1451
|
+
addTester (tester: HotTester): void
|
|
1452
|
+
{
|
|
1453
|
+
this.testers[tester.name] = tester;
|
|
1454
|
+
}
|
|
1455
|
+
|
|
1456
|
+
/**
|
|
1457
|
+
* Get the list of maps for testing from the HotSite.
|
|
1458
|
+
*/
|
|
1459
|
+
getWebTestingMaps (): string[]
|
|
1460
|
+
{
|
|
1461
|
+
if (this.hotSite == null)
|
|
1462
|
+
throw new Error ("No HotSite was loaded!");
|
|
1463
|
+
|
|
1464
|
+
if (this.hotSite.testing == null)
|
|
1465
|
+
throw new Error ("The HotSite does not have a testing object!");
|
|
1466
|
+
|
|
1467
|
+
if (this.hotSite.testing.web == null)
|
|
1468
|
+
throw new Error ("The HotSite does not have a testing web object!");
|
|
1469
|
+
|
|
1470
|
+
if (this.hotSite.testing.web.maps == null)
|
|
1471
|
+
throw new Error ("The HotSite testing object does not have any maps!");
|
|
1472
|
+
|
|
1473
|
+
return (this.hotSite.testing.web.maps);
|
|
1474
|
+
}
|
|
1475
|
+
|
|
1476
|
+
/**
|
|
1477
|
+
* Get the list of maps for testing from the HotSite.
|
|
1478
|
+
*/
|
|
1479
|
+
getAPITestingMaps (): string[]
|
|
1480
|
+
{
|
|
1481
|
+
if (this.hotSite == null)
|
|
1482
|
+
throw new Error ("No HotSite was loaded!");
|
|
1483
|
+
|
|
1484
|
+
if (this.hotSite.testing == null)
|
|
1485
|
+
throw new Error ("The HotSite does not have a testing object!");
|
|
1486
|
+
|
|
1487
|
+
if (this.hotSite.testing.api == null)
|
|
1488
|
+
throw new Error ("The HotSite does not have a testing api object!");
|
|
1489
|
+
|
|
1490
|
+
if (this.hotSite.testing.api.maps == null)
|
|
1491
|
+
throw new Error ("The HotSite testing object does not have any maps!");
|
|
1492
|
+
|
|
1493
|
+
return (this.hotSite.testing.api.maps);
|
|
1494
|
+
}
|
|
1495
|
+
|
|
1496
|
+
/**
|
|
1497
|
+
* Get a route's key from a route's name.
|
|
1498
|
+
*/
|
|
1499
|
+
getRouteKeyFromName (name: string): string
|
|
1500
|
+
{
|
|
1501
|
+
let foundKey: string = "";
|
|
1502
|
+
|
|
1503
|
+
if (this.hotSite != null)
|
|
1504
|
+
{
|
|
1505
|
+
if (this.hotSite.routes != null)
|
|
1506
|
+
{
|
|
1507
|
+
for (let key in this.hotSite.routes)
|
|
1508
|
+
{
|
|
1509
|
+
let route: HotSiteRoute = this.hotSite.routes[key];
|
|
1510
|
+
|
|
1511
|
+
if (route.name === name)
|
|
1512
|
+
{
|
|
1513
|
+
foundKey = key;
|
|
1514
|
+
|
|
1515
|
+
break;
|
|
1516
|
+
}
|
|
1517
|
+
}
|
|
1518
|
+
}
|
|
1519
|
+
}
|
|
1520
|
+
|
|
1521
|
+
return (foundKey);
|
|
1522
|
+
}
|
|
1523
|
+
|
|
1524
|
+
/**
|
|
1525
|
+
* Get a route from a route's name.
|
|
1526
|
+
*/
|
|
1527
|
+
getRouteFromName (name: string): HotSiteRoute
|
|
1528
|
+
{
|
|
1529
|
+
let foundRoute: HotSiteRoute = null;
|
|
1530
|
+
let foundKey: string = this.getRouteKeyFromName (name);
|
|
1531
|
+
|
|
1532
|
+
if (foundKey !== "")
|
|
1533
|
+
foundRoute = this.hotSite.routes[foundKey];
|
|
1534
|
+
|
|
1535
|
+
return (foundRoute);
|
|
1536
|
+
}
|
|
1537
|
+
|
|
1538
|
+
/**
|
|
1539
|
+
* Execute tests.
|
|
1540
|
+
*
|
|
1541
|
+
* @param testerName The tester to use to execute tests.
|
|
1542
|
+
* @param mapName The map or maps to use to navigate through tests.
|
|
1543
|
+
*/
|
|
1544
|
+
async executeTests (testerName: string, mapName: string): Promise<void>
|
|
1545
|
+
{
|
|
1546
|
+
let tester: HotTester = this.testers[testerName];
|
|
1547
|
+
|
|
1548
|
+
if (tester == null)
|
|
1549
|
+
throw new Error (`Unable to execute tests. Tester ${testerName} does not exist!`);
|
|
1550
|
+
|
|
1551
|
+
return (tester.execute (mapName));
|
|
1552
|
+
}
|
|
1553
|
+
|
|
1554
|
+
/**
|
|
1555
|
+
* Execute all web tests from the HotSite testing web object.
|
|
1556
|
+
*
|
|
1557
|
+
* @param testerName The tester to use to execute tests.
|
|
1558
|
+
*/
|
|
1559
|
+
async executeAllWebTests (testerName: string): Promise<void>
|
|
1560
|
+
{
|
|
1561
|
+
let maps: string[] = this.getWebTestingMaps ();
|
|
1562
|
+
let tester: HotTester = this.testers[testerName];
|
|
1563
|
+
|
|
1564
|
+
if (tester == null)
|
|
1565
|
+
throw new Error (`Unable to execute tests. Tester ${testerName} does not exist!`);
|
|
1566
|
+
|
|
1567
|
+
for (let iIdx = 0; iIdx < maps.length; iIdx++)
|
|
1568
|
+
{
|
|
1569
|
+
let mapName: string = maps[iIdx];
|
|
1570
|
+
|
|
1571
|
+
await this.executeTests (testerName, mapName);
|
|
1572
|
+
}
|
|
1573
|
+
}
|
|
1574
|
+
|
|
1575
|
+
/**
|
|
1576
|
+
* Execute all api tests from the HotSite testing api object.
|
|
1577
|
+
*
|
|
1578
|
+
* @param testerName The tester to use to execute tests.
|
|
1579
|
+
*/
|
|
1580
|
+
async executeAllAPITests (testerName: string): Promise<void>
|
|
1581
|
+
{
|
|
1582
|
+
let maps: string[] = this.getAPITestingMaps ();
|
|
1583
|
+
let tester: HotTester = this.testers[testerName];
|
|
1584
|
+
|
|
1585
|
+
if (tester == null)
|
|
1586
|
+
throw new Error (`Unable to execute tests. Tester ${testerName} does not exist!`);
|
|
1587
|
+
|
|
1588
|
+
for (let iIdx = 0; iIdx < maps.length; iIdx++)
|
|
1589
|
+
{
|
|
1590
|
+
let mapName: string = maps[iIdx];
|
|
1591
|
+
|
|
1592
|
+
await this.executeTests (testerName, mapName);
|
|
1593
|
+
}
|
|
1594
|
+
}
|
|
1595
|
+
|
|
1596
|
+
/**
|
|
1597
|
+
* Process a page and get the result.
|
|
1598
|
+
*/
|
|
1599
|
+
async process (pageName: string, args: any = null): Promise<string>
|
|
1600
|
+
{
|
|
1601
|
+
let page: HotPage = this.getPage (pageName);
|
|
1602
|
+
let result: string = await page.process (args);
|
|
1603
|
+
|
|
1604
|
+
return (result);
|
|
1605
|
+
}
|
|
1606
|
+
|
|
1607
|
+
/**
|
|
1608
|
+
* Process a local file and get the result.
|
|
1609
|
+
*/
|
|
1610
|
+
static async processLocalFile (localFilepath: string, name: string = localFilepath, args: any = null): Promise<string>
|
|
1611
|
+
{
|
|
1612
|
+
let processor: HotStaq = new HotStaq ();
|
|
1613
|
+
let file: HotFile = new HotFile ({
|
|
1614
|
+
"localFile": localFilepath
|
|
1615
|
+
});
|
|
1616
|
+
await file.load ();
|
|
1617
|
+
let page: HotPage = new HotPage ({
|
|
1618
|
+
"processor": processor,
|
|
1619
|
+
"name": name,
|
|
1620
|
+
"files": [file]
|
|
1621
|
+
});
|
|
1622
|
+
processor.addPage (page);
|
|
1623
|
+
let result: string = await processor.process (name, args);
|
|
1624
|
+
|
|
1625
|
+
return (result);
|
|
1626
|
+
}
|
|
1627
|
+
|
|
1628
|
+
/**
|
|
1629
|
+
* Process a url and get the result.
|
|
1630
|
+
*/
|
|
1631
|
+
static async processUrl (options: HotStartOptions): Promise<string>
|
|
1632
|
+
{
|
|
1633
|
+
let file: HotFile = new HotFile ({
|
|
1634
|
+
"url": options.url
|
|
1635
|
+
});
|
|
1636
|
+
|
|
1637
|
+
await file.load ();
|
|
1638
|
+
let page: HotPage = new HotPage ({
|
|
1639
|
+
"processor": options.processor,
|
|
1640
|
+
"name": options.name,
|
|
1641
|
+
"files": [file],
|
|
1642
|
+
"testerName": options.testerName,
|
|
1643
|
+
"testerMap": options.testerMap
|
|
1644
|
+
});
|
|
1645
|
+
options.processor.addPage (page);
|
|
1646
|
+
let result: string = await options.processor.process (options.name, options.args);
|
|
1647
|
+
|
|
1648
|
+
return (result);
|
|
1649
|
+
}
|
|
1650
|
+
|
|
1651
|
+
/**
|
|
1652
|
+
* Process content and get the result.
|
|
1653
|
+
*/
|
|
1654
|
+
static async processContent (processor: HotStaq,
|
|
1655
|
+
content: string, name: string, args: any = null): Promise<string>
|
|
1656
|
+
{
|
|
1657
|
+
let file: HotFile = new HotFile ({
|
|
1658
|
+
"content": content
|
|
1659
|
+
});
|
|
1660
|
+
await file.load ();
|
|
1661
|
+
let page: HotPage = new HotPage ({
|
|
1662
|
+
"processor": processor,
|
|
1663
|
+
"name": name,
|
|
1664
|
+
"files": [file]
|
|
1665
|
+
});
|
|
1666
|
+
processor.addPage (page);
|
|
1667
|
+
let result: string = await processor.process (name, args);
|
|
1668
|
+
|
|
1669
|
+
return (result);
|
|
1670
|
+
}
|
|
1671
|
+
|
|
1672
|
+
/**
|
|
1673
|
+
* When the window has finished loading, execute the function.
|
|
1674
|
+
* This is meant for web browser use only.
|
|
1675
|
+
*/
|
|
1676
|
+
static onReady (readyFunc: () => void): void
|
|
1677
|
+
{
|
|
1678
|
+
if ((document.readyState === "complete") || (document.readyState === "interactive"))
|
|
1679
|
+
readyFunc ();
|
|
1680
|
+
else
|
|
1681
|
+
window.addEventListener ("load", readyFunc);
|
|
1682
|
+
}
|
|
1683
|
+
|
|
1684
|
+
/**
|
|
1685
|
+
* Replace the current HTML page with the output.
|
|
1686
|
+
* This is meant for web browser use only.
|
|
1687
|
+
*/
|
|
1688
|
+
static useOutput (output: string): void
|
|
1689
|
+
{
|
|
1690
|
+
document.open ();
|
|
1691
|
+
document.write (output);
|
|
1692
|
+
document.close ();
|
|
1693
|
+
}
|
|
1694
|
+
|
|
1695
|
+
/**
|
|
1696
|
+
* Wait for testers to load.
|
|
1697
|
+
*
|
|
1698
|
+
* @fixme This does not wait for ALL testers to finish loading. Only
|
|
1699
|
+
* the first one.
|
|
1700
|
+
*/
|
|
1701
|
+
static async waitForTesters (): Promise<void>
|
|
1702
|
+
{
|
|
1703
|
+
while (HotStaq.isReadyForTesting === false)
|
|
1704
|
+
await HotStaq.wait (10);
|
|
1705
|
+
|
|
1706
|
+
if (HotStaq.onReadyForTesting != null)
|
|
1707
|
+
await HotStaq.onReadyForTesting ();
|
|
1708
|
+
}
|
|
1709
|
+
|
|
1710
|
+
/**
|
|
1711
|
+
* Process and replace the current HTML page with the hott script from the given url.
|
|
1712
|
+
* This is meant for web browser use only.
|
|
1713
|
+
*/
|
|
1714
|
+
static async displayUrl (url: string | HotStartOptions, name: string = null,
|
|
1715
|
+
processor: HotStaq = null, args: any = null): Promise<HotStaq>
|
|
1716
|
+
{
|
|
1717
|
+
return (new Promise<HotStaq> ((resolve, reject) =>
|
|
1718
|
+
{
|
|
1719
|
+
HotStaq.onReady (async () =>
|
|
1720
|
+
{
|
|
1721
|
+
let options: HotStartOptions = {
|
|
1722
|
+
"url": ""
|
|
1723
|
+
};
|
|
1724
|
+
|
|
1725
|
+
if (name == null)
|
|
1726
|
+
{
|
|
1727
|
+
if (typeof (url) === "string")
|
|
1728
|
+
options.name = url;
|
|
1729
|
+
else
|
|
1730
|
+
options.name = url.name;
|
|
1731
|
+
}
|
|
1732
|
+
else
|
|
1733
|
+
options.name = name;
|
|
1734
|
+
|
|
1735
|
+
if (options.name === "")
|
|
1736
|
+
{
|
|
1737
|
+
if (typeof (url) === "string")
|
|
1738
|
+
options.name = url;
|
|
1739
|
+
else
|
|
1740
|
+
options.name = url.name;
|
|
1741
|
+
}
|
|
1742
|
+
|
|
1743
|
+
if (typeof (url) === "string")
|
|
1744
|
+
options.url = url;
|
|
1745
|
+
else
|
|
1746
|
+
{
|
|
1747
|
+
options.url = url.url;
|
|
1748
|
+
|
|
1749
|
+
if (processor == null)
|
|
1750
|
+
{
|
|
1751
|
+
if (url.processor != null)
|
|
1752
|
+
processor = url.processor;
|
|
1753
|
+
}
|
|
1754
|
+
|
|
1755
|
+
if (args == null)
|
|
1756
|
+
{
|
|
1757
|
+
if (url.args != null)
|
|
1758
|
+
args = url.args;
|
|
1759
|
+
}
|
|
1760
|
+
|
|
1761
|
+
if (url.testerMap != null)
|
|
1762
|
+
options.testerMap = url.testerMap;
|
|
1763
|
+
|
|
1764
|
+
if (url.testerName != null)
|
|
1765
|
+
options.testerName = url.testerName;
|
|
1766
|
+
|
|
1767
|
+
if (url.testerAPIBaseUrl != null)
|
|
1768
|
+
options.testerAPIBaseUrl = url.testerAPIBaseUrl;
|
|
1769
|
+
}
|
|
1770
|
+
|
|
1771
|
+
if (processor == null)
|
|
1772
|
+
processor = new HotStaq ();
|
|
1773
|
+
|
|
1774
|
+
if (processor.mode === DeveloperMode.Development)
|
|
1775
|
+
{
|
|
1776
|
+
if (processor.testerAPI == null)
|
|
1777
|
+
{
|
|
1778
|
+
if (options.testerAPIBaseUrl == null)
|
|
1779
|
+
options.testerAPIBaseUrl = "";
|
|
1780
|
+
|
|
1781
|
+
if (options.testerAPIBaseUrl === "")
|
|
1782
|
+
options.testerAPIBaseUrl = "http://127.0.0.1:8182";
|
|
1783
|
+
|
|
1784
|
+
let client: HotClient = new HotClient (processor);
|
|
1785
|
+
let testerAPI: HotTesterAPI = new HotTesterAPI (options.testerAPIBaseUrl, client);
|
|
1786
|
+
testerAPI.connection.api = testerAPI;
|
|
1787
|
+
processor.testerAPI = testerAPI;
|
|
1788
|
+
}
|
|
1789
|
+
}
|
|
1790
|
+
|
|
1791
|
+
options.processor = processor;
|
|
1792
|
+
options.args = args;
|
|
1793
|
+
|
|
1794
|
+
let output: string = await HotStaq.processUrl (options);
|
|
1795
|
+
|
|
1796
|
+
if (processor.mode === DeveloperMode.Development)
|
|
1797
|
+
{
|
|
1798
|
+
output +=
|
|
1799
|
+
`<script type = "text/javascript">
|
|
1800
|
+
function hotstaq_isDocumentReady ()
|
|
1801
|
+
{
|
|
1802
|
+
if (window["Hot"] != null)
|
|
1803
|
+
{
|
|
1804
|
+
if (Hot.Mode === HotStaqWeb.DeveloperMode.Development)
|
|
1805
|
+
{
|
|
1806
|
+
let func = function ()
|
|
1807
|
+
{
|
|
1808
|
+
if (Hot.TesterAPI != null)
|
|
1809
|
+
{
|
|
1810
|
+
let testPaths = {};
|
|
1811
|
+
let testElements = JSON.stringify (Hot.CurrentPage.testElements);
|
|
1812
|
+
let testMaps = JSON.stringify (Hot.CurrentPage.testMaps);
|
|
1813
|
+
|
|
1814
|
+
for (let key in Hot.CurrentPage.testPaths)
|
|
1815
|
+
{
|
|
1816
|
+
let testPath = Hot.CurrentPage.testPaths[key];
|
|
1817
|
+
|
|
1818
|
+
testPaths[key] = testPath.toString ();
|
|
1819
|
+
}
|
|
1820
|
+
|
|
1821
|
+
let testPathsStr = JSON.stringify (testPaths);
|
|
1822
|
+
|
|
1823
|
+
Hot.TesterAPI.tester.pageLoaded ({
|
|
1824
|
+
testerName: Hot.CurrentPage.testerName,
|
|
1825
|
+
testerMap: Hot.CurrentPage.testerMap,
|
|
1826
|
+
pageName: Hot.CurrentPage.name,
|
|
1827
|
+
testElements: testElements,
|
|
1828
|
+
testPaths: testPathsStr
|
|
1829
|
+
}).then (function (resp)
|
|
1830
|
+
{
|
|
1831
|
+
if (resp.error != null)
|
|
1832
|
+
{
|
|
1833
|
+
if (resp.error !== "")
|
|
1834
|
+
throw new Error (resp.error);
|
|
1835
|
+
}
|
|
1836
|
+
|
|
1837
|
+
HotStaqWeb.HotStaq.isReadyForTesting = true;
|
|
1838
|
+
});
|
|
1839
|
+
}
|
|
1840
|
+
};
|
|
1841
|
+
|
|
1842
|
+
if ((document.readyState === "complete") || (document.readyState === "interactive"))
|
|
1843
|
+
func ();
|
|
1844
|
+
else
|
|
1845
|
+
document.addEventListener ("DOMContentLoaded", func);
|
|
1846
|
+
}
|
|
1847
|
+
}
|
|
1848
|
+
}
|
|
1849
|
+
|
|
1850
|
+
hotstaq_isDocumentReady ();
|
|
1851
|
+
</script>`;
|
|
1852
|
+
}
|
|
1853
|
+
|
|
1854
|
+
HotStaq.useOutput (output);
|
|
1855
|
+
resolve (processor);
|
|
1856
|
+
});
|
|
1857
|
+
}));
|
|
1858
|
+
}
|
|
1859
|
+
|
|
1860
|
+
/**
|
|
1861
|
+
* Process and replace the current HTML page with the hott script.
|
|
1862
|
+
* This is meant for web browser use only.
|
|
1863
|
+
*/
|
|
1864
|
+
static async displayContent (content: string, name: string, processor: HotStaq = null): Promise<HotStaq>
|
|
1865
|
+
{
|
|
1866
|
+
return (new Promise<HotStaq> ((resolve, reject) =>
|
|
1867
|
+
{
|
|
1868
|
+
HotStaq.onReady (async () =>
|
|
1869
|
+
{
|
|
1870
|
+
if (processor == null)
|
|
1871
|
+
processor = new HotStaq ();
|
|
1872
|
+
|
|
1873
|
+
let output: string = await HotStaq.processContent (processor, content, name);
|
|
1874
|
+
|
|
1875
|
+
HotStaq.useOutput (output);
|
|
1876
|
+
resolve (processor);
|
|
1877
|
+
});
|
|
1878
|
+
}));
|
|
1879
|
+
}
|
|
1880
|
+
}
|
|
1881
|
+
|