Skip to content

Commit 563f11f

Browse files
committed
converted generator into an ESM package, bumped version of yeoman-generator to ^6.0.0
bumped typescript version to ~4.7.0 to be able to * set tsConfig options 'module' and 'moduleResolution' to value of 'Node16', see https://www.typescriptlang.org/docs/handbook/release-notes/typescript-4-7.html * deal with the transitive dependency 'mem-fs-editor' in version 10.0.x containing function alias assignments including type argument assignments, see https://www.typescriptlang.org/docs/handbook/release-notes/typescript-4-7.html#instantiation-expressions Signed-off-by: Christian Schneider <[email protected]>
1 parent c44e654 commit 563f11f

File tree

7 files changed

+986
-1651
lines changed

7 files changed

+986
-1651
lines changed

package.json

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,9 @@
33
"version": "0.1.36",
44
"engines": {
55
"yarn": ">=1.7.0 <2",
6-
"node": ">=14.18.0"
6+
"node": ">=16.7.0"
77
},
8+
"type": "module",
89
"description": "Helps to setup the project structure for developing extensions to the Theia IDE",
910
"repository": {
1011
"type": "git",
@@ -20,28 +21,28 @@
2021
"author": "TypeFox",
2122
"license": "EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0",
2223
"dependencies": {
23-
"fs-extra": "^10.0.0",
2424
"request": "^2.88.2",
2525
"tar": "^6.1.1",
26-
"yeoman-generator": "^5.0.0"
26+
"yeoman-generator": "^6.0.0"
2727
},
2828
"devDependencies": {
29+
"@types/request": "^2.48.0",
30+
"@types/tar": "^6.1.1",
2931
"@types/mocha": "^5.2.7",
30-
"@types/yeoman-generator": "^5.0.0",
31-
"mocha": "^6.2.0",
32+
"mocha": "^10.0.0",
3233
"rimraf": "^3.0.0",
33-
"typescript": "~4.5.5",
34+
"typescript": "~4.7.0",
3435
"yeoman-assert": "^3.1.1",
3536
"yeoman-environment": "^3.0.0",
36-
"yeoman-test": "^5.0.0"
37+
"yeoman-test": "^6.0.0"
3738
},
3839
"files": [
3940
"generators",
4041
"templates"
4142
],
4243
"scripts": {
4344
"prepare": "yarn run clean && yarn run build",
44-
"clean": "rimraf lib",
45+
"clean": "rimraf generators",
4546
"build": "tsc",
4647
"watch": "tsc -w",
4748
"test": "mocha",

src/app/index.ts

Lines changed: 53 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -14,12 +14,12 @@
1414
* SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
1515
********************************************************************************/
1616

17-
import type execa = require('execa');
18-
import path = require('path');
19-
import Base = require('yeoman-generator');
20-
const request = require('request');
21-
const tar = require('tar');
22-
const fs = require('fs-extra');
17+
import * as fs from 'node:fs/promises';
18+
import * as path from 'node:path';
19+
import * as url from 'node:url';
20+
import request from 'request';
21+
import tar from 'tar';
22+
import Base, { BaseFeatures, BaseOptions } from 'yeoman-generator/typed';
2323

2424
const glspExamplesRepositoryTag = "generator-latest";
2525
const backend = "backend";
@@ -40,13 +40,26 @@ enum TemplateType {
4040
Node = 'node',
4141
}
4242

43-
module.exports = class TheiaExtension extends Base {
43+
type ExtensionOptions = {
44+
extensionType: ExtensionType;
45+
extensionName?: string;
46+
browser: boolean;
47+
electron: boolean;
48+
standalone?: boolean;
49+
templateType: string;
50+
"theia-version": string;
51+
"lerna-version": string;
52+
githubURL: string;
53+
params: unknown;
54+
}
55+
56+
export default class TheiaExtension extends Base<BaseOptions & ExtensionOptions> {
4457

4558
params: {
4659
author: string
4760
version: string
4861
license: string
49-
extensionName: string
62+
extensionName?: string
5063
extensionType: string
5164
templateType: string
5265
unscopedExtensionName: string
@@ -67,13 +80,14 @@ module.exports = class TheiaExtension extends Base {
6780
rootscripts: string
6881
containsTests: boolean
6982
electronMainLocation: string
83+
backend?: boolean
7084
};
7185

72-
constructor(args: string | string[], options: Base.GeneratorOptions) {
86+
constructor(args: string | string[], options: BaseOptions & ExtensionOptions) {
7387
// For v5 generators the '<npm|pnpm|yarn> install' task is implicitely invoked by 'yeoman-environment' since 'yeoman-environment@3', see
7488
// https://github.com/yeoman/environment/commit/ab9582a70073203c7a6b58fb6dbf1f4eba249d48#diff-54bc5f4bd40f22e081d54b6c20bbf2523e438cf2f2716b91714a1f596e4d87cd
7589
// since we spawn the pm processes on our own in 'install()', we need to declare that here in order to avoid errors because of concurrent runs!
76-
super(args, options, { customInstallTask: true });
90+
super(args, options, <BaseFeatures>{ customInstallTask: true });
7791

7892
this.argument('extensionName', {
7993
type: String,
@@ -155,12 +169,12 @@ module.exports = class TheiaExtension extends Base {
155169
}
156170

157171
path() {
158-
this.sourceRoot(__dirname + '/../../templates');
172+
this.sourceRoot(path.dirname(url.fileURLToPath(import.meta.url)) + '/../../templates');
159173
}
160174

161175
async prompting() {
162-
let extensionType = (this.options as any).extensionType;
163-
const inExtensionType = (<any>Object).values(ExtensionType).includes(extensionType);
176+
let extensionType = this.options.extensionType;
177+
const inExtensionType = Object.values(ExtensionType).includes(extensionType);
164178
if ((extensionType === undefined) || !inExtensionType) {
165179
if (!(extensionType === undefined)) {
166180
this.log(`Invalid extension type: ${extensionType}`);
@@ -179,7 +193,7 @@ module.exports = class TheiaExtension extends Base {
179193
{ value: ExtensionType.DiagramEditor, name: 'DiagramEditor' }
180194
]
181195
});
182-
(this.options as any).extensionType = answer.type;
196+
this.options.extensionType = answer.type;
183197

184198
if (answer.type === ExtensionType.DiagramEditor) {
185199
const answer = await this.prompt({
@@ -193,7 +207,7 @@ module.exports = class TheiaExtension extends Base {
193207
});
194208
let template = answer.backend;
195209

196-
(this.options as any).templateType = template;
210+
this.options.templateType = template;
197211

198212
if(template === TemplateType.Java) {
199213
this.log('\x1b[32m%s\x1b[0m', 'The template will use an EMF source model on the server and generate a Theia extension ✓')
@@ -204,22 +218,22 @@ module.exports = class TheiaExtension extends Base {
204218
}
205219
}
206220

207-
let extensionName = (this.options as any).extensionName;
221+
let extensionName = this.options.extensionName;
208222
// extensionName is not used within the DiagramEditor
209223
if (!extensionName && this.options.extensionType !== ExtensionType.DiagramEditor) {
210224
const answer = await this.prompt({
211225
type: 'input',
212226
name: 'name',
213227
message: 'The extension\'s name',
214-
default: (this.options as any).extensionType
228+
default: this.options.extensionType
215229
});
216-
(this.options as any).extensionName = answer.name;
230+
this.options.extensionName = answer.name;
217231
}
218232
}
219233

220234
configuring() {
221-
const options = this.options as any
222-
const extensionName = options.extensionName as string
235+
const options = this.options
236+
const extensionName = options.extensionName
223237
let unscopedExtensionName = ''
224238
let extensionPath = ''
225239
let extensionPrefix = ''
@@ -234,7 +248,7 @@ module.exports = class TheiaExtension extends Base {
234248
const templateType = options.templateType;
235249
const githubURL = options.githubURL;
236250
this.log(extensionPrefix);
237-
this.params = {
251+
this.params = <any>{
238252
...options,
239253
extensionName,
240254
unscopedExtensionName,
@@ -245,7 +259,7 @@ module.exports = class TheiaExtension extends Base {
245259
githubURL,
246260
theiaVersion: options["theia-version"],
247261
lernaVersion: options["lerna-version"],
248-
backend: options["extensionType"] === ExtensionType.Backend,
262+
backend: options.extensionType === ExtensionType.Backend,
249263
electronMainLocation: this.getElectronMainLocation(options["theia-version"])
250264
}
251265
this.params.dependencies = '';
@@ -259,13 +273,13 @@ module.exports = class TheiaExtension extends Base {
259273
this.params.rootscripts =`,\n "test": "cd ${this.params.extensionPath} && yarn test"`;
260274
this.params.containsTests = true;
261275
}
262-
options.params = this.params
276+
options.params = this.params // piggyback the params to options and hand them over to the child generators
263277
if (!options.standalone && this.params.extensionType !== ExtensionType.DiagramEditor) {
264278
if (options.browser) {
265-
this.composeWith(require.resolve('../browser'), this.options);
279+
this.composeWith('../browser/index.js', this.options);
266280
}
267281
if (options.electron) {
268-
this.composeWith(require.resolve('../electron'), this.options);
282+
this.composeWith('../electron/index.js', this.options);
269283
}
270284
}
271285
if (options.standalone) {
@@ -477,7 +491,7 @@ module.exports = class TheiaExtension extends Base {
477491

478492
/** DiagramEditor */
479493
if (this.params.extensionType === ExtensionType.DiagramEditor) {
480-
const baseDir = `./glsp-examples-${glspExamplesRepositoryTag}`;
494+
const baseDir = `glsp-examples-${glspExamplesRepositoryTag}`;
481495
let templatePath = '';
482496
if(this.params.templateType == TemplateType.Java) {
483497
templatePath = '/project-templates/java-emf-theia';
@@ -487,13 +501,18 @@ module.exports = class TheiaExtension extends Base {
487501
return;
488502
}
489503

490-
return new Promise<void>((resolve) => {
491-
request.get(`https://github.com/eclipse-glsp/glsp-examples/archive/refs/tags/${glspExamplesRepositoryTag}.tar.gz`).pipe(tar.x().on('close',() => {
492-
fs.copy(baseDir+'/README.md', './README.md');
493-
fs.copy(baseDir+templatePath, './').then(() => {
494-
fs.rm(baseDir, { recursive: true });
504+
const dest = this.destinationPath.bind(this);
505+
506+
return new Promise<void>((resolve, reject) => {
507+
request.get(`https://github.com/eclipse-glsp/glsp-examples/archive/refs/tags/${glspExamplesRepositoryTag}.tar.gz`).pipe(tar.x({ cwd: dest() }).on('close', async () => {
508+
try {
509+
await fs.cp(dest(baseDir, 'README.md'), dest('./README.md'));
510+
await fs.cp(dest(baseDir, templatePath), dest(), { recursive: true });
511+
await fs.rm(dest(baseDir), { recursive: true });
495512
resolve();
496-
});
513+
} catch (e) {
514+
reject(e);
515+
}
497516
}));
498517
});
499518
}
@@ -504,9 +523,9 @@ module.exports = class TheiaExtension extends Base {
504523
}
505524

506525
async install() {
507-
if (!(this.options as any).skipInstall) {
526+
if (!this.options.skipInstall) {
508527
this.log('Installing dependencies');
509-
const command: execa.ExecaChildProcess = this.spawnCommand('yarn', []);
528+
const command = this.spawn('yarn', []);
510529

511530
if (this.params.extensionType == ExtensionType.DiagramEditor) {
512531
command.on('close', (code:number) => {
@@ -553,6 +572,3 @@ module.exports = class TheiaExtension extends Base {
553572
}
554573
}
555574
}
556-
557-
module.exports.ExtensionType = ExtensionType;
558-

src/browser/index.ts

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -14,22 +14,23 @@
1414
* SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
1515
********************************************************************************/
1616

17-
import Base  = require('yeoman-generator');
17+
import * as path from 'node:path';
18+
import * as url from 'node:url';
19+
import Base, { BaseOptions } from 'yeoman-generator';
1820

19-
module.exports = class TheiaBrowser extends Base {
21+
export default class TheiaBrowser extends Base<BaseOptions & { params: unknown }> {
2022

2123
path() {
22-
this.sourceRoot(__dirname + '/../../templates')
24+
this.sourceRoot(path.dirname(url.fileURLToPath(import.meta.url)) + '/../../templates')
2325
}
2426

2527
writing() {
26-
const params = (this.options as any).params
2728
this.fs.copyTpl(
2829
this.templatePath('app-browser-package.json'),
2930
this.destinationPath('browser-app/package.json'),
3031
{
3132
appMode: 'browser',
32-
params
33+
params: this.options.params
3334
}
3435
);
3536
}

src/electron/index.ts

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -14,12 +14,14 @@
1414
* SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
1515
********************************************************************************/
1616

17-
import Base  = require('yeoman-generator');
17+
import * as path from 'node:path';
18+
import * as url from 'node:url';
19+
import Base, { BaseOptions } from 'yeoman-generator';
1820

19-
module.exports = class TheiaElectron extends Base {
21+
export default class TheiaElectron extends Base<BaseOptions & { params: unknown }> {
2022

2123
path() {
22-
this.sourceRoot(__dirname + '/../../templates')
24+
this.sourceRoot(path.dirname(url.fileURLToPath(import.meta.url)) + '/../../templates')
2325
}
2426

2527
writing() {
@@ -28,7 +30,7 @@ module.exports = class TheiaElectron extends Base {
2830
this.destinationPath('electron-app/package.json'),
2931
{
3032
appMode: 'electron',
31-
params: (this.options as any).params
33+
params: this.options.params
3234
}
3335
);
3436
}

test/generator-test.js

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -14,10 +14,13 @@
1414
* SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
1515
********************************************************************************/
1616

17-
var assert = require('yeoman-assert')
18-
var helpers = require('yeoman-test');
19-
var path = require('path');
20-
var fs = require('fs');
17+
import * as fs from 'fs';
18+
import * as path from 'path';
19+
import * as url from 'url';
20+
import assert from 'yeoman-assert';
21+
import helpers from 'yeoman-test';
22+
23+
const __dirname = path.dirname(url.fileURLToPath(import.meta.url));
2124

2225
describe('test extension generation', function () {
2326
this.timeout(10000);

tsconfig.json

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,9 @@
77
"emitDecoratorMetadata": true,
88
"skipLibCheck": true,
99
"downlevelIteration": true,
10-
"module": "commonjs",
11-
"moduleResolution": "node",
10+
"module": "Node16",
11+
"moduleResolution": "Node16",
12+
"allowSyntheticDefaultImports": false, // to force us writing proper imports of contents of third-party CommonJS modules
1213
"target": "es6",
1314
"lib": [
1415
"es6",

0 commit comments

Comments
 (0)