snapshot of https://github.com/dream-num/univer.git (dev, 2026-09-16; blobs > 131072B omitted)
Some checks failed
📦 Build / build (push) Has been cancelled
🧪 CI Test / test shard (1/4) (push) Has been cancelled
🧪 CI Test / test shard (2/4) (push) Has been cancelled
🧪 CI Test / test shard (3/4) (push) Has been cancelled
🧪 CI Test / test shard (4/4) (push) Has been cancelled
🧪 CI Test / test (push) Has been cancelled
🧪 CI Test / eslint (push) Has been cancelled
🧪 CI Test / typecheck (push) Has been cancelled
🔫 Sync to Pro / dispatch-sync (push) Has been cancelled
🔮 Sync Mirror / sync (push) Has been cancelled
Some checks failed
📦 Build / build (push) Has been cancelled
🧪 CI Test / test shard (1/4) (push) Has been cancelled
🧪 CI Test / test shard (2/4) (push) Has been cancelled
🧪 CI Test / test shard (3/4) (push) Has been cancelled
🧪 CI Test / test shard (4/4) (push) Has been cancelled
🧪 CI Test / test (push) Has been cancelled
🧪 CI Test / eslint (push) Has been cancelled
🧪 CI Test / typecheck (push) Has been cancelled
🔫 Sync to Pro / dispatch-sync (push) Has been cancelled
🔮 Sync Mirror / sync (push) Has been cancelled
This commit is contained in:
1
common/shared/preset-build/constants.ts
Normal file
1
common/shared/preset-build/constants.ts
Normal file
@@ -0,0 +1 @@
|
||||
export const PRESET_LOCALE_SOURCE_DIR = 'src/locales';
|
||||
49
common/shared/preset-build/entries.ts
Normal file
49
common/shared/preset-build/entries.ts
Normal file
@@ -0,0 +1,49 @@
|
||||
import type { IEntryConfig } from '../tsdown/types.ts';
|
||||
import { existsSync, readdirSync, statSync } from 'node:fs';
|
||||
import path from 'node:path';
|
||||
import { PRESET_LOCALE_SOURCE_DIR } from './constants.ts';
|
||||
|
||||
function getPresetLocaleEntries(packageDir: string): IEntryConfig[] {
|
||||
const localeDir = path.join(packageDir, PRESET_LOCALE_SOURCE_DIR);
|
||||
|
||||
if (!existsSync(localeDir)) {
|
||||
return [];
|
||||
}
|
||||
|
||||
const entries: IEntryConfig[] = [];
|
||||
|
||||
for (const fileName of readdirSync(localeDir).sort((left, right) => left.localeCompare(right))) {
|
||||
const fullPath = path.join(localeDir, fileName);
|
||||
|
||||
if (statSync(fullPath).isDirectory() || !fileName.endsWith('.ts') || !fileName.includes('-')) {
|
||||
continue;
|
||||
}
|
||||
|
||||
entries.push({
|
||||
key: `locales/${fileName.replace(/\.ts$/, '')}`,
|
||||
path: fullPath,
|
||||
type: 'locale',
|
||||
});
|
||||
}
|
||||
|
||||
return entries;
|
||||
}
|
||||
|
||||
export function getPresetModuleEntries(packageDir: string): IEntryConfig[] {
|
||||
const entries: IEntryConfig[] = [{
|
||||
key: 'index',
|
||||
path: path.join(packageDir, 'src/index.ts'),
|
||||
type: 'index',
|
||||
}];
|
||||
|
||||
const workerEntry = path.join(packageDir, 'src/worker.ts');
|
||||
if (existsSync(workerEntry)) {
|
||||
entries.push({
|
||||
key: 'worker',
|
||||
path: workerEntry,
|
||||
type: 'worker',
|
||||
});
|
||||
}
|
||||
|
||||
return [...entries, ...getPresetLocaleEntries(packageDir)];
|
||||
}
|
||||
130
common/shared/preset-build/index.ts
Normal file
130
common/shared/preset-build/index.ts
Normal file
@@ -0,0 +1,130 @@
|
||||
import type { TModuleFormat } from '../tsdown/configs/module.ts';
|
||||
import type { IPackageJson } from '../tsdown/types.ts';
|
||||
import type { IPresetBuildOptions, IPresetPackageJson } from './types.ts';
|
||||
import { existsSync, readFileSync, rmSync } from 'node:fs';
|
||||
import path from 'node:path';
|
||||
import process from 'node:process';
|
||||
import { pathToFileURL } from 'node:url';
|
||||
import { mergeConfig, build as tsdownBuild } from 'tsdown';
|
||||
import { createModuleConfig } from '../tsdown/configs/module.ts';
|
||||
import { BUILD_OUTPUT_DIRECTORIES, CLEANUP_DIRECTORIES } from '../tsdown/constants.ts';
|
||||
import { createBaseConfig, createInputPlugins } from '../tsdown/utils/base-config.ts';
|
||||
import { getPresetModuleEntries } from './entries.ts';
|
||||
import { generatePresetLocales } from './locale.ts';
|
||||
import { buildPresetStyles } from './style.ts';
|
||||
|
||||
export { generatePresetLocales } from './locale.ts';
|
||||
export type { IPresetBuildOptions } from './types.ts';
|
||||
|
||||
function readPackageJson(packageDir: string): IPresetPackageJson {
|
||||
return JSON.parse(readFileSync(path.join(packageDir, 'package.json'), 'utf8')) as IPresetPackageJson;
|
||||
}
|
||||
|
||||
function getExternalPackages(packageJson: IPresetPackageJson) {
|
||||
return [...new Set([
|
||||
...Object.keys(packageJson.dependencies ?? {}),
|
||||
...Object.keys(packageJson.peerDependencies ?? {}),
|
||||
'react',
|
||||
'react-dom',
|
||||
'rxjs',
|
||||
])]
|
||||
.sort((left, right) => left.localeCompare(right))
|
||||
.flatMap((packageName) => [packageName, `${packageName}/*`]);
|
||||
}
|
||||
|
||||
async function loadUserConfig(options: IPresetBuildOptions, packageDir: string) {
|
||||
if (!options.tsdownConfigPath) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const configPath = path.resolve(packageDir, options.tsdownConfigPath);
|
||||
let userConfig = (await import(pathToFileURL(configPath).href)).default;
|
||||
|
||||
if (typeof userConfig === 'function') {
|
||||
userConfig = await userConfig();
|
||||
}
|
||||
|
||||
return userConfig;
|
||||
}
|
||||
|
||||
function mergeUserConfig(configs: any[], userConfig: any) {
|
||||
if (!userConfig) {
|
||||
return configs;
|
||||
}
|
||||
|
||||
return configs.map((config) => mergeConfig(config, userConfig));
|
||||
}
|
||||
|
||||
export function createPresetModuleEntryGroups(entries: ReturnType<typeof getPresetModuleEntries>) {
|
||||
const primaryEntries = entries.filter((entry) => entry.type === 'index' || entry.type === 'locale');
|
||||
const isolatedEntries = entries.filter((entry) => entry.type !== 'index' && entry.type !== 'locale');
|
||||
|
||||
return [
|
||||
...(primaryEntries.length > 0 ? [primaryEntries] : []),
|
||||
...isolatedEntries.map((entry) => [entry]),
|
||||
];
|
||||
}
|
||||
|
||||
export function removePresetOutputs(packageDir = process.cwd()) {
|
||||
for (const dir of CLEANUP_DIRECTORIES) {
|
||||
const targetDir = path.resolve(packageDir, dir);
|
||||
|
||||
if (existsSync(targetDir)) {
|
||||
rmSync(targetDir, { force: true, recursive: true });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export function preparePresetPackage(packageDir = process.cwd()) {
|
||||
const packageJson = readPackageJson(packageDir);
|
||||
|
||||
if (packageJson.name === '@univerjs/presets') {
|
||||
return [];
|
||||
}
|
||||
|
||||
return generatePresetLocales({ packageDir });
|
||||
}
|
||||
|
||||
export async function buildPresetPackage(options: IPresetBuildOptions = {}) {
|
||||
const packageDir = process.cwd();
|
||||
const packageJson = readPackageJson(packageDir);
|
||||
|
||||
if (options.cleanup) {
|
||||
removePresetOutputs(packageDir);
|
||||
}
|
||||
|
||||
const externalPackages = getExternalPackages(packageJson);
|
||||
const baseConfig = createBaseConfig({
|
||||
entries: [],
|
||||
externalPackages,
|
||||
facadeExternalPackages: externalPackages,
|
||||
packageDir,
|
||||
packageJson: packageJson as IPackageJson,
|
||||
plugins: [],
|
||||
});
|
||||
const plugins = createInputPlugins(packageDir);
|
||||
const userConfig = await loadUserConfig(options, packageDir);
|
||||
const moduleFormats: TModuleFormat[] = ['esm', 'cjs'];
|
||||
const moduleConfigs = createPresetModuleEntryGroups(getPresetModuleEntries(packageDir)).flatMap((entries) => {
|
||||
return moduleFormats.map((format) => createModuleConfig({
|
||||
baseConfig,
|
||||
enableObfuscation: false,
|
||||
entries,
|
||||
externalPackages,
|
||||
facadeExternalPackages: externalPackages,
|
||||
format,
|
||||
outDir: BUILD_OUTPUT_DIRECTORIES[format],
|
||||
packageDir,
|
||||
plugins,
|
||||
}));
|
||||
});
|
||||
|
||||
for (const config of mergeUserConfig(moduleConfigs, userConfig)) {
|
||||
await tsdownBuild(config);
|
||||
}
|
||||
|
||||
await buildPresetStyles({
|
||||
packageDir,
|
||||
packageJson,
|
||||
});
|
||||
}
|
||||
98
common/shared/preset-build/locale.ts
Normal file
98
common/shared/preset-build/locale.ts
Normal file
@@ -0,0 +1,98 @@
|
||||
import type { IGeneratePresetLocalesOptions, IPresetPackageJson } from './types.ts';
|
||||
import { existsSync, mkdirSync, readFileSync, rmSync, writeFileSync } from 'node:fs';
|
||||
import path from 'node:path';
|
||||
import { discoverUniverUiLocales } from '../locale/index.ts';
|
||||
import { PRESET_LOCALE_SOURCE_DIR } from './constants.ts';
|
||||
|
||||
function readPackageJson(packageDir: string): IPresetPackageJson {
|
||||
return JSON.parse(readFileSync(path.join(packageDir, 'package.json'), 'utf8')) as IPresetPackageJson;
|
||||
}
|
||||
|
||||
function convertImportNameFromPackageName(name: string) {
|
||||
return name
|
||||
.replace(/^@univerjs(?:-[^/]+)?\//, 'univerjs')
|
||||
.replace(/[^a-zA-Z0-9_$]/g, '');
|
||||
}
|
||||
|
||||
function compareStrings(left: string, right: string) {
|
||||
if (left < right) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (left > right) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
function getDependencyNames(pkg: IPresetPackageJson) {
|
||||
return Object.keys(pkg.dependencies ?? {})
|
||||
.filter((name) => name.startsWith('@univerjs'))
|
||||
.sort(compareStrings);
|
||||
}
|
||||
|
||||
function getDependencyLocaleSubpath(packageDir: string, dependencyName: string, locale: string) {
|
||||
const dependencyDir = path.join(packageDir, 'node_modules', dependencyName);
|
||||
|
||||
if (
|
||||
existsSync(path.join(dependencyDir, 'lib/es/locale', `${locale}.js`))
|
||||
|| existsSync(path.join(dependencyDir, 'src/locale', `${locale}.ts`))
|
||||
) {
|
||||
return 'locale';
|
||||
}
|
||||
|
||||
if (
|
||||
existsSync(path.join(dependencyDir, 'lib/es/locales', `${locale}.js`))
|
||||
|| existsSync(path.join(dependencyDir, 'src/locales', `${locale}.ts`))
|
||||
) {
|
||||
return 'locales';
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
export function generatePresetLocales(options: IGeneratePresetLocalesOptions): string[] {
|
||||
const { packageDir } = options;
|
||||
const pkg = readPackageJson(packageDir);
|
||||
const dependencyNames = getDependencyNames(pkg);
|
||||
const localeDir = path.join(packageDir, PRESET_LOCALE_SOURCE_DIR);
|
||||
|
||||
rmSync(localeDir, { force: true, recursive: true });
|
||||
mkdirSync(localeDir, { recursive: true });
|
||||
|
||||
const generated: string[] = [];
|
||||
|
||||
for (const locale of discoverUniverUiLocales({ rootDir: packageDir })) {
|
||||
const dependenciesWithLocale = dependencyNames
|
||||
.map((dependencyName) => ({
|
||||
dependencyName,
|
||||
localeSubpath: getDependencyLocaleSubpath(packageDir, dependencyName, locale),
|
||||
}))
|
||||
.filter((dependency): dependency is { dependencyName: string; localeSubpath: 'locale' | 'locales' } => dependency.localeSubpath !== null);
|
||||
|
||||
if (dependenciesWithLocale.length === 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
let content = '';
|
||||
|
||||
for (const { dependencyName, localeSubpath } of dependenciesWithLocale) {
|
||||
content += `import ${convertImportNameFromPackageName(dependencyName)} from '${dependencyName}/${localeSubpath}/${locale}';\n`;
|
||||
}
|
||||
|
||||
content += '\nexport default Object.assign(\n';
|
||||
content += ' {},\n';
|
||||
|
||||
for (const { dependencyName } of dependenciesWithLocale) {
|
||||
content += ` ${convertImportNameFromPackageName(dependencyName)},\n`;
|
||||
}
|
||||
|
||||
content += ');\n';
|
||||
|
||||
writeFileSync(path.join(localeDir, `${locale}.ts`), content);
|
||||
generated.push(locale);
|
||||
}
|
||||
|
||||
return generated;
|
||||
}
|
||||
58
common/shared/preset-build/style.ts
Normal file
58
common/shared/preset-build/style.ts
Normal file
@@ -0,0 +1,58 @@
|
||||
import type { IPresetPackageJson } from './types.ts';
|
||||
import { existsSync, mkdirSync, readFileSync, rmSync, writeFileSync } from 'node:fs';
|
||||
import path from 'node:path';
|
||||
|
||||
function getDependencyDir(packageDir: string, dependencyName: string) {
|
||||
return path.join(packageDir, 'node_modules', dependencyName);
|
||||
}
|
||||
|
||||
function getBuiltStyleDependencyCssFiles(packageDir: string, packageJson: IPresetPackageJson) {
|
||||
return Object.keys(packageJson.dependencies ?? {})
|
||||
.flatMap((dependencyName) => {
|
||||
if (!dependencyName.startsWith('@univerjs')) {
|
||||
return [];
|
||||
}
|
||||
|
||||
const dependencyDir = getDependencyDir(packageDir, dependencyName);
|
||||
const sourceGlobalCss = path.join(dependencyDir, 'src/global.css');
|
||||
const builtCss = path.join(dependencyDir, 'lib/index.css');
|
||||
|
||||
if (!existsSync(sourceGlobalCss)) {
|
||||
return [];
|
||||
}
|
||||
|
||||
if (!existsSync(builtCss)) {
|
||||
throw new Error(`Missing built CSS for ${dependencyName}. Build dependency packages before building preset CSS.`);
|
||||
}
|
||||
|
||||
return [builtCss];
|
||||
});
|
||||
}
|
||||
|
||||
function writePresetCss(packageDir: string, cssFiles: string[]) {
|
||||
const outputFile = path.join(packageDir, 'lib/index.css');
|
||||
|
||||
mkdirSync(path.dirname(outputFile), { recursive: true });
|
||||
|
||||
const content = cssFiles
|
||||
.map((cssFile) => readFileSync(cssFile, 'utf8').trimEnd())
|
||||
.filter(Boolean)
|
||||
.join('\n');
|
||||
|
||||
writeFileSync(outputFile, `${content}\n`);
|
||||
}
|
||||
|
||||
export async function buildPresetStyles(options: {
|
||||
packageDir: string;
|
||||
packageJson: IPresetPackageJson;
|
||||
}) {
|
||||
const { packageDir, packageJson } = options;
|
||||
const cssFiles = getBuiltStyleDependencyCssFiles(packageDir, packageJson);
|
||||
|
||||
if (cssFiles.length === 0) {
|
||||
rmSync(path.join(packageDir, 'lib/index.css'), { force: true });
|
||||
return;
|
||||
}
|
||||
|
||||
writePresetCss(packageDir, cssFiles);
|
||||
}
|
||||
15
common/shared/preset-build/types.ts
Normal file
15
common/shared/preset-build/types.ts
Normal file
@@ -0,0 +1,15 @@
|
||||
export interface IPresetBuildOptions {
|
||||
cleanup?: boolean;
|
||||
tsdownConfigPath?: string;
|
||||
}
|
||||
|
||||
export interface IPresetPackageJson {
|
||||
dependencies?: Record<string, string>;
|
||||
devDependencies?: Record<string, string>;
|
||||
name: string;
|
||||
peerDependencies?: Record<string, string>;
|
||||
}
|
||||
|
||||
export interface IGeneratePresetLocalesOptions {
|
||||
packageDir: string;
|
||||
}
|
||||
Reference in New Issue
Block a user