mirror of
https://github.com/trezor/trezor-suite.git
synced 2026-02-19 16:22:25 +01:00
168 lines
6.6 KiB
TypeScript
168 lines
6.6 KiB
TypeScript
import chalk from 'chalk';
|
|
import { minimatch } from 'minimatch';
|
|
import fs from 'node:fs';
|
|
import path from 'node:path';
|
|
import prettier from 'prettier';
|
|
import yargs from 'yargs';
|
|
import { hideBin } from 'yargs/helpers';
|
|
|
|
import { getPrettierConfig } from './utils/getPrettierConfig';
|
|
import { getWorkspacesList } from './utils/getWorkspacesList';
|
|
|
|
/**
|
|
* Example usage:
|
|
* yarn update-project-references --read-only 1 2 3 --test true
|
|
* yarn update-project-references --ignore *\/firmware
|
|
*/
|
|
(async () => {
|
|
const { argv } = yargs(hideBin(process.argv))
|
|
.array('read-only')
|
|
.array('ignore')
|
|
.boolean('test') as any;
|
|
|
|
const readOnlyGlobs: string[] = argv.readOnly || [];
|
|
const ignoreGlobs: string[] = argv.ignore || [];
|
|
|
|
const isTesting = argv.test || false;
|
|
|
|
const prettierConfig = await getPrettierConfig();
|
|
|
|
const serializeConfig = (config: any, stringifySpaces?: number) => {
|
|
try {
|
|
return prettier.format(
|
|
JSON.stringify(config, null, stringifySpaces).replace(/\\\\/g, '/'),
|
|
prettierConfig,
|
|
);
|
|
} catch (error) {
|
|
console.error(error);
|
|
process.exit(1);
|
|
}
|
|
};
|
|
|
|
const parseTSConfigFile = (configPath: string) => {
|
|
try {
|
|
return fs.existsSync(configPath)
|
|
? JSON.parse(fs.readFileSync(configPath).toString())
|
|
: null;
|
|
} catch {
|
|
console.error(chalk.bold.red('Error while parsing file: '), configPath);
|
|
process.exit(1);
|
|
}
|
|
};
|
|
|
|
const isDiffInConfig = async (actualConfig: any[] = [], expectedConfig: any[] = []) =>
|
|
(await serializeConfig(actualConfig)) !== (await serializeConfig(expectedConfig));
|
|
|
|
const workspaces = getWorkspacesList();
|
|
|
|
// NOTE: Workspace keys must be sorted due to file systems being a part of the equation...
|
|
Object.keys(workspaces)
|
|
.sort()
|
|
.forEach(async workspaceName => {
|
|
const workspace = workspaces[workspaceName];
|
|
|
|
if (workspace.location === '.') {
|
|
// Skip root workspace
|
|
return;
|
|
}
|
|
|
|
if (ignoreGlobs.some((path: string) => minimatch(workspace.location, path))) {
|
|
return;
|
|
}
|
|
|
|
const workspacePath = path.resolve(process.cwd(), workspace.location);
|
|
const workspaceConfigPath = path.resolve(workspacePath, 'tsconfig.json');
|
|
const workspaceLibConfigPath = path.resolve(workspacePath, 'tsconfig.lib.json');
|
|
const workspaceLibESMConfigPath = path.resolve(workspacePath, 'tsconfig.libESM.json');
|
|
|
|
const defaultWorkspaceConfig = {
|
|
extends: path.relative(workspacePath, path.resolve(process.cwd(), 'tsconfig.json')),
|
|
compilerOptions: { outDir: './libDev' },
|
|
include: ['.'],
|
|
};
|
|
|
|
// parse tsconfig.json, which should exist, so if it doesn't, assign default config to have it created
|
|
const workspaceConfig =
|
|
parseTSConfigFile(workspaceConfigPath) ?? defaultWorkspaceConfig;
|
|
|
|
// parse tsconfig.lib.json, which may not exist, and shall not be created
|
|
const workspaceLibConfig = parseTSConfigFile(workspaceLibConfigPath);
|
|
|
|
// parse tsconfig.libESM.json, which may not exist, and shall not be created
|
|
const workspaceLibESMConfig = parseTSConfigFile(workspaceLibESMConfigPath);
|
|
|
|
// actual references of the workspace from parsed package.json (assigned later)
|
|
const nextWorkspaceReferences: Array<{ path: string }> = [];
|
|
|
|
Object.values(workspace.workspaceDependencies).forEach(dependencyLocation => {
|
|
const dependencyPath = path.resolve(process.cwd(), dependencyLocation);
|
|
const relativeDependencyPath = path.relative(workspacePath, dependencyPath);
|
|
|
|
if (relativeDependencyPath) {
|
|
nextWorkspaceReferences.push({ path: relativeDependencyPath });
|
|
} else {
|
|
console.warn(
|
|
chalk.yellow(
|
|
`${dependencyLocation} might be referencing itself in package.json#dependencies.`,
|
|
),
|
|
);
|
|
}
|
|
});
|
|
|
|
const expectedReferences = nextWorkspaceReferences;
|
|
const expectedLibReferences = nextWorkspaceReferences.filter(
|
|
// Don't include reference to schema-utils due to issues with the @sinclair/typebox library
|
|
// When using a reference it results in incorrect imports
|
|
({ path }) => path !== '../schema-utils',
|
|
);
|
|
|
|
if (isTesting) {
|
|
const isConfigDiff = await isDiffInConfig(
|
|
workspaceConfig.references,
|
|
expectedReferences,
|
|
);
|
|
|
|
const isConfigLibDiff =
|
|
workspaceLibConfig !== null &&
|
|
(await isDiffInConfig(workspaceLibConfig.references, expectedLibReferences));
|
|
|
|
const isConfigLibESMDiff =
|
|
workspaceLibESMConfig !== null &&
|
|
(await isDiffInConfig(workspaceLibESMConfig.references, expectedLibReferences));
|
|
|
|
if (isConfigDiff || isConfigLibDiff || isConfigLibESMDiff) {
|
|
console.error(
|
|
chalk.red(
|
|
`TypeScript project references in ${workspace.location} are inconsistent with package.json#dependencies.`,
|
|
),
|
|
chalk.red.bold(`Run "yarn update-project-references" to fix them.`),
|
|
);
|
|
process.exit(1);
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
if (readOnlyGlobs.some((path: string) => minimatch(workspace.location, path))) return;
|
|
|
|
workspaceConfig.references = expectedReferences;
|
|
fs.writeFileSync(workspaceConfigPath, await serializeConfig(workspaceConfig));
|
|
|
|
if (workspaceLibConfig !== null) {
|
|
workspaceLibConfig.references = expectedLibReferences;
|
|
fs.writeFileSync(
|
|
workspaceLibConfigPath,
|
|
await serializeConfig(workspaceLibConfig, 2),
|
|
);
|
|
}
|
|
|
|
if (workspaceLibESMConfig !== null) {
|
|
workspaceLibESMConfig.references = expectedLibReferences;
|
|
fs.writeFileSync(
|
|
workspaceLibESMConfigPath,
|
|
await serializeConfig(workspaceLibESMConfig, 2),
|
|
);
|
|
}
|
|
});
|
|
})();
|