@silexlabs/silex 3.0.0-alpha.49 → 3.0.0-alpha.51
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/dist/client/client/config.d.ts +14 -1
- package/dist/client/client/grapesjs/PublicationManager.d.ts +2 -7
- package/dist/client/client/publication-transformers.d.ts +41 -0
- package/dist/client/css/admin.css +4 -1
- package/dist/client/js/main.js +3 -3
- package/dist/client/types.d.ts +18 -16
- package/dist/plugins/client/client/api.d.ts +83 -0
- package/dist/plugins/client/client/api.js +105 -0
- package/dist/plugins/client/client/api.js.map +1 -0
- package/dist/plugins/client/client/config.d.ts +58 -0
- package/dist/plugins/client/client/config.js +80 -0
- package/dist/plugins/client/client/config.js.map +1 -0
- package/dist/plugins/client/client/events.js +2 -0
- package/dist/plugins/client/client/events.js.map +1 -1
- package/dist/plugins/client/client/grapesjs/LoginDialog.d.ts +15 -0
- package/dist/plugins/client/client/grapesjs/LoginDialog.js +193 -0
- package/dist/plugins/client/client/grapesjs/LoginDialog.js.map +1 -0
- package/dist/plugins/client/client/grapesjs/PublicationManager.d.ts +70 -0
- package/dist/plugins/client/client/grapesjs/PublicationManager.js +310 -0
- package/dist/plugins/client/client/grapesjs/PublicationManager.js.map +1 -0
- package/dist/plugins/client/client/grapesjs/PublicationUi.d.ts +61 -0
- package/dist/plugins/client/client/grapesjs/PublicationUi.js +324 -0
- package/dist/plugins/client/client/grapesjs/PublicationUi.js.map +1 -0
- package/dist/plugins/client/client/grapesjs/blocks.d.ts +1 -0
- package/dist/plugins/client/client/grapesjs/blocks.js +37 -0
- package/dist/plugins/client/client/grapesjs/blocks.js.map +1 -0
- package/dist/plugins/client/client/grapesjs/index.d.ts +5 -0
- package/dist/plugins/client/client/grapesjs/index.js +264 -0
- package/dist/plugins/client/client/grapesjs/index.js.map +1 -0
- package/dist/plugins/client/client/grapesjs/internal-links.d.ts +1 -0
- package/dist/plugins/client/client/grapesjs/internal-links.js +220 -0
- package/dist/plugins/client/client/grapesjs/internal-links.js.map +1 -0
- package/dist/plugins/client/client/grapesjs/new-page-dialog.d.ts +2 -0
- package/dist/plugins/client/client/grapesjs/new-page-dialog.js +83 -0
- package/dist/plugins/client/client/grapesjs/new-page-dialog.js.map +1 -0
- package/dist/plugins/client/client/grapesjs/openImport.d.ts +9 -0
- package/dist/plugins/client/client/grapesjs/openImport.js +74 -0
- package/dist/plugins/client/client/grapesjs/openImport.js.map +1 -0
- package/dist/plugins/client/client/grapesjs/page-panel.d.ts +3 -0
- package/dist/plugins/client/client/grapesjs/page-panel.js +113 -0
- package/dist/plugins/client/client/grapesjs/page-panel.js.map +1 -0
- package/dist/plugins/client/client/grapesjs/project-bar.d.ts +1 -0
- package/dist/plugins/client/client/grapesjs/project-bar.js +106 -0
- package/dist/plugins/client/client/grapesjs/project-bar.js.map +1 -0
- package/dist/plugins/client/client/grapesjs/rich-text.d.ts +1 -0
- package/dist/plugins/client/client/grapesjs/rich-text.js +31 -0
- package/dist/plugins/client/client/grapesjs/rich-text.js.map +1 -0
- package/dist/plugins/client/client/grapesjs/semantic.d.ts +1 -0
- package/dist/plugins/client/client/grapesjs/semantic.js +110 -0
- package/dist/plugins/client/client/grapesjs/semantic.js.map +1 -0
- package/dist/plugins/client/client/grapesjs/settings.d.ts +2 -0
- package/dist/plugins/client/client/grapesjs/settings.js +197 -0
- package/dist/plugins/client/client/grapesjs/settings.js.map +1 -0
- package/dist/plugins/client/client/grapesjs/storage.d.ts +1 -0
- package/dist/plugins/client/client/grapesjs/storage.js +124 -0
- package/dist/plugins/client/client/grapesjs/storage.js.map +1 -0
- package/dist/plugins/client/client/grapesjs/symbolDialogs.d.ts +3 -0
- package/dist/plugins/client/client/grapesjs/symbolDialogs.js +36 -0
- package/dist/plugins/client/client/grapesjs/symbolDialogs.js.map +1 -0
- package/dist/plugins/client/client/publication-transformers.d.ts +41 -0
- package/dist/plugins/client/client/publication-transformers.js +165 -0
- package/dist/plugins/client/client/publication-transformers.js.map +1 -0
- package/dist/plugins/client/constants.d.ts +29 -0
- package/dist/plugins/client/constants.js +46 -0
- package/dist/plugins/client/constants.js.map +1 -0
- package/dist/plugins/client/plugins/client/11ty.d.ts +17 -0
- package/dist/plugins/client/plugins/client/11ty.js +70 -0
- package/dist/plugins/client/plugins/client/11ty.js.map +1 -0
- package/dist/plugins/client/plugins/client/publicationRenderer.js +59 -21
- package/dist/plugins/client/plugins/client/publicationRenderer.js.map +1 -1
- package/dist/plugins/client/plugins/client/website-info.js +1 -1
- package/dist/plugins/client/plugins/client/website-info.js.map +1 -1
- package/dist/plugins/client/types.d.ts +18 -16
- package/dist/plugins/client/types.js.map +1 -1
- package/dist/plugins/server/plugins/server/FtpConnector.d.ts +2 -1
- package/dist/plugins/server/plugins/server/FtpConnector.js +5 -6
- package/dist/plugins/server/plugins/server/FtpConnector.js.map +1 -1
- package/dist/plugins/server/plugins/server/GitlabConnector.d.ts +1 -7
- package/dist/plugins/server/plugins/server/GitlabConnector.js +124 -112
- package/dist/plugins/server/plugins/server/GitlabConnector.js.map +1 -1
- package/dist/plugins/server/server/connectors/FsHosting.d.ts +2 -1
- package/dist/plugins/server/server/connectors/FsHosting.js +4 -5
- package/dist/plugins/server/server/connectors/FsHosting.js.map +1 -1
- package/dist/plugins/server/server/connectors/FsStorage.js +1 -0
- package/dist/plugins/server/server/connectors/FsStorage.js.map +1 -1
- package/dist/plugins/server/server/connectors/connectors.d.ts +2 -1
- package/dist/plugins/server/server/connectors/connectors.js.map +1 -1
- package/dist/plugins/server/server/jobs.d.ts +6 -0
- package/dist/plugins/server/server/jobs.js +3 -1
- package/dist/plugins/server/server/jobs.js.map +1 -1
- package/dist/plugins/server/types.d.ts +18 -16
- package/dist/plugins/server/types.js.map +1 -1
- package/dist/server/server/api/publicationApi.js +14 -20
- package/dist/server/server/connectors/FsHosting.js +4 -5
- package/dist/server/server/connectors/FsStorage.js +1 -0
- package/dist/server/server/jobs.js +2 -1
- package/package.json +1 -1
- package/public/silex.js +23 -0
- package/src/css/website-info.scss +4 -1
- package/src/ts/client/config.ts +22 -2
- package/src/ts/client/events.ts +3 -0
- package/src/ts/client/grapesjs/PublicationManager.ts +23 -3
- package/src/ts/client/grapesjs/internal-links.ts +0 -2
- package/src/ts/client/grapesjs/storage.ts +1 -1
- package/src/ts/client/index.ts +4 -0
- package/src/ts/client/publication-transformers.test.ts +146 -0
- package/src/ts/client/publication-transformers.ts +188 -0
- package/src/ts/plugins/client/11ty.ts +89 -0
- package/src/ts/plugins/client/publicationRenderer.ts +64 -22
- package/src/ts/plugins/client/website-info.ts +1 -1
- package/src/ts/plugins/server/FtpConnector.ts +3 -3
- package/src/ts/plugins/server/GitlabConnector.ts +128 -109
- package/src/ts/server/api/publicationApi.ts +16 -23
- package/src/ts/server/connectors/FsHosting.ts +2 -2
- package/src/ts/server/connectors/FsStorage.ts +1 -0
- package/src/ts/server/connectors/connectors.ts +3 -1
- package/src/ts/server/jobs.ts +10 -0
- package/src/ts/server/utils/BackwardCompat.ts +530 -529
- package/src/ts/types.ts +20 -17
|
@@ -16,7 +16,7 @@
|
|
|
16
16
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
17
17
|
*/
|
|
18
18
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
19
|
-
exports.killJob = exports.jobError = exports.jobSuccess = exports.getJob = exports.startJob = void 0;
|
|
19
|
+
exports.jobManager = exports.killJob = exports.jobError = exports.jobSuccess = exports.getJob = exports.startJob = void 0;
|
|
20
20
|
const types_1 = require("../types");
|
|
21
21
|
// Delay after which the job is deleted from memory
|
|
22
22
|
const TIME_TO_KEEP_AFTER_STOP = 60 * 10 * 1000; // 10 min
|
|
@@ -72,4 +72,6 @@ function end(id, status, message = '') {
|
|
|
72
72
|
}
|
|
73
73
|
return false;
|
|
74
74
|
}
|
|
75
|
+
// Export the job manager
|
|
76
|
+
exports.jobManager = { startJob, jobSuccess, jobError };
|
|
75
77
|
//# sourceMappingURL=jobs.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"jobs.js","sourceRoot":"","sources":["../../../../src/ts/server/jobs.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;;;;;GAeG;;;AAEH,oCAAoD;AAEpD,mDAAmD;AACnD,MAAM,uBAAuB,GAAG,EAAE,GAAC,EAAE,GAAC,IAAI,CAAA,CAAC,SAAS;AAEpD,2BAA2B;AAC3B,MAAM,IAAI,GAAG,IAAI,KAAK,EAAW,CAAA;AAEjC,0CAA0C;AAC1C,MAAM,UAAU,GAAG,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,GAAG,OAAO,CAAC,CAAA;AAErD,2BAA2B;AAC3B,IAAI,SAAS,GAAG,CAAC,CAAA;AAEjB,mBAAmB;AACnB,SAAgB,QAAQ,CAAC,OAAO,GAAG,EAAE;IACnC,MAAM,KAAK,GAAG,GAAG,UAAU,IAAI,EAAE,SAAS,EAAE,CAAA;IAC5C,MAAM,GAAG,GAAY;QACnB,KAAK;QACL,MAAM,EAAE,iBAAS,CAAC,WAAW;QAC7B,OAAO,EAAE,OAAO;KACjB,CAAA;IACD,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,CAAA;IACd,OAAO,GAAG,CAAA;AACZ,CAAC;AATD,4BASC;AAED,6BAA6B;AAC7B,SAAgB,MAAM,CAAC,EAAS;IAC9B,OAAO,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,KAAK,KAAK,EAAE,CAAC,CAAA;AAC3C,CAAC;AAFD,wBAEC;AAGD,2BAA2B;AAC3B,SAAgB,UAAU,CAAC,EAAS,EAAE,OAAO,GAAG,EAAE;IAChD,OAAO,GAAG,CAAC,EAAE,EAAE,iBAAS,CAAC,OAAO,EAAE,OAAO,CAAC,CAAA;AAC5C,CAAC;AAFD,gCAEC;AAED,yBAAyB;AACzB,SAAgB,QAAQ,CAAC,EAAS,EAAE,OAAO,GAAG,EAAE;IAC9C,OAAO,GAAG,CAAC,EAAE,EAAE,iBAAS,CAAC,KAAK,EAAE,OAAO,CAAC,CAAA;AAC1C,CAAC;AAFD,4BAEC;AAED,2BAA2B;AAC3B,sDAAsD;AACtD,SAAgB,OAAO,CAAC,GAAY;IAClC,YAAY,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAA;IAC1B,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,GAAG,CAAC,KAAK,KAAK,CAAC,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC,CAAA;AAC5D,CAAC;AAHD,0BAGC;AAED,cAAc;AACd,SAAS,GAAG,CAAC,EAAS,EAAE,MAAiB,EAAE,OAAO,GAAG,EAAE;IACrD,MAAM,GAAG,GAAG,MAAM,CAAC,EAAE,CAAC,CAAA;IACtB,IAAG,GAAG,EAAE;QACN,GAAG,CAAC,MAAM,GAAG,MAAM,CAAA;QACnB,IAAG,OAAO;YAAE,GAAG,CAAC,OAAO,GAAG,OAAO,CAAA;QACjC,GAAG,CAAC,QAAQ,GAAG,UAAU,CAAC,GAAG,EAAE,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE,uBAAuB,CAAC,CAAA;QACtE,OAAO,IAAI,CAAA;KACZ;IACD,OAAO,KAAK,CAAA;AACd,CAAC"}
|
|
1
|
+
{"version":3,"file":"jobs.js","sourceRoot":"","sources":["../../../../src/ts/server/jobs.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;;;;;GAeG;;;AAEH,oCAAoD;AAEpD,mDAAmD;AACnD,MAAM,uBAAuB,GAAG,EAAE,GAAC,EAAE,GAAC,IAAI,CAAA,CAAC,SAAS;AAEpD,2BAA2B;AAC3B,MAAM,IAAI,GAAG,IAAI,KAAK,EAAW,CAAA;AAEjC,0CAA0C;AAC1C,MAAM,UAAU,GAAG,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,GAAG,OAAO,CAAC,CAAA;AAErD,2BAA2B;AAC3B,IAAI,SAAS,GAAG,CAAC,CAAA;AAEjB,mBAAmB;AACnB,SAAgB,QAAQ,CAAC,OAAO,GAAG,EAAE;IACnC,MAAM,KAAK,GAAG,GAAG,UAAU,IAAI,EAAE,SAAS,EAAE,CAAA;IAC5C,MAAM,GAAG,GAAY;QACnB,KAAK;QACL,MAAM,EAAE,iBAAS,CAAC,WAAW;QAC7B,OAAO,EAAE,OAAO;KACjB,CAAA;IACD,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,CAAA;IACd,OAAO,GAAG,CAAA;AACZ,CAAC;AATD,4BASC;AAED,6BAA6B;AAC7B,SAAgB,MAAM,CAAC,EAAS;IAC9B,OAAO,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,KAAK,KAAK,EAAE,CAAC,CAAA;AAC3C,CAAC;AAFD,wBAEC;AAGD,2BAA2B;AAC3B,SAAgB,UAAU,CAAC,EAAS,EAAE,OAAO,GAAG,EAAE;IAChD,OAAO,GAAG,CAAC,EAAE,EAAE,iBAAS,CAAC,OAAO,EAAE,OAAO,CAAC,CAAA;AAC5C,CAAC;AAFD,gCAEC;AAED,yBAAyB;AACzB,SAAgB,QAAQ,CAAC,EAAS,EAAE,OAAO,GAAG,EAAE;IAC9C,OAAO,GAAG,CAAC,EAAE,EAAE,iBAAS,CAAC,KAAK,EAAE,OAAO,CAAC,CAAA;AAC1C,CAAC;AAFD,4BAEC;AAED,2BAA2B;AAC3B,sDAAsD;AACtD,SAAgB,OAAO,CAAC,GAAY;IAClC,YAAY,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAA;IAC1B,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,GAAG,CAAC,KAAK,KAAK,CAAC,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC,CAAA;AAC5D,CAAC;AAHD,0BAGC;AAED,cAAc;AACd,SAAS,GAAG,CAAC,EAAS,EAAE,MAAiB,EAAE,OAAO,GAAG,EAAE;IACrD,MAAM,GAAG,GAAG,MAAM,CAAC,EAAE,CAAC,CAAA;IACtB,IAAG,GAAG,EAAE;QACN,GAAG,CAAC,MAAM,GAAG,MAAM,CAAA;QACnB,IAAG,OAAO;YAAE,GAAG,CAAC,OAAO,GAAG,OAAO,CAAA;QACjC,GAAG,CAAC,QAAQ,GAAG,UAAU,CAAC,GAAG,EAAE,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE,uBAAuB,CAAC,CAAA;QACtE,OAAO,IAAI,CAAA;KACZ;IACD,OAAO,KAAK,CAAA;AACd,CAAC;AASD,yBAAyB;AACZ,QAAA,UAAU,GAAe,EAAE,QAAQ,EAAE,UAAU,EAAE,QAAQ,EAAE,CAAA"}
|
|
@@ -5,7 +5,6 @@ export interface PublicationSettings {
|
|
|
5
5
|
connector?: ConnectorData;
|
|
6
6
|
options?: ConnectorOptions;
|
|
7
7
|
url?: string;
|
|
8
|
-
autoHomePage?: boolean;
|
|
9
8
|
}
|
|
10
9
|
export interface WebsiteFile {
|
|
11
10
|
html: string;
|
|
@@ -137,7 +136,7 @@ export type ApiConnectorUserQuery = {
|
|
|
137
136
|
export type ApiConnectorUserResponse = ConnectorUser;
|
|
138
137
|
export declare const defaultWebsiteData: WebsiteData;
|
|
139
138
|
export interface WebsiteData {
|
|
140
|
-
pages:
|
|
139
|
+
pages: any[];
|
|
141
140
|
assets: Asset[];
|
|
142
141
|
styles: Style[];
|
|
143
142
|
settings: WebsiteSettings;
|
|
@@ -146,7 +145,7 @@ export interface WebsiteData {
|
|
|
146
145
|
publication: PublicationSettings;
|
|
147
146
|
}
|
|
148
147
|
export interface PublicationData extends WebsiteData {
|
|
149
|
-
files?:
|
|
148
|
+
files?: ClientSideFile[];
|
|
150
149
|
}
|
|
151
150
|
export interface WebsiteSettings {
|
|
152
151
|
description?: string;
|
|
@@ -163,16 +162,6 @@ export interface Font {
|
|
|
163
162
|
value: string;
|
|
164
163
|
variants: string[];
|
|
165
164
|
}
|
|
166
|
-
export interface Page {
|
|
167
|
-
name?: string;
|
|
168
|
-
id: string;
|
|
169
|
-
type?: string;
|
|
170
|
-
frames: Frame[];
|
|
171
|
-
settings?: WebsiteSettings;
|
|
172
|
-
cssExt?: string;
|
|
173
|
-
htmlExt?: string;
|
|
174
|
-
slug?: string;
|
|
175
|
-
}
|
|
176
165
|
export interface Frame {
|
|
177
166
|
component: {
|
|
178
167
|
type: string;
|
|
@@ -216,13 +205,26 @@ export type Selector = string | {
|
|
|
216
205
|
export type ConnectorId = string;
|
|
217
206
|
export type ConnectorOptions = object;
|
|
218
207
|
/**
|
|
219
|
-
* Type for a client side file
|
|
220
|
-
* @see connector/File
|
|
208
|
+
* Type for a client side file when the content is available as a string
|
|
221
209
|
*/
|
|
222
|
-
export interface
|
|
210
|
+
export interface ClientSideFileWithContent {
|
|
223
211
|
path: string;
|
|
224
212
|
content: string;
|
|
213
|
+
type: 'html' | 'asset' | 'css';
|
|
214
|
+
}
|
|
215
|
+
/**
|
|
216
|
+
* Type for a client side file when the content is in the storage connector
|
|
217
|
+
*/
|
|
218
|
+
export interface ClientSideFileWithSrc {
|
|
219
|
+
path: string;
|
|
220
|
+
src: string;
|
|
221
|
+
type: 'html' | 'asset' | 'css';
|
|
225
222
|
}
|
|
223
|
+
/**
|
|
224
|
+
* Type for a client side file
|
|
225
|
+
* @see connector/File
|
|
226
|
+
*/
|
|
227
|
+
export type ClientSideFile = ClientSideFileWithContent | ClientSideFileWithSrc;
|
|
226
228
|
/**
|
|
227
229
|
* Type for file listing
|
|
228
230
|
*/
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../../src/ts/types.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;;;;;GAeG;;;
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../../src/ts/types.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;;;;;GAeG;;;AAoBH,MAAa,QAAS,SAAQ,KAAK;IACY;IAA7C,YAAY,OAAe,EAAkB,cAAsB;QACjE,KAAK,CAAC,OAAO,CAAC,CAAA;QAD6B,mBAAc,GAAd,cAAc,CAAQ;QAEjE,OAAO,CAAC,IAAI,CAAC,WAAW,EAAE,cAAc,EAAE,OAAO,CAAC,CAAA;IACpD,CAAC;CACF;AALD,4BAKC;AA+CD,KAAK;AACL,cAAc;AACD,QAAA,kBAAkB,GAAgB;AAC7C,YAAY;AACZ,aAAa;AACb,aAAa;AACb,eAAe;AACf,YAAY;AACZ,cAAc;AACd,kBAAkB;CACJ,CAAA;AA8ChB,IAAY,IAEX;AAFD,WAAY,IAAI;IACd,iBAAS,CAAA;AACX,CAAC,EAFW,IAAI,oBAAJ,IAAI,QAEf;AAmED;;GAEG;AACH,IAAY,aAGX;AAHD,WAAY,aAAa;IACvB,oCAAmB,CAAA;IACnB,oCAAmB,CAAA;AACrB,CAAC,EAHW,aAAa,6BAAb,aAAa,QAGxB;AAuDD;;GAEG;AACH,IAAY,SAIX;AAJD,WAAY,SAAS;IACnB,wCAA2B,CAAA;IAC3B,gCAAmB,CAAA;IACnB,4BAAe,CAAA;AACjB,CAAC,EAJW,SAAS,yBAAT,SAAS,QAIpB"}
|
|
@@ -3,11 +3,11 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.getStorageConnector = exports.getHostingConnector = exports.PublicationError = void 0;
|
|
4
4
|
const express_1 = require("express");
|
|
5
5
|
const constants_1 = require("../../constants");
|
|
6
|
-
const jobs_1 = require("../jobs");
|
|
7
6
|
const types_1 = require("../../types");
|
|
8
7
|
const connectors_1 = require("../connectors/connectors");
|
|
9
8
|
const validation_1 = require("../utils/validation");
|
|
10
9
|
const events_1 = require("../events");
|
|
10
|
+
const jobs_1 = require("../jobs");
|
|
11
11
|
class PublicationError extends Error {
|
|
12
12
|
code;
|
|
13
13
|
constructor(message, code) {
|
|
@@ -66,35 +66,29 @@ function default_1(config) {
|
|
|
66
66
|
const hostingId = (0, validation_1.requiredParam)(query.hostingId, 'hostingId in query');
|
|
67
67
|
const session = (0, validation_1.requiredParam)(req['session'], 'session on express request');
|
|
68
68
|
const data = body;
|
|
69
|
-
const { files
|
|
70
|
-
if (!files
|
|
71
|
-
throw new PublicationError('Missing
|
|
69
|
+
const { files } = data;
|
|
70
|
+
if (!files) {
|
|
71
|
+
throw new PublicationError('Missing files in body', 400);
|
|
72
72
|
}
|
|
73
73
|
config.emit(events_1.ServerEvent.PUBLISH_START, data);
|
|
74
74
|
const hostingConnector = await getHostingConnector(session, config, hostingId);
|
|
75
75
|
const storage = await getStorageConnector(session, config, storageId);
|
|
76
|
-
const
|
|
77
|
-
if (!asset.path)
|
|
78
|
-
throw new PublicationError('Missing path in asset', 400);
|
|
79
|
-
if (!asset.src)
|
|
80
|
-
throw new PublicationError('Missing src in asset', 400);
|
|
76
|
+
const filesList = await Promise.all(files.map(async (file) => {
|
|
81
77
|
const prefix = constants_1.API_WEBSITE_ASSET_READ.replace(/^\//, '');
|
|
82
|
-
const
|
|
78
|
+
const fileWithContent = file;
|
|
79
|
+
const fileWithSrc = file;
|
|
80
|
+
if (!fileWithContent.content && !fileWithSrc.src)
|
|
81
|
+
throw new PublicationError('Missing content or src in file', 400);
|
|
82
|
+
const src = fileWithSrc.src?.startsWith(prefix) ? fileWithSrc.src.substring(prefix.length) : fileWithSrc.src;
|
|
83
83
|
return {
|
|
84
|
-
path:
|
|
85
|
-
content:
|
|
84
|
+
path: file.path,
|
|
85
|
+
content: fileWithContent.content ??
|
|
86
|
+
await storage.readAsset(session, websiteId, src),
|
|
86
87
|
};
|
|
87
88
|
}));
|
|
88
|
-
const filesList = files.flatMap(file => ([{
|
|
89
|
-
path: file.htmlPath,
|
|
90
|
-
content: file.html,
|
|
91
|
-
}, {
|
|
92
|
-
path: file.cssPath,
|
|
93
|
-
content: file.css,
|
|
94
|
-
}])).concat(assetsFiles);
|
|
95
89
|
res.json({
|
|
96
90
|
url: await hostingConnector.getUrl(session, websiteId),
|
|
97
|
-
job: await hostingConnector.publish(session, websiteId, filesList),
|
|
91
|
+
job: await hostingConnector.publish(session, websiteId, filesList, jobs_1.jobManager),
|
|
98
92
|
});
|
|
99
93
|
}
|
|
100
94
|
catch (err) {
|
|
@@ -2,7 +2,6 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.FsHosting = void 0;
|
|
4
4
|
const path_1 = require("path");
|
|
5
|
-
const jobs_1 = require("../jobs");
|
|
6
5
|
const FsStorage_1 = require("./FsStorage");
|
|
7
6
|
const types_1 = require("../../types");
|
|
8
7
|
class FsHosting extends FsStorage_1.FsStorage {
|
|
@@ -10,8 +9,8 @@ class FsHosting extends FsStorage_1.FsStorage {
|
|
|
10
9
|
displayName = 'File system hosting';
|
|
11
10
|
icon = 'data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20viewBox%3D%220%200%2024%2024%22%20fill%3D%22none%22%20stroke%3D%22currentColor%22%20stroke-width%3D%222%22%20stroke-linecap%3D%22round%22%20stroke-linejoin%3D%22round%22%3E%3Cpath%20d%3D%22M6%202L6%2022%2018%2022%2018%207%2012%202%206%202Z%22%3E%3C%2Fpath%3E%3Cpath%20d%3D%22M18%202L12%202%2012%208%2018%208%2018%202Z%22%3E%3C%2Fpath%3E%3C%2Fsvg%3E';
|
|
12
11
|
connectorType = types_1.ConnectorType.HOSTING;
|
|
13
|
-
async publish(session, id, files) {
|
|
14
|
-
const job =
|
|
12
|
+
async publish(session, id, files, { startJob, jobSuccess, jobError }) {
|
|
13
|
+
const job = startJob(`Publishing to ${this.displayName}`);
|
|
15
14
|
job.logs = [[`Publishing to ${this.displayName}`]];
|
|
16
15
|
job.errors = [[]];
|
|
17
16
|
this.writeAssets(session, id, files, async ({ status, message }) => {
|
|
@@ -19,11 +18,11 @@ class FsHosting extends FsStorage_1.FsStorage {
|
|
|
19
18
|
job.message = message;
|
|
20
19
|
job.logs[0].push(message);
|
|
21
20
|
if (status === types_1.JobStatus.SUCCESS) {
|
|
22
|
-
|
|
21
|
+
jobSuccess(job.jobId, message);
|
|
23
22
|
}
|
|
24
23
|
else if (status === types_1.JobStatus.ERROR) {
|
|
25
24
|
job.errors[0].push(message);
|
|
26
|
-
|
|
25
|
+
jobError(job.jobId, message);
|
|
27
26
|
}
|
|
28
27
|
});
|
|
29
28
|
return job;
|
|
@@ -163,6 +163,7 @@ class FsStorage {
|
|
|
163
163
|
let error = null;
|
|
164
164
|
for (const fileStatus of filesStatuses) {
|
|
165
165
|
const { file } = fileStatus;
|
|
166
|
+
console.log('writeAssets', file, this.options.path, id, this.options.assetsFolder, file.path);
|
|
166
167
|
const path = (0, path_1.join)(this.options.path, id, this.options.assetsFolder, file.path);
|
|
167
168
|
if (typeof file.content === 'string' || Buffer.isBuffer(file.content)) {
|
|
168
169
|
fileStatus.message = 'Writing';
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.killJob = exports.jobError = exports.jobSuccess = exports.getJob = exports.startJob = void 0;
|
|
3
|
+
exports.jobManager = exports.killJob = exports.jobError = exports.jobSuccess = exports.getJob = exports.startJob = void 0;
|
|
4
4
|
const types_1 = require("../types");
|
|
5
5
|
const TIME_TO_KEEP_AFTER_STOP = 60 * 10 * 1000;
|
|
6
6
|
const jobs = new Array();
|
|
@@ -45,3 +45,4 @@ function end(id, status, message = '') {
|
|
|
45
45
|
}
|
|
46
46
|
return false;
|
|
47
47
|
}
|
|
48
|
+
exports.jobManager = { startJob, jobSuccess, jobError };
|
package/package.json
CHANGED
package/public/silex.js
CHANGED
|
@@ -44,4 +44,27 @@ export default async function (config) {
|
|
|
44
44
|
// },
|
|
45
45
|
// },
|
|
46
46
|
// }
|
|
47
|
+
config.addPublicationTransformers({
|
|
48
|
+
// Override how components render at publication by grapesjs
|
|
49
|
+
renderComponent(component, initialHtml) {
|
|
50
|
+
return initialHtml
|
|
51
|
+
},
|
|
52
|
+
// Override how styles render at publication by grapesjs
|
|
53
|
+
renderCssRule(rule, initialCss) {
|
|
54
|
+
return initialCss
|
|
55
|
+
},
|
|
56
|
+
// Define how pages are named
|
|
57
|
+
pageToSlug(page) {
|
|
58
|
+
return page.get('slug') ?? page.get('name') ?? 'index'
|
|
59
|
+
},
|
|
60
|
+
// Transform files after they are rendered and before they are published
|
|
61
|
+
transformFile(file) {
|
|
62
|
+
//return {
|
|
63
|
+
// ...file,
|
|
64
|
+
// content: 'TRANSFORMED FILE',
|
|
65
|
+
// src: undefined,
|
|
66
|
+
//}
|
|
67
|
+
return file
|
|
68
|
+
}
|
|
69
|
+
})
|
|
47
70
|
}
|
|
@@ -6,7 +6,10 @@
|
|
|
6
6
|
justify-content: center;
|
|
7
7
|
margin-left: 10px;
|
|
8
8
|
margin-right: 10px;
|
|
9
|
-
|
|
9
|
+
padding-top: 5px;
|
|
10
|
+
padding-left: 10px;
|
|
11
|
+
padding-right: 10px;
|
|
12
|
+
line-height: 1;
|
|
10
13
|
min-width: 100px;
|
|
11
14
|
border: 1px solid $lighterPrimaryColor;
|
|
12
15
|
background-color: $darkerPrimaryColor;
|
package/src/ts/client/config.ts
CHANGED
|
@@ -16,10 +16,11 @@
|
|
|
16
16
|
*/
|
|
17
17
|
|
|
18
18
|
import { Config } from '@silexlabs/silex-plugins'
|
|
19
|
-
import { getEditorConfig } from './grapesjs'
|
|
19
|
+
import { getEditor, getEditorConfig } from './grapesjs'
|
|
20
20
|
import { CLIENT_CONFIG_FILE_NAME, DEFAULT_LANGUAGE, DEFAULT_WEBSITE_ID } from '../constants'
|
|
21
21
|
import { ConnectorId, WebsiteId } from '../types'
|
|
22
|
-
import { EditorConfig } from 'grapesjs'
|
|
22
|
+
import { Editor, EditorConfig, Page } from 'grapesjs'
|
|
23
|
+
import { PublicationTransformer } from './publication-transformers'
|
|
23
24
|
import * as api from './api'
|
|
24
25
|
|
|
25
26
|
/**
|
|
@@ -73,4 +74,23 @@ export class ClientConfig extends Config {
|
|
|
73
74
|
initGrapesConfig() {
|
|
74
75
|
this.grapesJsConfig = getEditorConfig(this.websiteId, this.storageId, this.rootUrl)
|
|
75
76
|
}
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* Get grapesjs editor
|
|
80
|
+
*/
|
|
81
|
+
getEditor(): Editor {
|
|
82
|
+
return getEditor()
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
/**
|
|
86
|
+
* Publication transformers let plugins change files before they are published
|
|
87
|
+
*/
|
|
88
|
+
publicationTransformers: Array<PublicationTransformer> = []
|
|
89
|
+
|
|
90
|
+
/**
|
|
91
|
+
* Add a publication transformer(s)
|
|
92
|
+
*/
|
|
93
|
+
addPublicationTransformers(transformers: PublicationTransformer | PublicationTransformer[]) {
|
|
94
|
+
this.publicationTransformers = this.publicationTransformers.concat(transformers)
|
|
95
|
+
}
|
|
76
96
|
}
|
package/src/ts/client/events.ts
CHANGED
|
@@ -16,10 +16,13 @@
|
|
|
16
16
|
*/
|
|
17
17
|
|
|
18
18
|
export enum ClientEvent {
|
|
19
|
+
// Sent on the config object
|
|
19
20
|
STARTUP_START = 'silex:startup:start',
|
|
20
21
|
STARTUP_END = 'silex:startup:end',
|
|
21
22
|
GRAPESJS_START = 'silex:grapesjs:start',
|
|
22
23
|
GRAPESJS_END = 'silex:grapesjs:end',
|
|
24
|
+
|
|
25
|
+
// Sent on the editor object
|
|
23
26
|
PUBLISH_START = 'silex:publish:start',
|
|
24
27
|
PUBLISH_DATA = 'silex:publish:data',
|
|
25
28
|
PUBLISH_END = 'silex:publish:end',
|
|
@@ -16,7 +16,7 @@
|
|
|
16
16
|
*/
|
|
17
17
|
|
|
18
18
|
import { getPageSlug } from '../../page'
|
|
19
|
-
import { ApiConnectorLoggedInPostMessage, ApiConnectorLoginQuery, ApiPublicationPublishBody, ApiPublicationPublishQuery, ApiPublicationPublishResponse, ApiPublicationStatusQuery, ApiPublicationStatusResponse, ConnectorData, ConnectorType, ConnectorUser, JobData, JobStatus, PublicationData, PublicationJobData, PublicationSettings, WebsiteData, WebsiteId, WebsiteSettings } from '../../types'
|
|
19
|
+
import { ApiConnectorLoggedInPostMessage, ApiConnectorLoginQuery, ApiPublicationPublishBody, ApiPublicationPublishQuery, ApiPublicationPublishResponse, ApiPublicationStatusQuery, ApiPublicationStatusResponse, ClientSideFile, ClientSideFileWithContent, ClientSideFileWithSrc, ConnectorData, ConnectorType, ConnectorUser, JobData, JobStatus, PublicationData, PublicationJobData, PublicationSettings, WebsiteData, WebsiteFile, WebsiteId, WebsiteSettings } from '../../types'
|
|
20
20
|
import { Editor, ProjectData } from 'grapesjs'
|
|
21
21
|
import { PublicationUi } from './PublicationUi'
|
|
22
22
|
import { getUser, logout, publicationStatus, publish } from '../api'
|
|
@@ -206,7 +206,22 @@ export class PublicationManager {
|
|
|
206
206
|
const projectData = this.editor.getProjectData() as WebsiteData
|
|
207
207
|
const siteSettings = this.editor.getModel().get('settings') as WebsiteSettings
|
|
208
208
|
// Build the files structure
|
|
209
|
-
const files = await this.
|
|
209
|
+
const files: ClientSideFile[] = (await this.getSiteFiles(siteSettings))
|
|
210
|
+
.flatMap(file => ([{
|
|
211
|
+
path: file.htmlPath,
|
|
212
|
+
content: file.html,
|
|
213
|
+
type: 'html',
|
|
214
|
+
} as ClientSideFile, {
|
|
215
|
+
path: file.cssPath,
|
|
216
|
+
content: file.css,
|
|
217
|
+
type: 'css',
|
|
218
|
+
} as ClientSideFile]))
|
|
219
|
+
.concat(projectData.assets.map(asset => ({
|
|
220
|
+
...asset,
|
|
221
|
+
path: `/${asset.src}`,
|
|
222
|
+
src: asset.src,
|
|
223
|
+
type: 'asset',
|
|
224
|
+
}) as ClientSideFile))
|
|
210
225
|
|
|
211
226
|
// Create the data to send to the server
|
|
212
227
|
const data: PublicationData = {
|
|
@@ -253,13 +268,18 @@ export class PublicationManager {
|
|
|
253
268
|
}
|
|
254
269
|
}
|
|
255
270
|
|
|
256
|
-
async
|
|
271
|
+
async getSiteFiles(siteSettings: WebsiteSettings): Promise<WebsiteFile[]> {
|
|
257
272
|
return this.editor.Pages.getAll().map(page => {
|
|
258
273
|
const pageSettings = page.get('settings') as WebsiteSettings
|
|
259
274
|
function getSetting(name) {
|
|
260
275
|
return (pageSettings || {})[name] || (siteSettings || [])[name] || ''
|
|
261
276
|
}
|
|
262
277
|
const component = page.getMainComponent()
|
|
278
|
+
|
|
279
|
+
|
|
280
|
+
|
|
281
|
+
|
|
282
|
+
|
|
263
283
|
const slug = page.get('slug') || getPageSlug(page.get('name') || page.get('type'))
|
|
264
284
|
return {
|
|
265
285
|
html: `
|
package/src/ts/client/index.ts
CHANGED
|
@@ -24,6 +24,7 @@
|
|
|
24
24
|
import { ClientConfig } from './config'
|
|
25
25
|
import { ClientEvent } from './events'
|
|
26
26
|
import { initEditor, getEditor } from './grapesjs/index'
|
|
27
|
+
import { initPublicationTransformers } from './publication-transformers'
|
|
27
28
|
|
|
28
29
|
// Expose API to calling app as window.silex
|
|
29
30
|
export * from './expose'
|
|
@@ -61,6 +62,9 @@ export async function start(options = {}) {
|
|
|
61
62
|
const editor = getEditor()
|
|
62
63
|
config.emit(ClientEvent.GRAPESJS_END, { editor })
|
|
63
64
|
|
|
65
|
+
// Init publication transformers
|
|
66
|
+
initPublicationTransformers(config)
|
|
67
|
+
|
|
64
68
|
// Init internationalization module
|
|
65
69
|
editor.I18n.setLocale(config.lang)
|
|
66
70
|
|
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
import { jest, expect, describe, it, beforeEach } from '@jest/globals'
|
|
2
|
+
import { Mock } from 'jest-mock'
|
|
3
|
+
import {
|
|
4
|
+
transformComponents,
|
|
5
|
+
transformStyles,
|
|
6
|
+
resetTransformComponents,
|
|
7
|
+
resetTransformStyles,
|
|
8
|
+
PublicationTransformer,
|
|
9
|
+
transformPages,
|
|
10
|
+
resetTransformPages,
|
|
11
|
+
transformFiles
|
|
12
|
+
} from './publication-transformers'
|
|
13
|
+
import { ClientConfig } from './config'
|
|
14
|
+
import GrapesJS, { Component, Editor, ObjectStrings, Page } from 'grapesjs'
|
|
15
|
+
import { ClientSideFile, PublicationData } from '../types'
|
|
16
|
+
|
|
17
|
+
describe('publication-transformers', () => {
|
|
18
|
+
let mockConfig: ClientConfig
|
|
19
|
+
let mockFile: ClientSideFile
|
|
20
|
+
let mockData: PublicationData
|
|
21
|
+
let transformer: PublicationTransformer
|
|
22
|
+
|
|
23
|
+
let editor: Editor
|
|
24
|
+
|
|
25
|
+
beforeEach(() => {
|
|
26
|
+
// Initialize your mocks here
|
|
27
|
+
editor = GrapesJS.init({
|
|
28
|
+
headless: true,
|
|
29
|
+
storageManager: { autoload: false },
|
|
30
|
+
})
|
|
31
|
+
expect(editor).not.toBeUndefined()
|
|
32
|
+
editor.addComponents(`
|
|
33
|
+
<nav class="parent">
|
|
34
|
+
<div class="child">Hello world</div>
|
|
35
|
+
<nav>
|
|
36
|
+
`)
|
|
37
|
+
editor.addStyle(`
|
|
38
|
+
.parent {
|
|
39
|
+
color: red;
|
|
40
|
+
}
|
|
41
|
+
.child {
|
|
42
|
+
color: blue;
|
|
43
|
+
}
|
|
44
|
+
`)
|
|
45
|
+
mockFile = {
|
|
46
|
+
path: 'test path',
|
|
47
|
+
content: 'test content',
|
|
48
|
+
} as ClientSideFile
|
|
49
|
+
mockData = {
|
|
50
|
+
files: [mockFile],
|
|
51
|
+
pages: [{} as Page],
|
|
52
|
+
} as PublicationData
|
|
53
|
+
transformer = {
|
|
54
|
+
renderComponent: jest.fn(),
|
|
55
|
+
renderCssRule: jest.fn(),
|
|
56
|
+
pageToSlug: jest.fn(),
|
|
57
|
+
transformFile: jest.fn()
|
|
58
|
+
} as PublicationTransformer
|
|
59
|
+
mockConfig = { getEditor: jest.fn(() => editor), publicationTransformers: [transformer] } as unknown as ClientConfig
|
|
60
|
+
})
|
|
61
|
+
|
|
62
|
+
it('should transform components', () => {
|
|
63
|
+
const renderComponent = transformer.renderComponent as Mock
|
|
64
|
+
renderComponent.mockReturnValue('mockHtml')
|
|
65
|
+
transformComponents(mockConfig)
|
|
66
|
+
const html = editor.getHtml()
|
|
67
|
+
expect(renderComponent).toBeCalledTimes(6)
|
|
68
|
+
const results = renderComponent.mock.calls.map(call => call[0] as Component)
|
|
69
|
+
const parent = results.find(c => c.getClasses()[0] === 'parent')
|
|
70
|
+
expect(parent).not.toBeUndefined()
|
|
71
|
+
const child = results.find(c => c.getClasses()[0] === 'child')
|
|
72
|
+
expect(child).not.toBeUndefined()
|
|
73
|
+
})
|
|
74
|
+
|
|
75
|
+
it('should reset transformed pages', () => {
|
|
76
|
+
const renderComponent = transformer.renderComponent as Mock
|
|
77
|
+
renderComponent.mockReturnValue('mockHtml')
|
|
78
|
+
transformComponents(mockConfig)
|
|
79
|
+
resetTransformComponents(mockConfig)
|
|
80
|
+
const html = editor.getHtml()
|
|
81
|
+
expect(renderComponent).toBeCalledTimes(0)
|
|
82
|
+
expect(html).toContain('Hello world')
|
|
83
|
+
})
|
|
84
|
+
|
|
85
|
+
it('should transform styles', () => {
|
|
86
|
+
const renderCssRule = transformer.renderCssRule as Mock
|
|
87
|
+
renderCssRule.mockImplementation((rule: any) => {
|
|
88
|
+
return { color: 'test'+rule.attributes.style.color } as ObjectStrings
|
|
89
|
+
})
|
|
90
|
+
transformStyles(mockConfig)
|
|
91
|
+
const css = editor.getCss()
|
|
92
|
+
expect(renderCssRule).toBeCalledTimes(2)
|
|
93
|
+
const results = renderCssRule.mock.results.map(r => r.value as ObjectStrings)
|
|
94
|
+
const parent = results.find(c => c.color === 'testred')
|
|
95
|
+
expect(parent).not.toBeUndefined()
|
|
96
|
+
const child = results.find(c => c.color === 'testblue')
|
|
97
|
+
expect(child).not.toBeUndefined()
|
|
98
|
+
expect(css).toContain('color:test')
|
|
99
|
+
expect(css).not.toContain('color:blue')
|
|
100
|
+
})
|
|
101
|
+
|
|
102
|
+
it('should reset transformed styles', () => {
|
|
103
|
+
const renderCssRule = transformer.renderCssRule as Mock
|
|
104
|
+
const returned = {color: 'test'} as ObjectStrings
|
|
105
|
+
renderCssRule.mockReturnValue(returned)
|
|
106
|
+
transformStyles(mockConfig)
|
|
107
|
+
resetTransformStyles(mockConfig)
|
|
108
|
+
const css = editor.getCss()
|
|
109
|
+
expect(renderCssRule).toBeCalledTimes(0)
|
|
110
|
+
expect(css).toContain('color:blue')
|
|
111
|
+
})
|
|
112
|
+
|
|
113
|
+
it('should transform pages', () => {
|
|
114
|
+
const PAGE_SLUG = 'test page slug'
|
|
115
|
+
const pageToSlug = transformer.pageToSlug as Mock
|
|
116
|
+
pageToSlug.mockReturnValue(PAGE_SLUG)
|
|
117
|
+
transformPages(mockConfig)
|
|
118
|
+
const pages = editor.Pages.getAll()
|
|
119
|
+
expect(pageToSlug).toBeCalledTimes(1)
|
|
120
|
+
expect(pages[0].get('slug')).toBe(PAGE_SLUG)
|
|
121
|
+
})
|
|
122
|
+
|
|
123
|
+
it('should reset transformed components', () => {
|
|
124
|
+
const PAGE_SLUG = 'test page slug'
|
|
125
|
+
const pageToSlug = transformer.pageToSlug as Mock
|
|
126
|
+
pageToSlug.mockReturnValue(PAGE_SLUG)
|
|
127
|
+
transformPages(mockConfig)
|
|
128
|
+
resetTransformPages(mockConfig)
|
|
129
|
+
const pages = editor.Pages.getAll()
|
|
130
|
+
expect(pageToSlug).toBeCalledTimes(1)
|
|
131
|
+
expect(pages[0].get('slug')).not.toBe(PAGE_SLUG)
|
|
132
|
+
})
|
|
133
|
+
|
|
134
|
+
it('should transform files', () => {
|
|
135
|
+
const transformFile = transformer.transformFile as Mock
|
|
136
|
+
const returned = {path: 'test path changed', content: 'test content changed'} as ClientSideFile
|
|
137
|
+
transformFile.mockReturnValue(returned)
|
|
138
|
+
expect(mockData.files?.length).toBe(1)
|
|
139
|
+
if (mockData.files?.length) { // To avoid ! operator on mockData.files and make the lint happy
|
|
140
|
+
expect(mockData.files[0]).toBe(mockFile)
|
|
141
|
+
transformFiles(mockConfig, mockData)
|
|
142
|
+
expect(transformFile).toBeCalledTimes(1)
|
|
143
|
+
expect(mockData.files[0]).toBe(returned)
|
|
144
|
+
}
|
|
145
|
+
})
|
|
146
|
+
})
|