gdcore-tools 1.0.4 → 1.0.5

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.
@@ -1,28 +1,28 @@
1
- const fs = require('fs-extra');
2
- const path = require('path');
3
- const os = require('os');
1
+ const fs = require("fs-extra");
2
+ const path = require("path");
3
+ const os = require("os");
4
4
 
5
- exports.fs = {
6
- mkDir: function(path) {
5
+ module.exports.makeFS = (gd) => ({
6
+ mkDir: function (path) {
7
7
  try {
8
8
  fs.mkdirsSync(path);
9
9
  } catch (e) {
10
- console.error('mkDir(' + path + ') failed: ' + e);
10
+ console.error("mkDir(" + path + ") failed: " + e);
11
11
  return false;
12
12
  }
13
13
  return true;
14
14
  },
15
- dirExists: function(path) {
15
+ dirExists: function (path) {
16
16
  return fs.existsSync(path);
17
17
  },
18
- clearDir: function(path) {
18
+ clearDir: function (path) {
19
19
  var files = [];
20
20
  var that = this;
21
21
  try {
22
22
  if (fs.existsSync(path)) {
23
23
  files = fs.readdirSync(path);
24
- files.forEach(function(file) {
25
- var curPath = path + '/' + file;
24
+ files.forEach(function (file) {
25
+ var curPath = path + "/" + file;
26
26
  if (fs.lstatSync(curPath).isDirectory()) {
27
27
  // recurse
28
28
  that.clearDir(curPath);
@@ -31,31 +31,31 @@ exports.fs = {
31
31
  try {
32
32
  fs.unlinkSync(curPath);
33
33
  } catch (e) {
34
- console.error('fs.unlinkSync(' + curPath + ') failed: ' + e);
34
+ console.error("fs.unlinkSync(" + curPath + ") failed: " + e);
35
35
  }
36
36
  }
37
37
  });
38
38
  }
39
39
  } catch (e) {
40
- console.error('clearDir(' + path + ') failed: ' + e);
40
+ console.error("clearDir(" + path + ") failed: " + e);
41
41
  }
42
42
  },
43
- getTempDir: function() {
43
+ getTempDir: function () {
44
44
  return os.tmpdir();
45
45
  },
46
- fileNameFrom: function(fullpath) {
46
+ fileNameFrom: function (fullpath) {
47
47
  if (this._isExternalURL(fullpath)) return fullpath;
48
48
 
49
49
  fullpath = this._translateURL(fullpath);
50
50
  return path.basename(fullpath);
51
51
  },
52
- dirNameFrom: function(fullpath) {
53
- if (this._isExternalURL(fullpath)) return '';
52
+ dirNameFrom: function (fullpath) {
53
+ if (this._isExternalURL(fullpath)) return "";
54
54
 
55
55
  fullpath = this._translateURL(fullpath);
56
56
  return path.dirname(fullpath);
57
57
  },
58
- makeAbsolute: function(filename, baseDirectory) {
58
+ makeAbsolute: function (filename, baseDirectory) {
59
59
  if (this._isExternalURL(filename)) return filename;
60
60
 
61
61
  filename = this._translateURL(filename);
@@ -64,23 +64,23 @@ exports.fs = {
64
64
 
65
65
  return path.resolve(baseDirectory, path.normalize(filename));
66
66
  },
67
- makeRelative: function(filename, baseDirectory) {
67
+ makeRelative: function (filename, baseDirectory) {
68
68
  if (this._isExternalURL(filename)) return filename;
69
69
 
70
70
  filename = this._translateURL(filename);
71
71
  return path.relative(baseDirectory, path.normalize(filename));
72
72
  },
73
- isAbsolute: function(fullpath) {
73
+ isAbsolute: function (fullpath) {
74
74
  if (this._isExternalURL(fullpath)) return true;
75
75
 
76
76
  if (fullpath.length === 0) return true;
77
77
  fullpath = this._translateURL(fullpath);
78
78
  return (
79
- (fullpath.length > 0 && fullpath.charAt(0) === '/') ||
80
- (fullpath.length > 1 && fullpath.charAt(1) === ':')
79
+ (fullpath.length > 0 && fullpath.charAt(0) === "/") ||
80
+ (fullpath.length > 1 && fullpath.charAt(1) === ":")
81
81
  );
82
82
  },
83
- copyFile: function(source, dest) {
83
+ copyFile: function (source, dest) {
84
84
  //URL are not copied.
85
85
  if (this._isExternalURL(source)) return true;
86
86
 
@@ -88,52 +88,52 @@ exports.fs = {
88
88
  try {
89
89
  if (source !== dest) fs.copySync(source, dest);
90
90
  } catch (e) {
91
- console.error('copyFile(' + source + ', ' + dest + ') failed: ' + e);
91
+ console.error("copyFile(" + source + ", " + dest + ") failed: " + e);
92
92
  return false;
93
93
  }
94
94
  return true;
95
95
  },
96
- writeToFile: function(file, contents) {
96
+ writeToFile: function (file, contents) {
97
97
  try {
98
98
  fs.outputFileSync(file, contents);
99
99
  } catch (e) {
100
- console.error('writeToFile(' + file + ', ...) failed: ' + e);
100
+ console.error("writeToFile(" + file + ", ...) failed: " + e);
101
101
  return false;
102
102
  }
103
103
  return true;
104
104
  },
105
- readFile: function(file) {
105
+ readFile: function (file) {
106
106
  try {
107
107
  var contents = fs.readFileSync(file);
108
108
  return contents.toString();
109
109
  } catch (e) {
110
- console.error('readFile(' + file + ') failed: ' + e);
111
- return '';
110
+ console.error("readFile(" + file + ") failed: " + e);
111
+ return "";
112
112
  }
113
113
  },
114
- readDir: function(path, ext) {
114
+ readDir: function (path, ext) {
115
115
  ext = ext.toUpperCase();
116
- var output = new _GD.VectorString();
116
+ var output = new gd.VectorString();
117
117
  try {
118
118
  var files = [];
119
119
  if (fs.existsSync(path)) {
120
120
  files = fs.readdirSync(path);
121
- files.forEach(function(file) {
121
+ files.forEach(function (file) {
122
122
  if (
123
123
  ext.length === 0 ||
124
124
  file.toUpperCase().indexOf(ext, file.length - ext.length) !== -1
125
125
  ) {
126
- output.push_back(path + '/' + file);
126
+ output.push_back(path + "/" + file);
127
127
  }
128
128
  });
129
129
  }
130
130
  } catch (e) {
131
- console.error('readDir(' + path + ',' + ext + ') failed: ' + e);
131
+ console.error("readDir(" + path + "," + ext + ") failed: " + e);
132
132
  }
133
133
 
134
134
  return output;
135
135
  },
136
- fileExists: function(filename) {
136
+ fileExists: function (filename) {
137
137
  filename = this._translateURL(filename);
138
138
  try {
139
139
  const stat = fs.statSync(filename);
@@ -142,17 +142,17 @@ exports.fs = {
142
142
  return false;
143
143
  }
144
144
  },
145
- _isExternalURL: function(filename) {
146
- return filename.substr(0, 4) === 'http' || filename.substr(0, 4) === 'ftp';
145
+ _isExternalURL: function (filename) {
146
+ return filename.substr(0, 4) === "http" || filename.substr(0, 4) === "ftp";
147
147
  },
148
148
  /**
149
149
  * Return the filename associated to the URL on the server, relative to the games directory.
150
150
  * (i.e: Transform g/mydirectory/myfile.png to mydirectory/myfile.png).
151
151
  */
152
- _translateURL: function(filename) {
153
- if (filename.substr(0, 2) === 'g/' || filename.substr(0, 2) === 'g\\')
152
+ _translateURL: function (filename) {
153
+ if (filename.substr(0, 2) === "g/" || filename.substr(0, 2) === "g\\")
154
154
  filename = filename.substr(2);
155
155
 
156
156
  return filename;
157
157
  },
158
- };
158
+ });
@@ -0,0 +1,138 @@
1
+ const EventEmitter = require("events");
2
+ const loadExtensions = require("./JsExtensionsLoader/LocalJsExtensionsLoader");
3
+ const projectLoader = require("./LocalProjectOpener");
4
+ const { makeLoader } = require("./EventsFunctionsExtensionsLoader/index");
5
+ const {
6
+ makeLocalEventsFunctionCodeWriter,
7
+ } = require("./EventsFunctionsExtensionsLoader/LocalEventsFunctionCodeWriter");
8
+ const saveProject = require("./LocalProjectWriter");
9
+ const assignIn = require("lodash/assignIn");
10
+ const { getGD, getRuntimePath } = require("./downloadGD");
11
+ const { join, resolve } = require("path");
12
+ const { makeFS } = require("./LocalFileSystem");
13
+
14
+ class WrappedGD extends EventEmitter {
15
+ constructor(version) {
16
+ super();
17
+
18
+ /**
19
+ * The raw gd namespace.
20
+ */
21
+ this.gd = null;
22
+
23
+ /**
24
+ * The GDevelop abstract file system.
25
+ * @private
26
+ */
27
+ this.fs = null;
28
+
29
+ /**
30
+ * The Events Functions loader
31
+ * @private
32
+ */
33
+ this.eventsFunctionsLoader = null;
34
+
35
+ /**
36
+ * The Events Functions loader.
37
+ * @private
38
+ */
39
+ this.eventsFunctionsWriter = makeLocalEventsFunctionCodeWriter();
40
+
41
+ /**
42
+ * The path to the current version.
43
+ * @private
44
+ */
45
+ this.versionPath = getRuntimePath(version);
46
+
47
+ // Begin async loading of GDCore and extensions
48
+ getGD(version, {
49
+ print: (message) => this.emit("print", message),
50
+ printErr: (e) => this.emit("error", e),
51
+ onAbort: (e) => this.emit("error", e),
52
+ })
53
+ .then((gd) => {
54
+ this.gd = gd;
55
+ return loadExtensions(
56
+ gd,
57
+ join(this.versionPath, "Runtime", "Extensions")
58
+ );
59
+ })
60
+ .then(() => {
61
+ this.fs = assignIn(new this.gd.AbstractFileSystemJS(), makeFS(this.gd));
62
+ this.eventsFunctionsLoader = makeLoader(
63
+ this.gd
64
+ ).loadProjectEventsFunctionsExtensions;
65
+ })
66
+ .then(() => this.emit("ready"))
67
+ .catch((e) => this.emit("initError", e));
68
+ }
69
+
70
+ /**
71
+ * Loads a project json file.
72
+ * @param {string} projectLocation The path to the json file
73
+ */
74
+ loadProject(projectLocation) {
75
+ return projectLoader
76
+ .loadProjectFiles(projectLocation)
77
+ .then((projectFile) => {
78
+ projectFile.content.properties.projectFile = projectLocation;
79
+ return projectLoader.loadSerializedProject(
80
+ this.gd,
81
+ projectFile.content
82
+ );
83
+ })
84
+ .then(async (project) => {
85
+ await this.reloadEventsFunctions(project);
86
+ project.setProjectFile(resolve(projectLocation));
87
+ return project;
88
+ });
89
+ }
90
+
91
+ /**
92
+ * Saves a project to a json file.
93
+ * @param {*} project The loaded project
94
+ * @param {string} [fileName] The name of the file to save. Defaults to "game.json".
95
+ * @param {string} [pathName] The path to save to. Defaults to "./".
96
+ */
97
+ saveProject(project, fileName, pathName) {
98
+ pathName = pathName || "./";
99
+ fileName = join(pathName, fileName || "game.json");
100
+ return saveProject(this.gd, project, fileName, pathName);
101
+ }
102
+
103
+ /**
104
+ * Exports a project.
105
+ * @param {*} project The loaded project.
106
+ * @param {string} outputDir The output directory.
107
+ * @param {Object<string>} options Options to pass to the exporter.
108
+ */
109
+ exportProject(project, outputDir, options) {
110
+ const gd = this.gd;
111
+ const exporter = new gd.Exporter(this.fs, this.versionPath);
112
+ const exportOptions = new gd.MapStringBoolean();
113
+ for (let key in options) {
114
+ exportOptions.set(key, options[key]);
115
+ }
116
+ exporter.exportWholePixiProject(project, outputDir, exportOptions);
117
+ exportOptions.delete();
118
+ exporter.delete();
119
+ }
120
+
121
+ /**
122
+ * Reload and generate events based extensions in a project.
123
+ * @param {*} project
124
+ */
125
+ reloadEventsFunctions(project) {
126
+ return this.eventsFunctionsLoader(project, this.eventsFunctionsWriter);
127
+ }
128
+
129
+ /**
130
+ * Returns the path to the runtime files.
131
+ * @returns {string}
132
+ */
133
+ getRuntimePath() {
134
+ return join(this.versionPath, "Runtime");
135
+ }
136
+ }
137
+
138
+ module.exports = WrappedGD;
package/src/downloadGD.js CHANGED
@@ -1,12 +1,13 @@
1
1
  const fs = require("fs-extra-promise");
2
2
  const path = require("path");
3
3
  const { request } = require("@octokit/request");
4
+ const { https } = require("follow-redirects");
4
5
 
5
6
  const getRuntimePath = (version) => path.join(__dirname, "Versions", version);
6
7
 
7
8
  const downloadFile = (file, savePath, required = true) =>
8
9
  new Promise((resolve) => {
9
- require("follow-redirects").https.get(file, function (response) {
10
+ https.get(file, function (response) {
10
11
  if (response.statusCode !== 200) {
11
12
  if (required)
12
13
  throw new Error(
@@ -65,11 +66,25 @@ const downloadVersion = async function (versionTag) {
65
66
  .then(() => fs.removeAsync(gdPath))
66
67
  .finally(() => fs.mkdirAsync(gdPath));
67
68
 
68
- const commitHash = (
69
- await request("GET /repos/4ian/GDevelop/git/ref/tags/{tag}", {
70
- tag: versionTag,
69
+ let commit = (
70
+ await request("GET /repos/4ian/GDevelop/commits/{ref}", {
71
+ ref: (
72
+ await request("GET /repos/4ian/GDevelop/git/ref/tags/{tag}", {
73
+ tag: versionTag,
74
+ })
75
+ ).data.object.sha,
71
76
  })
72
- ).data.object.sha;
77
+ ).data;
78
+
79
+ // Go up to the latest commit for which libGD.js was built
80
+ while (commit.commit.message.indexOf("[skip ci]") !== -1) {
81
+ commit = (
82
+ await request("GET /repos/4ian/GDevelop/commits/{ref}", {
83
+ ref: commit.parents[0].sha,
84
+ })
85
+ ).data;
86
+ console.log(commit.commit.message, commit.parents);
87
+ }
73
88
 
74
89
  // Fetch the file with the GDJS Runtime and extensions
75
90
  console.info(`🕗 Starting download of GDevelop Runtime '${versionTag}'...`);
@@ -88,7 +103,7 @@ const downloadVersion = async function (versionTag) {
88
103
  file: zipPath,
89
104
  storeEntries: true,
90
105
  });
91
- const prefix = `4ian-GDevelop-${commitHash.slice(0, 7)}/`;
106
+ const prefix = `4ian-GDevelop-${commit.sha.slice(0, 7)}/`;
92
107
  return Promise.all([
93
108
  new Promise((resolve) => {
94
109
  zip.on("ready", () => {
@@ -97,7 +112,10 @@ const downloadVersion = async function (versionTag) {
97
112
  path.join(gdPath, "Runtime", "Extensions"),
98
113
  (e) => {
99
114
  if (e)
100
- console.error("❌ Error while extracting the GDevelop Runtime extensions! ", e);
115
+ console.error(
116
+ "❌ Error while extracting the GDevelop Runtime extensions! ",
117
+ e
118
+ );
101
119
  else resolve();
102
120
  }
103
121
  );
@@ -110,7 +128,10 @@ const downloadVersion = async function (versionTag) {
110
128
  path.join(gdPath, "Runtime"),
111
129
  (e) => {
112
130
  if (e)
113
- console.error("❌ Error while extracting the GDevelop Runtime! ", e);
131
+ console.error(
132
+ "❌ Error while extracting the GDevelop Runtime! ",
133
+ e
134
+ );
114
135
  else resolve();
115
136
  }
116
137
  );
@@ -136,14 +157,13 @@ const downloadVersion = async function (versionTag) {
136
157
  // Download the fitting libGD version
137
158
  const libGDPath =
138
159
  "https://s3.amazonaws.com/gdevelop-gdevelop.js/master/commit/" +
139
- commitHash +
160
+ commit.sha +
140
161
  "/";
141
162
  console.info(`🕗 Starting download of GDevelop Core...`);
142
163
  tasks.push(
143
- downloadFile(
144
- libGDPath + "libGD.js",
145
- path.join(gdPath, "libGD.js")
146
- ).then(() => console.info(`✅ Done downloading libGD.js`))
164
+ downloadFile(libGDPath + "libGD.js", path.join(gdPath, "libGD.js")).then(
165
+ () => console.info(`✅ Done downloading libGD.js`)
166
+ )
147
167
  );
148
168
  tasks.push(
149
169
  downloadFile(
@@ -169,16 +189,13 @@ const downloadVersion = async function (versionTag) {
169
189
  );
170
190
  };
171
191
 
172
- const onGDCorePrint = new Set();
173
- const onGDCoreError = new Set();
174
-
175
192
  /**
176
193
  * Initialize libGD.js.
177
194
  * If the version is not present, download it.
178
195
  * Returning `gd` doesn't work, so a hacky workaround with global is used.
179
196
  * @param {string} [versionTag] The GDevelop version to use. If not precised, the latest is used.
180
197
  */
181
- const getGD = async function (versionTag) {
198
+ const getGD = async function (versionTag, gdOptions) {
182
199
  const runtimePath = getRuntimePath(versionTag);
183
200
  // Download the version if it isn't present
184
201
  try {
@@ -188,24 +205,18 @@ const getGD = async function (versionTag) {
188
205
  await downloadVersion(versionTag).catch(console.error);
189
206
  }
190
207
 
191
- return await new Promise((resolve) => {
192
- global._GD = require(path.join(runtimePath, "libGD.js"))({
193
- print: (e) => onGDCorePrint.forEach((callback) => callback(e)),
194
- printErr: (e) => onGDCoreError.forEach((callback) => callback(e)),
195
- onAbort: (e) => onGDCoreError.forEach((callback) => callback(e)),
208
+ const gd = require(path.join(runtimePath, "libGD.js"))(gdOptions);
209
+ return new Promise((resolve) => {
210
+ gd.then(() => {
211
+ // Make sure gd is not thenable as the promise would think it is one as well.
212
+ delete gd.then;
213
+ resolve(gd);
196
214
  });
197
- _GD.then((gd) => resolve());
198
215
  });
199
216
  };
200
217
 
201
- const onGDCoreEvent = (event, handler) => {
202
- if (event === "print") onGDCorePrint.add(handler);
203
- if (event === "error") onGDCoreError.add(handler);
204
- };
205
-
206
218
  module.exports = {
207
219
  getRuntimePath,
208
220
  getGD,
209
221
  findLatestVersion,
210
- onGDCoreEvent,
211
222
  };
package/src/index.js CHANGED
@@ -1,124 +1,16 @@
1
- const loadExtensions = require("./JsExtensionsLoader/LocalJsExtensionsLoader");
2
- const projectLoader = require("./LocalProjectOpener");
3
- const eventsFunctionsLoader = require("./EventsFunctionsExtensionsLoader/index")
4
- .loadProjectEventsFunctionsExtensions;
5
- const eventFunctionsWriter = require("./EventsFunctionsExtensionsLoader/LocalEventsFunctionCodeWriter")
6
- .makeLocalEventsFunctionCodeWriter;
7
- const saveProject = require("./LocalProjectWriter");
8
- const localFileSystem = require("./LocalFileSystem").fs;
9
- const assignIn = require("lodash/assignIn");
10
- const {
11
- getGD,
12
- getRuntimePath,
13
- findLatestVersion,
14
- onGDCoreEvent,
15
- } = require("./downloadGD");
16
- const { join, resolve } = require("path");
17
-
18
- class WrappedGD {
19
- constructor(gd, versionPath) {
20
- /**
21
- * The raw gd namespace.
22
- */
23
- this.gd = gd;
24
-
25
- /**
26
- * The path to the current version.
27
- * @private
28
- */
29
- this.versionPath = versionPath;
30
- }
31
-
32
- /**
33
- * Loads a project json file.
34
- * @param {string} projectLocation The path to the json file
35
- */
36
- loadProject(projectLocation) {
37
- let project;
38
- return projectLoader
39
- .loadProjectFiles(projectLocation)
40
- .then((projectFile) => {
41
- projectFile.content.properties.projectFile = projectLocation;
42
- return projectLoader.loadSerializedProject(
43
- this.gd,
44
- projectFile.content
45
- );
46
- })
47
- .then((projectLoaded) => {
48
- project = projectLoaded;
49
- project.setProjectFile(resolve(projectLocation));
50
- return eventsFunctionsLoader(project, eventFunctionsWriter());
51
- })
52
- .then(() => project);
53
- }
54
-
55
- /**
56
- * Saves a project to a json file.
57
- * @param {*} project The loaded project
58
- * @param {string} [fileName] The name of the file to save. Defaults to "game.json".
59
- * @param {string} [pathName] The path to save to. Defaults to "./".
60
- */
61
- saveProject(project, fileName, pathName) {
62
- pathName = pathName || "./";
63
- fileName = join(pathName, fileName || "game.json");
64
- return saveProject(this.gd, project, fileName, pathName);
65
- }
66
-
67
- /**
68
- * Exports a project.
69
- * @param {*} project The loaded project.
70
- * @param {string} outputDir The output directory.
71
- * @param {Object<string>} options Options to pass to the exporter.
72
- */
73
- exportProject(project, outputDir, options) {
74
- const gd = this.gd;
75
- const fileSystem = assignIn(new gd.AbstractFileSystemJS(), localFileSystem);
76
- const exporter = new gd.Exporter(fileSystem, this.versionPath);
77
- const exportOptions = new gd.MapStringBoolean();
78
- for (let key in options) {
79
- exportOptions.set(key, options[key]);
80
- }
81
- exporter.exportWholePixiProject(project, outputDir, exportOptions);
82
- exportOptions.delete();
83
- exporter.delete();
84
- }
85
-
86
- /**
87
- * Returns the path to the runtime files.
88
- * @returns {string}
89
- */
90
- getRuntimePath() {
91
- return join(this.path, "Runtime");
92
- }
93
-
94
- /**
95
- * Trigger a callback when a certain event happens inside GDCore.
96
- * @param {"print" | "error"} type The event type.
97
- * @param {(message: string) => void} handler The event handler.
98
- */
99
- on(event, handler) {
100
- onGDCoreEvent(event, handler);
101
- }
102
- }
1
+ const { findLatestVersion } = require("./downloadGD");
2
+ const WrappedGD = require("./WrappedGD");
103
3
 
104
4
  const loadGD = async (version) => {
105
- let gd;
106
5
  if (version === undefined) version = await findLatestVersion();
107
- return (
108
- getGD(version)
109
- .then(() => {
110
- gd = global._GD;
111
- })
112
- .then(() => {
113
- return loadExtensions(
114
- gd,
115
- join(getRuntimePath(version), "Runtime", "Extensions")
116
- );
117
- })
118
- .then(() => {
119
- return new WrappedGD(gd, getRuntimePath(version));
120
- })
121
- );
6
+ return new Promise((resolve, reject) => {
7
+ const wgd = new WrappedGD(version);
8
+ wgd.once("ready", () => {
9
+ wgd.removeAllListeners();
10
+ resolve(wgd);
11
+ });
12
+ wgd.once("initError", reject);
13
+ });
122
14
  };
123
15
 
124
16
  module.exports = loadGD;