deploy: current vibn theia state
Made-with: Cursor
This commit is contained in:
10
dev-packages/private-re-exports/.eslintrc.js
Normal file
10
dev-packages/private-re-exports/.eslintrc.js
Normal file
@@ -0,0 +1,10 @@
|
||||
/** @type {import('eslint').Linter.Config} */
|
||||
module.exports = {
|
||||
extends: [
|
||||
'../../configs/build.eslintrc.json'
|
||||
],
|
||||
parserOptions: {
|
||||
tsconfigRootDir: __dirname,
|
||||
project: 'tsconfig.json'
|
||||
}
|
||||
};
|
||||
41
dev-packages/private-re-exports/README.md
Normal file
41
dev-packages/private-re-exports/README.md
Normal file
@@ -0,0 +1,41 @@
|
||||
# `@theia/re-export`
|
||||
|
||||
Utility package to re-export dependencies.
|
||||
|
||||
This is useful when you use and expose some APIs from a dependency and want
|
||||
your dependent to get access to the exact same symbols as you did.
|
||||
|
||||
## `package.json`
|
||||
|
||||
You can configure how the `theia-re-export` CLI will generate re-exports
|
||||
through your `package.json` file with a `theiaReExports` key:
|
||||
|
||||
```json
|
||||
{
|
||||
"theiaReExports": {
|
||||
"destination": {
|
||||
"export *": [
|
||||
"packages that export via *"
|
||||
],
|
||||
"export =": [
|
||||
"packages that export via ="
|
||||
],
|
||||
"copy": "other-package#destination"
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### `transitive`
|
||||
|
||||
If you want to re-export packages from another package that also re-exports
|
||||
its dependencies. We use this in `@theia/core` to simplify the consumption
|
||||
of some optional Electron-specific dependencies.
|
||||
|
||||
### `export *`
|
||||
|
||||
Packages that export their symbols as `export const x = ...`.
|
||||
|
||||
### `export =`
|
||||
|
||||
Packages that export their symbols as a namespace like `export = ...`.
|
||||
2
dev-packages/private-re-exports/bin/theia-re-exports.js
Executable file
2
dev-packages/private-re-exports/bin/theia-re-exports.js
Executable file
@@ -0,0 +1,2 @@
|
||||
#!/usr/bin/env node
|
||||
require('../lib/bin-theia-re-exports.js');
|
||||
39
dev-packages/private-re-exports/package.json
Normal file
39
dev-packages/private-re-exports/package.json
Normal file
@@ -0,0 +1,39 @@
|
||||
{
|
||||
"private": true,
|
||||
"name": "@theia/re-exports",
|
||||
"version": "1.68.0",
|
||||
"description": "Theia re-export helper functions and scripts.",
|
||||
"main": "lib/index.js",
|
||||
"engines": {
|
||||
"node": ">= 12"
|
||||
},
|
||||
"files": [
|
||||
"bin",
|
||||
"lib",
|
||||
"src"
|
||||
],
|
||||
"bin": {
|
||||
"theia-re-exports": "bin/theia-re-exports.js"
|
||||
},
|
||||
"scripts": {
|
||||
"afterInstall": "npm run build",
|
||||
"build": "theiaext build",
|
||||
"clean": "theiaext clean",
|
||||
"compile": "theiaext compile",
|
||||
"lint": "theiaext lint",
|
||||
"test": "theiaext test",
|
||||
"watch": "theiaext watch"
|
||||
},
|
||||
"dependencies": {
|
||||
"mustache": "^4.2.0",
|
||||
"semver": "^7.5.4",
|
||||
"tslib": "^2.6.2",
|
||||
"yargs": "^15.3.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/chai": "^4.3.0",
|
||||
"@types/mocha": "^10.0.0",
|
||||
"@types/mustache": "^4.1.2",
|
||||
"typescript": "~5.9.3"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
// *****************************************************************************
|
||||
// Copyright (C) 2022 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
|
||||
// *****************************************************************************
|
||||
|
||||
import { readPackageJson, parsePackageReExports } from './package-re-exports';
|
||||
|
||||
const packageName = process.argv[2].trim();
|
||||
|
||||
readPackageJson(packageName, { paths: [process.cwd()] })
|
||||
.then(([packageJsonPath, packageJson]) => parsePackageReExports(packageJsonPath, packageJson))
|
||||
.then(([packageRoot, reExports]) => console.log(JSON.stringify([packageRoot, reExports])));
|
||||
160
dev-packages/private-re-exports/src/bin-theia-re-exports.ts
Normal file
160
dev-packages/private-re-exports/src/bin-theia-re-exports.ts
Normal file
@@ -0,0 +1,160 @@
|
||||
// *****************************************************************************
|
||||
// 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
|
||||
// *****************************************************************************
|
||||
|
||||
import fs = require('fs');
|
||||
import mustache = require('mustache');
|
||||
import os = require('os');
|
||||
import path = require('path');
|
||||
import semver = require('semver');
|
||||
import yargs = require('yargs');
|
||||
import { parseModule } from './utility';
|
||||
import { ReExport, PackageReExports } from './package-re-exports';
|
||||
type EOL = '\r\n' | '\n' | '\r';
|
||||
|
||||
yargs
|
||||
.command(
|
||||
'generate [packageName]',
|
||||
'Generate Theia re-exports',
|
||||
cli => cli
|
||||
.positional('packageName', {
|
||||
type: 'string',
|
||||
describe: 'Name of the package to generate the re-exports for'
|
||||
}),
|
||||
async ({ packageName }) => {
|
||||
if (!packageName) {
|
||||
packageName = JSON.parse(await readFile(path.resolve('package.json'))).name as string;
|
||||
}
|
||||
const packageReExports = await PackageReExports.FromPackage(packageName);
|
||||
const writer = new FileWriter(findEol(await readFile(packageReExports.resolvePath('package.json'))));
|
||||
await Promise.all(packageReExports.all.map(async reExport => {
|
||||
const reExportPath = packageReExports.resolvePath(reExport.reExportDir, reExport.moduleName, 'index');
|
||||
await writer.write(`${reExportPath}.js`, `module.exports = require('${reExport.internalImport}');\n`);
|
||||
if (reExport.reExportStyle === '*') {
|
||||
const content = `export * from '${reExport.internalImport}';\n`;
|
||||
await writer.write(`${reExportPath}.d.ts`, content);
|
||||
} else if (reExport.reExportStyle === '=') {
|
||||
const content = `import ${reExport.exportNamespace} = require('${reExport.internalImport}');\nexport = ${reExport.exportNamespace};\n`;
|
||||
await writer.write(`${reExportPath}.d.ts`, content);
|
||||
} else {
|
||||
console.warn('unexpected re-export');
|
||||
}
|
||||
}));
|
||||
}
|
||||
)
|
||||
.command(
|
||||
'template inputFile [packageName]',
|
||||
'Evaluate mustache templates',
|
||||
cli => cli
|
||||
.positional('inputFile', {
|
||||
type: 'string',
|
||||
describe: 'File to evaluate defined using mustache template syntax',
|
||||
demandOption: true
|
||||
})
|
||||
.positional('packageName', {
|
||||
type: 'string',
|
||||
describe: 'Name of the package to generate the re-exports for'
|
||||
}),
|
||||
async ({ inputFile, packageName }) => {
|
||||
if (!packageName) {
|
||||
packageName = JSON.parse(await readFile(path.resolve('package.json'))).name as string;
|
||||
}
|
||||
const template = await readFile(inputFile);
|
||||
const packageReExports = await PackageReExports.FromPackage(packageName);
|
||||
const eol = findEol(await readFile(packageReExports.resolvePath('package.json')));
|
||||
// Organize `ReExport`s by `reExportsDir` then by `packageName`:
|
||||
const reExportsDirectories: Record<string, Record<string, ReExport[]>> = {};
|
||||
for (const reExport of packageReExports.all) {
|
||||
let reExportsPackages = reExportsDirectories[reExport.reExportDir];
|
||||
if (!reExportsPackages) {
|
||||
reExportsPackages = reExportsDirectories[reExport.reExportDir] = {};
|
||||
}
|
||||
let reExports = reExportsPackages[reExport.packageName];
|
||||
if (!reExports) {
|
||||
reExports = reExportsPackages[reExport.packageName] = [];
|
||||
}
|
||||
reExports.push(reExport);
|
||||
}
|
||||
// Map the organized `ReExport`s into a view object for mustache:
|
||||
const reExportsView: ReExportsView = {
|
||||
reExportsDirectories: Object.entries(reExportsDirectories).map(([directory, reExportsPackages]) => ({
|
||||
directory,
|
||||
// eslint-disable-next-line @typescript-eslint/no-shadow
|
||||
packages: Object.entries(reExportsPackages).map(([packageName, reExports]) => ({
|
||||
packageName,
|
||||
npmUrl: getNpmUrl(packageName, reExports[0].versionRange),
|
||||
versionRange: reExports[0].versionRange,
|
||||
modules: reExports.map(reExport => ({
|
||||
moduleName: reExport.moduleName,
|
||||
}))
|
||||
}))
|
||||
}))
|
||||
};
|
||||
// `console.log` replaces CRLF with LF which is problematic on Windows
|
||||
process.stdout.write(convertEol(eol, mustache.render(template, reExportsView)));
|
||||
}
|
||||
)
|
||||
.parse();
|
||||
|
||||
interface ReExportsView {
|
||||
reExportsDirectories: Array<{
|
||||
directory: string
|
||||
packages: Array<{
|
||||
npmUrl: string
|
||||
packageName: string
|
||||
modules: Array<{
|
||||
moduleName: string
|
||||
}>
|
||||
versionRange: string
|
||||
}>
|
||||
}>
|
||||
}
|
||||
|
||||
function getNpmUrl(moduleName: string, versionRange: string | null | undefined): string {
|
||||
const [packageName] = parseModule(moduleName);
|
||||
let url = `https://www.npmjs.com/package/${packageName}`;
|
||||
// Is the range a fixed version?
|
||||
const version = versionRange && semver.valid(versionRange);
|
||||
if (version) {
|
||||
url += `/v/${version}`;
|
||||
}
|
||||
return url;
|
||||
}
|
||||
|
||||
async function readFile(filePath: string): Promise<string> {
|
||||
return fs.promises.readFile(filePath, 'utf8');
|
||||
}
|
||||
|
||||
function findEol(content: string): EOL {
|
||||
const match = content.match(/\r\n?|\n/);
|
||||
return (match ? match[0] : os.EOL) as EOL;
|
||||
}
|
||||
|
||||
function convertEol(eol: EOL, content: string): string {
|
||||
switch (eol) {
|
||||
case '\r\n': return content.replace(/(?<!\r)\n|\r(?!\n)/g, '\r\n');
|
||||
case '\n': return content.replace(/\r\n?/g, '\n');
|
||||
case '\r': return content.replace(/\r?\n/g, '\r');
|
||||
}
|
||||
}
|
||||
|
||||
class FileWriter {
|
||||
constructor(public eol: EOL) { }
|
||||
async write(filePath: string, content: string): Promise<void> {
|
||||
const dirPath = path.dirname(filePath);
|
||||
await fs.promises.mkdir(dirPath, { recursive: true });
|
||||
await fs.promises.writeFile(filePath, convertEol(this.eol, content));
|
||||
}
|
||||
}
|
||||
18
dev-packages/private-re-exports/src/index.ts
Normal file
18
dev-packages/private-re-exports/src/index.ts
Normal file
@@ -0,0 +1,18 @@
|
||||
// *****************************************************************************
|
||||
// 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
|
||||
// *****************************************************************************
|
||||
|
||||
export * from './utility';
|
||||
export * from './package-re-exports';
|
||||
204
dev-packages/private-re-exports/src/package-re-exports.ts
Normal file
204
dev-packages/private-re-exports/src/package-re-exports.ts
Normal file
@@ -0,0 +1,204 @@
|
||||
// *****************************************************************************
|
||||
// Copyright (C) 2022 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
|
||||
// *****************************************************************************
|
||||
|
||||
import cp = require('child_process');
|
||||
import fs = require('fs');
|
||||
import path = require('path');
|
||||
import { PackageJson, parseModule, ReExportJson } from './utility';
|
||||
|
||||
export async function readJson<T = unknown>(jsonPath: string): Promise<T> {
|
||||
return JSON.parse(await fs.promises.readFile(jsonPath, 'utf8')) as T;
|
||||
}
|
||||
|
||||
export async function readPackageJson(packageName: string, options?: { paths?: string[] }): Promise<[string, PackageJson]> {
|
||||
const packageJsonPath = require.resolve(`${packageName}/package.json`, options);
|
||||
const packageJson = await readJson<PackageJson>(packageJsonPath);
|
||||
return [packageJsonPath, packageJson];
|
||||
}
|
||||
|
||||
export async function parsePackageReExports(packageJsonPath: string, packageJson: PackageJson): Promise<[string, ReExport[]]> {
|
||||
const packageRoot = path.dirname(packageJsonPath);
|
||||
const { theiaReExports } = packageJson;
|
||||
if (!theiaReExports) {
|
||||
return [packageRoot, []];
|
||||
}
|
||||
const reExportsByExportDir: ReExport[][] = await Promise.all(Object.entries(theiaReExports).map(
|
||||
async ([reExportDir, reExportJson]) => resolveTheiaReExports(packageJsonPath, packageJson, reExportDir, reExportJson))
|
||||
);
|
||||
return [packageRoot, ([] as ReExport[]).concat(...reExportsByExportDir)];
|
||||
}
|
||||
|
||||
export async function resolveTheiaReExports(
|
||||
packageJsonPath: string,
|
||||
packageJson: PackageJson,
|
||||
reExportDir: string,
|
||||
reExportJson: ReExportJson
|
||||
): Promise<ReExport[]> {
|
||||
if (reExportJson.copy) {
|
||||
const [packageName, dir] = reExportJson.copy.split('#', 2);
|
||||
const [subPackageJsonPath, subPackageJson] = await readPackageJson(packageName, { paths: [path.dirname(packageJsonPath)] });
|
||||
if (!subPackageJson.theiaReExports) {
|
||||
return [];
|
||||
}
|
||||
const reExports = await resolveTheiaReExports(subPackageJsonPath, subPackageJson, dir, subPackageJson.theiaReExports[dir]);
|
||||
return reExports.map(reExport => {
|
||||
reExport.reExportDir = reExportDir;
|
||||
reExport.internalImport = reExport.externalImport;
|
||||
reExport.externalImport = `${packageJson.name}/${reExportDir}/${reExport.moduleName}`;
|
||||
return reExport;
|
||||
});
|
||||
}
|
||||
const reExportsStar = reExportJson['export *'] || [];
|
||||
const reExportsEqual = reExportJson['export ='] || [];
|
||||
return [
|
||||
...reExportsStar.map<ReExportStar>(moduleName => {
|
||||
const [packageName, subModuleName] = parseModule(moduleName);
|
||||
return {
|
||||
moduleName,
|
||||
packageName,
|
||||
subModuleName,
|
||||
reExportStyle: '*',
|
||||
reExportDir,
|
||||
internalImport: moduleName,
|
||||
externalImport: `${packageJson.name}/${reExportDir}/${moduleName}`,
|
||||
hostPackageName: packageJson.name,
|
||||
versionRange: getPackageVersionRange(packageJson, packageName)
|
||||
};
|
||||
}),
|
||||
...reExportsEqual.map<ReExportEqual>(pattern => {
|
||||
const [moduleName, exportNamespace = moduleName] = pattern.split(' as ', 2);
|
||||
if (!/^[a-zA-Z_]\w/.test(exportNamespace)) {
|
||||
console.warn(`"${exportNamespace}" is not a valid namespace (module: ${moduleName})`);
|
||||
}
|
||||
const [packageName, subModuleName] = parseModule(moduleName);
|
||||
return {
|
||||
moduleName,
|
||||
packageName,
|
||||
subModuleName,
|
||||
exportNamespace,
|
||||
reExportStyle: '=',
|
||||
reExportDir,
|
||||
internalImport: moduleName,
|
||||
externalImport: `${packageJson.name}/${reExportDir}/${moduleName}`,
|
||||
hostPackageName: packageJson.name,
|
||||
versionRange: getPackageVersionRange(packageJson, packageName),
|
||||
};
|
||||
})
|
||||
];
|
||||
}
|
||||
|
||||
export function getPackageVersionRange(packageJson: PackageJson, packageName: string): string {
|
||||
const range = packageJson.dependencies?.[packageName]
|
||||
|| packageJson.optionalDependencies?.[packageName]
|
||||
|| packageJson.peerDependencies?.[packageName];
|
||||
if (!range) {
|
||||
throw new Error(`package not found: ${packageName}`);
|
||||
}
|
||||
return range;
|
||||
}
|
||||
|
||||
export type ReExport = ReExportStar | ReExportEqual;
|
||||
|
||||
export interface ReExportInfo {
|
||||
/**
|
||||
* The full name of the module. e.g. '@some/dep/nested/file'
|
||||
*/
|
||||
moduleName: string
|
||||
/**
|
||||
* Name of the package the re-export is from. e.g. '@some/dep' in '@some/dep/nested/file'
|
||||
*/
|
||||
packageName: string
|
||||
/**
|
||||
* Name of the file within the package. e.g. 'nested/file' in '@some/dep/nested/file'
|
||||
*/
|
||||
subModuleName?: string
|
||||
/**
|
||||
* Name/path of the directory where the re-exports should be located.
|
||||
*/
|
||||
reExportDir: string
|
||||
/**
|
||||
* Import statement used internally for the re-export.
|
||||
*/
|
||||
internalImport: string
|
||||
/**
|
||||
* Import name dependents should use externally for the re-export.
|
||||
*/
|
||||
externalImport: string
|
||||
/**
|
||||
* Name of the package that depends on the re-export.
|
||||
*/
|
||||
hostPackageName: string
|
||||
/**
|
||||
* Version range defined by the host package depending on the re-export.
|
||||
*/
|
||||
versionRange: string
|
||||
}
|
||||
|
||||
export interface ReExportStar extends ReExportInfo {
|
||||
reExportStyle: '*'
|
||||
}
|
||||
|
||||
export interface ReExportEqual extends ReExportInfo {
|
||||
reExportStyle: '='
|
||||
/**
|
||||
* Pretty name for the re-exported namespace. e.g. 'react-dom' as 'ReactDOM'
|
||||
*/
|
||||
exportNamespace: string
|
||||
}
|
||||
|
||||
export class PackageReExports {
|
||||
|
||||
static async FromPackage(packageName: string): Promise<PackageReExports> {
|
||||
const [packageJsonPath, packageJson] = await readPackageJson(packageName);
|
||||
const [packageRoot, reExports] = await parsePackageReExports(packageJsonPath, packageJson);
|
||||
return new PackageReExports(packageName, packageRoot, reExports);
|
||||
}
|
||||
|
||||
static FromPackageSync(packageName: string): PackageReExports {
|
||||
// Some tools (e.g. eslint) don't support async operations.
|
||||
// To get around this, we can spawn a sub NodeJS process that will run the asynchronous
|
||||
// logic and then synchronously wait for the serialized result on the standard output.
|
||||
const scriptPath = require.resolve('./bin-package-re-exports-from-package.js');
|
||||
const { stdout } = cp.spawnSync(process.platform === 'win32' ? `"${process.argv[0]}"` : process.argv[0], [...process.execArgv, scriptPath, packageName], {
|
||||
env: {
|
||||
ELECTRON_RUN_AS_NODE: '1'
|
||||
},
|
||||
encoding: 'utf8',
|
||||
stdio: ['ignore', 'pipe', 'inherit'],
|
||||
shell: true
|
||||
});
|
||||
const [packageRoot, reExports] = JSON.parse(stdout) as [string, ReExport[]];
|
||||
return new PackageReExports(packageName, packageRoot, reExports);
|
||||
}
|
||||
|
||||
constructor(
|
||||
readonly packageName: string,
|
||||
readonly packageRoot: string,
|
||||
readonly all: readonly Readonly<ReExport>[]
|
||||
) { }
|
||||
|
||||
findReExportByModuleName(moduleName: string): ReExport | undefined {
|
||||
return this.all.find(reExport => reExport.moduleName === moduleName);
|
||||
}
|
||||
|
||||
findReExportsByPackageName(packageName: string): ReExport[] {
|
||||
return this.all.filter(reExport => reExport.packageName === packageName);
|
||||
}
|
||||
|
||||
resolvePath(...parts: string[]): string {
|
||||
return path.resolve(this.packageRoot, ...parts);
|
||||
}
|
||||
}
|
||||
41
dev-packages/private-re-exports/src/utility.spec.ts
Normal file
41
dev-packages/private-re-exports/src/utility.spec.ts
Normal file
@@ -0,0 +1,41 @@
|
||||
// *****************************************************************************
|
||||
// Copyright (C) 2022 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
|
||||
// *****************************************************************************
|
||||
|
||||
import { parseModule } from './utility';
|
||||
import { expect } from 'chai';
|
||||
|
||||
describe('@theia/re-exports/lib/utility.js', () => {
|
||||
|
||||
it('parseModule', () => {
|
||||
expect(parseModule('a')).length(1).members(['a']);
|
||||
expect(parseModule('a/')).length(1).members(['a']);
|
||||
expect(parseModule('a/b')).length(2).members(['a', 'b']);
|
||||
expect(parseModule('a/b/')).length(2).members(['a', 'b']);
|
||||
expect(parseModule('a/b/c/d/e/f')).length(2).members(['a', 'b/c/d/e/f']);
|
||||
});
|
||||
|
||||
it('parseModule with namespaced package', () => {
|
||||
expect(parseModule('@a/b')).length(1).members(['@a/b']);
|
||||
expect(parseModule('@a/b/')).length(1).members(['@a/b']);
|
||||
expect(parseModule('@a/b/c')).length(2).members(['@a/b', 'c']);
|
||||
expect(parseModule('@a/b/c/')).length(2).members(['@a/b', 'c']);
|
||||
expect(parseModule('@a/b/c/d/e/f')).length(2).members(['@a/b', 'c/d/e/f']);
|
||||
});
|
||||
|
||||
it('parseModule unexpected module name/format', () => {
|
||||
expect(() => parseModule('@a')).throw();
|
||||
});
|
||||
});
|
||||
54
dev-packages/private-re-exports/src/utility.ts
Normal file
54
dev-packages/private-re-exports/src/utility.ts
Normal file
@@ -0,0 +1,54 @@
|
||||
// *****************************************************************************
|
||||
// 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
|
||||
// *****************************************************************************
|
||||
|
||||
export interface PackageJson {
|
||||
name: string
|
||||
dependencies?: Record<string, string>
|
||||
peerDependencies?: Record<string, string>
|
||||
optionalDependencies?: Record<string, string>
|
||||
theiaReExports?: Record<string, ReExportJson>
|
||||
}
|
||||
|
||||
/**
|
||||
* Raw re-export declaration as written in `package.json#theiaReExports[<destination>]`.
|
||||
*/
|
||||
export interface ReExportJson {
|
||||
'export *'?: string[]
|
||||
'export ='?: string[]
|
||||
copy?: string
|
||||
}
|
||||
|
||||
/**
|
||||
* Examples:
|
||||
* - `a` => `['a']`
|
||||
* - `a/b/c/...` => `['a', 'b/c/...']`
|
||||
* - `@a/b` => `['@a/b']`
|
||||
* - `@a/b/c/...` => `['@a/b', 'c/...']`
|
||||
*/
|
||||
export function parseModule(moduleName: string): [string, string?] {
|
||||
const slice = moduleName.startsWith('@') ? 2 : 1;
|
||||
const split = moduleName.split('/').filter(part => part.trim().length > 0);
|
||||
if (split.length < slice) {
|
||||
throw new Error(`Unexpected module name/format: ${JSON.stringify(moduleName)}`);
|
||||
}
|
||||
const packageName = split.slice(0, slice).join('/');
|
||||
if (split.length === slice) {
|
||||
return [packageName];
|
||||
} else {
|
||||
const subModuleName = split.slice(slice).join('/');
|
||||
return [packageName, subModuleName];
|
||||
}
|
||||
}
|
||||
12
dev-packages/private-re-exports/tsconfig.json
Normal file
12
dev-packages/private-re-exports/tsconfig.json
Normal file
@@ -0,0 +1,12 @@
|
||||
{
|
||||
"extends": "../../configs/base.tsconfig",
|
||||
"compilerOptions": {
|
||||
"composite": true,
|
||||
"rootDir": "src",
|
||||
"outDir": "lib"
|
||||
},
|
||||
"include": [
|
||||
"src"
|
||||
],
|
||||
"references": []
|
||||
}
|
||||
Reference in New Issue
Block a user