-
-
Notifications
You must be signed in to change notification settings - Fork 11
/
esbuild.mjs
160 lines (142 loc) · 5.85 KB
/
esbuild.mjs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
import { build } from 'esbuild';
import { sassPlugin } from 'esbuild-sass-plugin'
import fs from 'fs';
import path from 'path';
import { glob } from 'glob';
const resourcesDir = "resources";
const distDir = "dist";
const distLegacyDir = "dist_legacy";
const extensionBanner = `// For GNOME Shell version before 45
class Extension {
constructor(meta) { // meta has type ExtensionMeta
this.metadata = meta.metadata;
this.uuid = meta.uuid;
this.path = meta.path;
}
getSettings() {
return imports.misc.extensionUtils.getSettings();
}
}
class Mtk { Rectangle }
Mtk.Rectangle = function (params = {}) {
return new imports.gi.Meta.Rectangle(params);
};
Mtk.Rectangle.$gtype = imports.gi.Meta.Rectangle.$gtype;
`;
const extensionFooter = `
function init(meta) {
return new TilingShellExtension(meta);
}
`;
const prefsBanner = `// For GNOME Shell version before 45
class ExtensionPreferences {
constructor(metadata) {
this.metadata = metadata;
}
getSettings() {
return imports.misc.extensionUtils.getSettings();
}
}
`;
const prefsFooter = `
function init() {
}
function fillPreferencesWindow(window) {
const metadata = imports.misc.extensionUtils.getCurrentExtension().metadata;
const prefs = new TilingShellExtensionPreferences(metadata);
prefs.fillPreferencesWindow(window);
}
`;
/// Converts imports on the form
/// import { a, b, c } from 'gi://Source'
///
/// to
///
/// const Source = imports.gi;
/// and
/// const { a, b, c } = imports.gi.Source;
/// If the imported module is Mtk, it is aliased with Meta
function convertImports(text) {
// drop import of Extension class
text = text.replaceAll('import { Extension } from "resource:///org/gnome/shell/extensions/extension.js";', "");
// drop import of ExtensionPreferences class
text = text.replaceAll('import { ExtensionPreferences } from "resource:///org/gnome/Shell/Extensions/js/extensions/prefs.js";', "");
const regexExportExtension = new RegExp(`export {((.|\n)*)(.+) as default((.|\n)*)};`, 'gm');
text = text.replaceAll(regexExportExtension, "");
// replace import Source from "gi://Source" with const Source = imports.gi.Source;
const regexGi = new RegExp('import (.+) from \\"gi:\\/\\/(.+)\\"', 'gm');
text = text.replaceAll(regexGi, (match, imported, module) => {
if (module.indexOf("Mtk") >= 0) {
// remove first occurrence of Mtk.
// it will be defined by the extension banner
if (imported === "Mtk") return "";
// alias the imported Mtk with the extension banner's Mtk
return `const ${imported} = Mtk`;
}
return `const ${imported} = imports.gi.${module}`;
});
// replace import * as Source from "resource:///org/gnome/shell/path/to/source.js"; with const Source = imports.path.to.Source;
const regexResource = new RegExp('import \\* as (.+) from \\"resource:\\/\\/\\/org\\/gnome\\/shell\\/(.+)\\.js\\"', 'gm');
text = text.replaceAll(regexResource, (match, imported, module) => `const ${imported} = imports.${module.replace('/', '.')}`);
return text;
}
// build extension
build({
logLevel: "info",
entryPoints: ['src/extension.ts', 'src/prefs.ts'],
outdir: distDir,
bundle: true,
treeShaking: false,
// firefox60 // Since GJS 1.53.90
// firefox68 // Since GJS 1.63.90
// firefox78 // Since GJS 1.65.90
// firefox91 // Since GJS 1.71.1
// firefox102 // Since GJS 1.73.2
target: 'firefox78',
platform: 'node',
format: 'esm',
external: ['gi://*', 'resource://*', 'system', 'gettext', 'cairo', '@girs*'],
plugins: [sassPlugin()]/*,
banner: {
js: banner,
},
footer: {
js: footer
}*/
}).then(() => {
fs.renameSync(path.resolve(distDir, "extension.css"), path.resolve(distDir, "stylesheet.css"));
fs.cpSync(resourcesDir, distDir, { recursive: true });
}).then(async () => {
console.log(" 💡", "Generating legacy version...");
// duplicate the build into distLegacyDir
fs.cpSync(distDir, distLegacyDir, { recursive: true });
// for each js file in distLegacyDir, apply conversion
const files = await glob(`${distLegacyDir}/**/*.js`, {});
for (let file of files) {
let jsFileContent = fs.readFileSync(file).toString();
let convertedContent = convertImports(jsFileContent);
if (file.indexOf("extension.js") >= 0) {
fs.writeFileSync(file, `${extensionBanner}${convertedContent}${extensionFooter}`);
} else if (file.indexOf("prefs.js") >= 0) {
fs.writeFileSync(file, `${prefsBanner}${convertedContent}${prefsFooter}`);
} else {
fs.writeFileSync(file, convertedContent);
}
}
const metadataFile = path.resolve(resourcesDir, 'metadata.json');
const metadataJson = JSON.parse(fs.readFileSync(metadataFile));
const legacyShellVersions = metadataJson["shell-version"].filter(version => Number(version) <= 44);
const nonLegacyShellVersions = metadataJson["shell-version"].filter(version => Number(version) > 44);
console.log(" 🚀", "Updating metadata.json file...");
// remove legacy versions from main version's metadata file
metadataJson["shell-version"] = nonLegacyShellVersions;
fs.writeFileSync(path.resolve(distDir, 'metadata.json'), JSON.stringify(metadataJson, null, 4));
// keep legacy versions only from legacy extension's metadata file
metadataJson["shell-version"] = legacyShellVersions;
fs.writeFileSync(path.resolve(distLegacyDir, 'metadata.json'), JSON.stringify(metadataJson, null, 4));
console.log();
console.log("📁 ", "Main version directory: ", distDir);
console.log("📁 ", "Legacy version directory:", distLegacyDir);
console.log("📖 ", "Main version for GNOME Shells: ", nonLegacyShellVersions);
console.log("📖 ", "Legacy version for GNOME Shells:", legacyShellVersions);
});