Files
AFFiNE-Mirror/tools/cli/src/init.ts
T

138 lines
3.6 KiB
TypeScript
Executable File

import { readFileSync, writeFileSync } from 'node:fs';
import type { Path } from '@affine-tools/utils/path';
import {
type Package,
Workspace,
yarnList,
} from '@affine-tools/utils/workspace';
import { applyEdits, modify } from 'jsonc-parser';
import { type BuiltInParserName, format } from 'prettier';
import { Command } from './command';
export class InitCommand extends Command {
static override paths = [['init'], ['i'], ['codegen']];
async execute() {
this.logger.info('Generating Workspace configs');
await this.generateWorkspaceFiles();
this.logger.info('Workspace configs generated');
}
async generateWorkspaceFiles() {
this.workspace = new Workspace(yarnList());
const filesToGenerate: [
Path,
(prev: string) => string,
BuiltInParserName?,
][] = [
[this.workspace.join('tsconfig.json'), this.genProjectTsConfig, 'json'],
[
this.workspace
.getPackage('@affine-tools/utils')
.join('src/workspace.gen.ts'),
this.genWorkspaceInfo,
'typescript',
],
[this.workspace.join('oxlint.json'), this.genOxlintConfig, 'json'],
...this.workspace.packages
.filter(p => p.isTsProject)
.map(
p =>
[
p.join('tsconfig.json'),
this.genPackageTsConfig.bind(this, p),
'json',
] as any
),
];
for (const [path, content, formatter] of filesToGenerate) {
this.logger.info(`Generating: ${path}`);
const previous = readFileSync(path.value, 'utf-8');
let file = content(previous);
if (formatter) {
file = await this.format(file, formatter);
}
writeFileSync(path.value, file);
}
}
format(content: string, parser: BuiltInParserName) {
const config = JSON.parse(
readFileSync(this.workspace.join('.prettierrc').value, 'utf-8')
);
return format(content, { parser, ...config });
}
genOxlintConfig = () => {
const json = JSON.parse(
readFileSync(this.workspace.join('oxlint.json').value, 'utf-8')
);
const ignoreList = readFileSync(
this.workspace.join('.prettierignore').value,
'utf-8'
)
.split('\n')
.filter(line => line.trim() && !line.startsWith('#'));
json['ignorePatterns'] = ignoreList;
return JSON.stringify(json, null, 2);
};
genWorkspaceInfo = () => {
const list = yarnList();
const names = list.map(p => p.name);
const content = [
'// Auto generated content',
'// DO NOT MODIFY THIS FILE MANUALLY',
`export const PackageList = ${JSON.stringify(list, null, 2)}`,
'',
`export type PackageName = ${names.map(n => `'${n}'`).join(' | ')}`,
];
return content.join('\n');
};
genProjectTsConfig = (prev: string) => {
return applyEdits(
prev,
modify(
prev,
['references'],
this.workspace.packages
.filter(p => p.isTsProject)
.map(p => ({ path: p.path.relativePath })),
{}
)
);
};
genPackageTsConfig = (pkg: Package, prev: string) => {
// TODO(@forehalo):
// currently electron-api => electron => nbstore => electron-api
// this is a circular dependency, we need to fix it
// basically, the electron app don't need to use nbstore for exposing js bridge apis
if (pkg.name === '@affine/electron-api') {
return prev;
}
return applyEdits(
prev,
modify(
prev,
['references'],
pkg.deps
.filter(p => p.isTsProject)
.map(d => ({ path: pkg.path.relative(d.path.value) })),
{}
)
);
};
}