deploy: current vibn theia state
Made-with: Cursor
This commit is contained in:
70
dev-packages/private-ext-scripts/README.md
Normal file
70
dev-packages/private-ext-scripts/README.md
Normal file
@@ -0,0 +1,70 @@
|
||||
<div align='center'>
|
||||
|
||||
<br />
|
||||
|
||||
<img src='https://raw.githubusercontent.com/eclipse-theia/theia/master/logo/theia.svg?sanitize=true' alt='theia-ext-logo' width='100px' />
|
||||
|
||||
<h2>ECLIPSE THEIA - EXT-SCRIPTS</h2>
|
||||
|
||||
<hr />
|
||||
|
||||
</div>
|
||||
|
||||
## Description
|
||||
|
||||
`theiaext` is a command line tool to run shared npm scripts in Theia packages.\
|
||||
For instance, if you want add a new `hello` script that prints `Hello World`:
|
||||
|
||||
- add a new script to [./package.json](./package.json) with the `ext:` prefix.
|
||||
|
||||
```json
|
||||
{
|
||||
"name": "@theia/ext-scripts",
|
||||
"theia-monorepo-scripts": {
|
||||
"ext:hello": "echo 'Hello World'"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
- install `theiaext` in your package (the actual version can be different)
|
||||
|
||||
```json
|
||||
{
|
||||
"name": "@theia/myextension",
|
||||
"devDependencies": {
|
||||
"@theia/ext-scripts": "^0.1.1"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
- you should be able to call `hello` script in the context of your package:
|
||||
|
||||
```shell
|
||||
npx theiaext hello
|
||||
````
|
||||
|
||||
- and from npm scripts of your package:
|
||||
|
||||
```json
|
||||
{
|
||||
"name": "@theia/myextension",
|
||||
"scripts": {
|
||||
"hello": "theiaext hello"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Additional Information
|
||||
|
||||
- [Theia - GitHub](https://github.com/eclipse-theia/theia)
|
||||
- [Theia - Website](https://theia-ide.org/)
|
||||
|
||||
## License
|
||||
|
||||
- [Eclipse Public License 2.0](http://www.eclipse.org/legal/epl-2.0/)
|
||||
- [一 (Secondary) GNU General Public License, version 2 with the GNU Classpath Exception](https://projects.eclipse.org/license/secondary-gpl-2.0-cp)
|
||||
|
||||
## Trademark
|
||||
|
||||
"Theia" is a trademark of the Eclipse Foundation
|
||||
<https://www.eclipse.org/theia>
|
||||
83
dev-packages/private-ext-scripts/bin/theia-ext.js
Executable file
83
dev-packages/private-ext-scripts/bin/theia-ext.js
Executable file
@@ -0,0 +1,83 @@
|
||||
#!/usr/bin/env node
|
||||
|
||||
// *****************************************************************************
|
||||
// Copyright (C) 2017 TypeFox and others.
|
||||
//
|
||||
// This program and the accompanying materials are made available under the
|
||||
// terms of the Eclipse Public License v. 2.0 which is available at
|
||||
// http://www.eclipse.org/legal/epl-2.0.
|
||||
//
|
||||
// This Source Code may also be made available under the following Secondary
|
||||
// Licenses when the conditions for such availability set forth in the Eclipse
|
||||
// Public License v. 2.0 are satisfied: GNU General Public License, version 2
|
||||
// with the GNU Classpath Exception which is available at
|
||||
// https://www.gnu.org/software/classpath/license.html.
|
||||
//
|
||||
// SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-only WITH Classpath-exception-2.0
|
||||
// *****************************************************************************
|
||||
// @ts-check
|
||||
const path = require('path');
|
||||
const cp = require('child_process');
|
||||
|
||||
const extScriptsPck = require(path.resolve(__dirname, '../package.json'));
|
||||
|
||||
/**
|
||||
* Lookup the requested ext:script to run, returns the full command line to execute.
|
||||
*/
|
||||
function getExtScript() {
|
||||
// process.argv is always like [0:node, 1:script, 2:...args]
|
||||
const args = process.argv.slice(2);
|
||||
if (!args[0]) {
|
||||
throw new Error('Please specify the script that runs with theiaext command.');
|
||||
}
|
||||
const scripts = extScriptsPck['theia-monorepo-scripts'];
|
||||
const script = 'ext:' + args[0];
|
||||
if (!(script in scripts)) {
|
||||
throw new Error('The ext script does not exist: ' + script);
|
||||
}
|
||||
return [scripts[script], ...args.slice(1, args.length)].join(' ');
|
||||
}
|
||||
|
||||
/**
|
||||
* Essentially wraps `child_process.exec` into a promise.
|
||||
*
|
||||
* @param script Command line to run as a shell command.
|
||||
*/
|
||||
function run(script) {
|
||||
return new Promise((resolve, reject) => {
|
||||
const env = Object.assign({}, process.env);
|
||||
const scriptProcess = cp.exec(script, {
|
||||
cwd: process.cwd(),
|
||||
env,
|
||||
});
|
||||
scriptProcess.stdout.pipe(process.stdout);
|
||||
scriptProcess.stderr.pipe(process.stderr);
|
||||
scriptProcess.on('error', reject);
|
||||
scriptProcess.on('close', resolve);
|
||||
});
|
||||
}
|
||||
|
||||
(async () => {
|
||||
/** @type {Error | number} */
|
||||
let exitCode = 0;
|
||||
let extScript = undefined;
|
||||
try {
|
||||
extScript = getExtScript();
|
||||
console.debug(`$ ${extScript}`);
|
||||
exitCode = await run(extScript);
|
||||
} catch (err) {
|
||||
if (extScript) {
|
||||
console.error(`Error occurred in theiaext when executing: ${extScript}\n`);
|
||||
} else {
|
||||
console.error('Error occurred in theiaext.');
|
||||
}
|
||||
console.error(err);
|
||||
exitCode = err;
|
||||
}
|
||||
if (typeof exitCode !== 'number') {
|
||||
exitCode = 1; // Error happened without the process starting.
|
||||
} else if (exitCode) {
|
||||
console.error(`Exit with failure status (${exitCode}): ${extScript}`);
|
||||
}
|
||||
process.exit(exitCode);
|
||||
})();
|
||||
35
dev-packages/private-ext-scripts/bin/theia-run.js
Executable file
35
dev-packages/private-ext-scripts/bin/theia-run.js
Executable file
@@ -0,0 +1,35 @@
|
||||
#!/usr/bin/env node
|
||||
|
||||
// *****************************************************************************
|
||||
// Copyright (C) 2017 TypeFox and others.
|
||||
//
|
||||
// This program and the accompanying materials are made available under the
|
||||
// terms of the Eclipse Public License v. 2.0 which is available at
|
||||
// http://www.eclipse.org/legal/epl-2.0.
|
||||
//
|
||||
// This Source Code may also be made available under the following Secondary
|
||||
// Licenses when the conditions for such availability set forth in the Eclipse
|
||||
// Public License v. 2.0 are satisfied: GNU General Public License, version 2
|
||||
// with the GNU Classpath Exception which is available at
|
||||
// https://www.gnu.org/software/classpath/license.html.
|
||||
//
|
||||
// SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-only WITH Classpath-exception-2.0
|
||||
// *****************************************************************************
|
||||
// @ts-check
|
||||
const path = require('path');
|
||||
|
||||
// See: https://github.com/eclipse-theia/theia/issues/8779#issuecomment-733747340
|
||||
const filter = require('os').platform() === 'win32'
|
||||
? arg => arg.indexOf(path.join('ext-scripts', 'theia-run.js')) !== -1
|
||||
: arg => arg.indexOf(path.join('.bin', 'run')) !== -1
|
||||
let index = process.argv.findIndex(filter);
|
||||
if (index === -1) {
|
||||
// Fall back to the original logic.
|
||||
// https://github.com/eclipse-theia/theia/blob/6ef08676314a2ceca93023ddd149579493ae7914/dev-packages/ext-scripts/theia-run.js#L21
|
||||
index = process.argv.findIndex(arg => arg.indexOf('run') !== -1);
|
||||
}
|
||||
const args = process.argv.slice(index + 1);
|
||||
const scopedArgs = args.length > 1 ? [args[0], '--scope', ...args.slice(1)] : args;
|
||||
process.argv = [...process.argv.slice(0, index + 1), 'run', ...scopedArgs];
|
||||
|
||||
require(path.resolve(__dirname, '..', '..', 'scripts', 'lerna'));
|
||||
216
dev-packages/private-ext-scripts/bin/theia-ts-clean.js
Executable file
216
dev-packages/private-ext-scripts/bin/theia-ts-clean.js
Executable file
@@ -0,0 +1,216 @@
|
||||
#!/usr/bin/env node
|
||||
|
||||
// *****************************************************************************
|
||||
// Copyright (C) 2021 Ericsson and others.
|
||||
//
|
||||
// This program and the accompanying materials are made available under the
|
||||
// terms of the Eclipse Public License v. 2.0 which is available at
|
||||
// http://www.eclipse.org/legal/epl-2.0.
|
||||
//
|
||||
// This Source Code may also be made available under the following Secondary
|
||||
// Licenses when the conditions for such availability set forth in the Eclipse
|
||||
// Public License v. 2.0 are satisfied: GNU General Public License, version 2
|
||||
// with the GNU Classpath Exception which is available at
|
||||
// https://www.gnu.org/software/classpath/license.html.
|
||||
//
|
||||
// SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-only WITH Classpath-exception-2.0
|
||||
// *****************************************************************************
|
||||
|
||||
// @ts-check
|
||||
|
||||
const _glob = require('glob');
|
||||
const debug = require('debug')('ts-clean');
|
||||
const fs = require('fs');
|
||||
const parcelWatcher = require('@parcel/watcher');
|
||||
const path = require('path');
|
||||
const util = require('util');
|
||||
const yargs = require('yargs');
|
||||
|
||||
const glob = util.promisify(_glob);
|
||||
|
||||
tsClean().catch(error => {
|
||||
console.error(error);
|
||||
process.exit(1);
|
||||
});
|
||||
|
||||
async function tsClean() {
|
||||
yargs
|
||||
.command(
|
||||
'$0 [globs..]',
|
||||
'cleanup TypeScript output',
|
||||
cmd => cmd
|
||||
.option('verbose', {
|
||||
description: 'print what\'s going on',
|
||||
boolean: true,
|
||||
default: false,
|
||||
})
|
||||
.option('dry', {
|
||||
description: 'only display the files that would be deleted',
|
||||
boolean: true,
|
||||
default: false,
|
||||
})
|
||||
.option('watch', {
|
||||
description: 'run the cleanup in watch mode',
|
||||
alias: 'w',
|
||||
boolean: true,
|
||||
default: false,
|
||||
})
|
||||
.positional('globs', {
|
||||
array: true,
|
||||
default: [process.cwd()]
|
||||
}),
|
||||
async ({ dry, globs, verbose, watch }) => {
|
||||
if (dry || verbose) {
|
||||
debug.enabled = true;
|
||||
}
|
||||
await Promise.all(globs.map(async pattern => {
|
||||
if (typeof pattern !== 'string') {
|
||||
return;
|
||||
}
|
||||
const roots = await glob(pattern, {
|
||||
absolute: true,
|
||||
});
|
||||
await Promise.all(roots.map(async root => {
|
||||
const stat = await fs.promises.stat(root);
|
||||
if (!stat.isDirectory()) {
|
||||
debug(`"${root}" is not a directory, skipping...`);
|
||||
return;
|
||||
}
|
||||
const tsconfigPath = path.resolve(root, 'tsconfig.json');
|
||||
if (!await exists(tsconfigPath)) {
|
||||
debug(`"${root}" is not a TypeScript package, skipping...`);
|
||||
return;
|
||||
}
|
||||
const {
|
||||
compilerOptions: {
|
||||
outDir = undefined,
|
||||
rootDir = undefined,
|
||||
} = {},
|
||||
} = await fs.promises.readFile(tsconfigPath, 'utf8').then(JSON.parse);
|
||||
if (typeof outDir !== 'string' || typeof rootDir !== 'string') {
|
||||
debug(`"${tsconfigPath}" doesn't look like a compilation configuration, skipping...`);
|
||||
return;
|
||||
}
|
||||
const src = path.resolve(root, rootDir);
|
||||
const dst = path.resolve(root, outDir);
|
||||
await watch
|
||||
? tsCleanWatch(src, dst, dry)
|
||||
: tsCleanRun(src, dst, dry);
|
||||
}));
|
||||
}));
|
||||
}
|
||||
)
|
||||
.fail((msg, err, cli) => {
|
||||
process.exitCode = 1;
|
||||
if (err) {
|
||||
// One of the handlers threw an error:
|
||||
console.error(err);
|
||||
} else {
|
||||
// Yargs detected a problem with commands and/or arguments while parsing:
|
||||
cli.showHelp();
|
||||
console.error(msg);
|
||||
}
|
||||
})
|
||||
.parse();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} src
|
||||
* @param {string} dst
|
||||
* @param {boolean} dry
|
||||
*/
|
||||
async function tsCleanWatch(src, dst, dry) {
|
||||
await tsCleanRun(src, dst, dry);
|
||||
await parcelWatcher.subscribe(src, async (_err, events) => {
|
||||
for (const event of events) {
|
||||
let absolute;
|
||||
if (event.type === 'delete') {
|
||||
absolute = event.path;
|
||||
} else {
|
||||
continue;
|
||||
}
|
||||
console.log('Source removed:', absolute);
|
||||
const relative = path.relative(src, absolute);
|
||||
// Absolute path of the expected generated files, without the original ts(x) extension.
|
||||
const base = path.resolve(dst, relative).replace(/\.(tsx?)$/i, '');
|
||||
await Promise.all(generatedFilesFromBase(base).map(async file => {
|
||||
debug('delete', file);
|
||||
if (!dry && await exists(file)) {
|
||||
await fs.promises.unlink(file).catch(debug);
|
||||
}
|
||||
}));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} src
|
||||
* @param {string} dst
|
||||
* @param {boolean} dry
|
||||
*/
|
||||
async function tsCleanRun(src, dst, dry) {
|
||||
/**
|
||||
* Generated files relative to `dst`.
|
||||
*/
|
||||
const files = await glob('**/*.{d.ts,d.ts.map,js,js.map}', {
|
||||
absolute: false,
|
||||
cwd: dst,
|
||||
});
|
||||
/**
|
||||
* Key is the path without extension (base) relative to `dst`.
|
||||
* Value is the list of found generated files (absolute path).
|
||||
* @type {Map<string, string[]>}
|
||||
*/
|
||||
const bases = new Map();
|
||||
for (const file of files) {
|
||||
const parse = path.parse(file);
|
||||
const base = path.join(parse.dir, removeExtension(parse.base));
|
||||
let generated = bases.get(base);
|
||||
if (!generated) {
|
||||
bases.set(base, generated = []);
|
||||
}
|
||||
generated.push(path.resolve(dst, file));
|
||||
}
|
||||
await Promise.all(Array.from(bases.entries(), async ([base, generated]) => {
|
||||
if (await exists(src, `${base}.ts`) || await exists(src, `${base}.tsx`)) {
|
||||
return;
|
||||
}
|
||||
console.log('Missing source:', path.resolve(src, `${base}.ts(x)`));
|
||||
await Promise.all(generated.map(async file => {
|
||||
debug('delete', file);
|
||||
if (!dry) {
|
||||
await fs.promises.unlink(file).catch(debug);
|
||||
}
|
||||
}));
|
||||
}));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string[]} parts
|
||||
*/
|
||||
function generatedFilesFromBase(...parts) {
|
||||
const base = path.resolve(...parts);
|
||||
return [
|
||||
`${base}.d.ts`,
|
||||
`${base}.d.ts.map`,
|
||||
`${base}.js`,
|
||||
`${base}.js.map`,
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes the extension of files ending with:
|
||||
* .d.ts, .d.ts.map, .js, .js.map, .ts, .tsx
|
||||
* @param {string} base
|
||||
*/
|
||||
function removeExtension(base) {
|
||||
return base.replace(/\.(d\.ts(\.map)?|js(\.map)?|tsx?)$/i, '');
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string[]} parts
|
||||
*/
|
||||
async function exists(...parts) {
|
||||
return fs.promises.access(path.resolve(...parts), fs.constants.F_OK)
|
||||
.then(ok => true, error => false);
|
||||
}
|
||||
25
dev-packages/private-ext-scripts/package.json
Normal file
25
dev-packages/private-ext-scripts/package.json
Normal file
@@ -0,0 +1,25 @@
|
||||
{
|
||||
"private": true,
|
||||
"name": "@theia/ext-scripts",
|
||||
"version": "1.68.0",
|
||||
"license": "EPL-2.0 OR GPL-2.0-only WITH Classpath-exception-2.0",
|
||||
"description": "NPM scripts for Theia packages.",
|
||||
"bin": {
|
||||
"run": "bin/theia-run.js",
|
||||
"theiaext": "bin/theia-ext.js",
|
||||
"ts-clean-dangling": "bin/theia-ts-clean.js"
|
||||
},
|
||||
"theia-monorepo-scripts": {
|
||||
"ext:clean": "theiaext compile:clean && theiaext lint:clean && theiaext test:clean",
|
||||
"ext:build": "ts-clean-dangling && tsc --build",
|
||||
"ext:compile": "ts-clean-dangling && tsc --project .",
|
||||
"ext:compile:clean": "rimraf lib *.tsbuildinfo",
|
||||
"ext:lint": "eslint --cache=true --no-error-on-unmatched-pattern=true \"{src,test}/**/*.{ts,tsx}\"",
|
||||
"ext:lint:clean": "rimraf .eslintcache",
|
||||
"ext:watch": "concurrently --kill-others -n cleanup,tsc -c magenta,red \"ts-clean-dangling -w\" \"tsc -b -w --preserveWatchOutput\"",
|
||||
"ext:watch:fast": "tsc -p -w",
|
||||
"ext:test": "nyc mocha --config ../../configs/mocharc.yml \"./lib/**/*.*spec.js\"",
|
||||
"ext:test:watch": "mocha -w --config ../../configs/mocharc.yml \"./lib/**/*.*spec.js\"",
|
||||
"ext:test:clean": "rimraf .nyc_output coverage"
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user