From 34697f3ef5883392e38fa7e25c9bed092fd87ed8 Mon Sep 17 00:00:00 2001 From: Xc Date: Mon, 18 Aug 2025 15:06:03 +0800 Subject: [PATCH] =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E4=BA=86i18n=E7=9B=B8?= =?UTF-8?q?=E5=BA=94=E7=9A=84routine?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/AppLoader.js | 27 +++++------- lib/routines/i18n.d.ts | 15 +++++++ lib/routines/i18n.js | 78 +++++++++++++++++++++++++++++++++++ lib/utils/requirePrj.d.ts | 1 + lib/utils/requirePrj.js | 23 +++++++++++ src/AppLoader.ts | 33 +++++---------- src/routines/i18n.ts | 87 +++++++++++++++++++++++++++++++++++++++ src/utils/requirePrj.ts | 27 ++++++++++++ 8 files changed, 253 insertions(+), 38 deletions(-) create mode 100644 lib/routines/i18n.d.ts create mode 100644 lib/routines/i18n.js create mode 100644 lib/utils/requirePrj.d.ts create mode 100644 lib/utils/requirePrj.js create mode 100644 src/routines/i18n.ts create mode 100644 src/utils/requirePrj.ts diff --git a/lib/AppLoader.js b/lib/AppLoader.js index 5655adb..723eb2f 100644 --- a/lib/AppLoader.js +++ b/lib/AppLoader.js @@ -17,6 +17,7 @@ const DataSubscriber_1 = tslib_1.__importDefault(require("./cluster/DataSubscrib const env_1 = require("./cluster/env"); const Synchronizer_1 = tslib_1.__importDefault(require("./Synchronizer")); const i18n_1 = tslib_1.__importDefault(require("oak-domain/lib/data/i18n")); +const requirePrj_1 = tslib_1.__importDefault(require("./utils/requirePrj")); class AppLoader extends types_1.AppLoader { dbStore; aspectDict; @@ -28,21 +29,7 @@ class AppLoader extends types_1.AppLoader { watcherTimerId; scheduledJobs = {}; requireSth(filePath) { - const depFilePath = (0, path_1.join)(this.path, filePath); - let sth; - if ((0, fs_1.existsSync)(`${depFilePath}.js`)) { - sth = require((0, path_1.join)(this.path, filePath)).default; - } - const sthExternal = this.externalDependencies.map(ele => { - const depFilePath = (0, path_1.join)(this.path, 'node_modules', ele, filePath); - if ((0, fs_1.existsSync)(`${depFilePath}.js`)) { - return require(depFilePath).default; - } - }).filter(ele => !!ele); - if (sth) { - sthExternal.push(sth); - } - return (0, lodash_1.mergeConcatMany)(sthExternal); + return (0, requirePrj_1.default)(this.path, filePath, this.externalDependencies); } async makeContext(cxtStr, headers) { const context = this.contextBuilder(this.dbStore); @@ -506,7 +493,15 @@ class AppLoader extends types_1.AppLoader { } async execRoutine(routine) { const context = await this.makeContext(); - await routine(context); + try { + const result = await routine(context); + await context.commit(); + return result; + } + catch (e) { + await context.rollback(); + throw e; + } } } exports.AppLoader = AppLoader; diff --git a/lib/routines/i18n.d.ts b/lib/routines/i18n.d.ts new file mode 100644 index 0000000..1a76374 --- /dev/null +++ b/lib/routines/i18n.d.ts @@ -0,0 +1,15 @@ +import { EntityDict } from 'oak-domain/lib/types'; +import { EntityDict as BaseEntityDict } from 'oak-domain/lib/base-app-domain'; +import { AsyncContext } from 'oak-domain/lib/store/AsyncRowStore'; +/** + * 检查项目目录下的i18n数据和数据库中的差异 + * @param context + * @returns + */ +export declare function checkI18n>(context: Cxt): Promise<(void | Awaited>)[]>; +/** + * 检查项目目录下的i18n数据和数据库中的差异,并更新 + * @param context + * @returns + */ +export declare function checkAndUpdateI18n>(context: Cxt): Promise<(void | Awaited>)[]>; diff --git a/lib/routines/i18n.js b/lib/routines/i18n.js new file mode 100644 index 0000000..e396e0c --- /dev/null +++ b/lib/routines/i18n.js @@ -0,0 +1,78 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.checkAndUpdateI18n = exports.checkI18n = void 0; +const tslib_1 = require("tslib"); +const node_path_1 = require("node:path"); +const requirePrj_1 = tslib_1.__importDefault(require("../utils/requirePrj")); +const dependencyBuilder_1 = require("oak-domain/lib/compiler/dependencyBuilder"); +const node_assert_1 = tslib_1.__importDefault(require("node:assert")); +const lodash_1 = require("lodash"); +const uuid_1 = require("oak-domain/lib/utils/uuid"); +async function checkAndUpdateI18nInner(context, onlyCheck) { + const pwd = process.cwd(); + const i18nData = (0, requirePrj_1.default)(pwd, (0, node_path_1.join)('lib', 'data', 'i18n'), (0, dependencyBuilder_1.analyzeDepedency)(pwd).ascOrder); + const originI18nData = await context.select('i18n', { + data: { + id: 1, + namespace: 1, + language: 1, + module: 1, + position: 1, + data: 1, + }, + }, { dontCollect: true }); + const originDataDict = {}; + originI18nData.forEach((data) => originDataDict[data.id] = data); + const result = i18nData.map(async (i18n) => { + const { id, namespace, language, module, position, data } = i18n; + const origin = originDataDict[id]; + if (origin) { + (0, node_assert_1.default)(namespace === origin.namespace && language === origin.language && module === origin.module && position === origin.position); + if (!(0, lodash_1.isEqual)(data, origin.data)) { + console.log(`[${namespace}]数据${onlyCheck ? '需要更新' : '将被更新'}`); + if (!onlyCheck) { + return context.operate('i18n', { + id: await (0, uuid_1.generateNewIdAsync)(), + action: 'update', + data: { + data, + }, + filter: { + id, + }, + }, {}); + } + } + } + else { + console.log(`[${namespace}]数据${onlyCheck ? '需要新建' : '将被新建'}`); + if (!onlyCheck) { + return context.operate('i18n', { + id: await (0, uuid_1.generateNewIdAsync)(), + action: 'create', + data: i18n, + }, {}); + } + } + return Promise.resolve(); + }); + return await Promise.all(result); +} +/** + * 检查项目目录下的i18n数据和数据库中的差异 + * @param context + * @returns + */ +function checkI18n(context) { + return checkAndUpdateI18nInner(context, true); +} +exports.checkI18n = checkI18n; +/** + * 检查项目目录下的i18n数据和数据库中的差异,并更新 + * @param context + * @returns + */ +function checkAndUpdateI18n(context) { + return checkAndUpdateI18nInner(context); +} +exports.checkAndUpdateI18n = checkAndUpdateI18n; diff --git a/lib/utils/requirePrj.d.ts b/lib/utils/requirePrj.d.ts new file mode 100644 index 0000000..feaa3e8 --- /dev/null +++ b/lib/utils/requirePrj.d.ts @@ -0,0 +1 @@ +export default function requireSth(prjPath: string, filePath: string, dependencies: string[]): any; diff --git a/lib/utils/requirePrj.js b/lib/utils/requirePrj.js new file mode 100644 index 0000000..df6a041 --- /dev/null +++ b/lib/utils/requirePrj.js @@ -0,0 +1,23 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +const fs_1 = require("fs"); +const lodash_1 = require("oak-domain/lib/utils/lodash"); +const path_1 = require("path"); +function requireSth(prjPath, filePath, dependencies) { + const depFilePath = (0, path_1.join)(prjPath, filePath); + let sth; + if ((0, fs_1.existsSync)(`${depFilePath}.js`)) { + sth = require((0, path_1.join)(prjPath, filePath)).default; + } + const sthExternal = dependencies.map(ele => { + const depFilePath = (0, path_1.join)(prjPath, 'node_modules', ele, filePath); + if ((0, fs_1.existsSync)(`${depFilePath}.js`)) { + return require(depFilePath).default; + } + }).filter(ele => !!ele); + if (sth) { + sthExternal.push(sth); + } + return (0, lodash_1.mergeConcatMany)(sthExternal); +} +exports.default = requireSth; diff --git a/src/AppLoader.ts b/src/AppLoader.ts index fc3bb30..46145ed 100644 --- a/src/AppLoader.ts +++ b/src/AppLoader.ts @@ -21,6 +21,7 @@ import { getClusterInfo } from './cluster/env'; import Synchronizer from './Synchronizer'; import { AsyncContext } from 'oak-domain/lib/store/AsyncRowStore'; import domainI18nData from 'oak-domain/lib/data/i18n'; +import requireSth from './utils/requirePrj'; export class AppLoader> extends GeneralAppLoader { protected dbStore: DbStore; @@ -34,27 +35,7 @@ export class AppLoader = {}; private requireSth(filePath: string): any { - const depFilePath = join(this.path, filePath); - let sth: any; - if (existsSync(`${depFilePath}.js`)) { - sth = require(join(this.path, filePath)).default; - } - const sthExternal = this.externalDependencies.map( - ele => { - const depFilePath = join(this.path, 'node_modules', ele, filePath); - if (existsSync(`${depFilePath}.js`)) { - return require(depFilePath).default - } - } - ).filter( - ele => !!ele - ); - - if (sth) { - sthExternal.push(sth); - } - - return mergeConcatMany(sthExternal); + return requireSth(this.path, filePath, this.externalDependencies); } protected async makeContext(cxtStr?: string, headers?: IncomingHttpHeaders) { @@ -595,6 +576,14 @@ export class AppLoader>(context: Cxt) => Promise) { const context = await this.makeContext(); - await routine(context); + try { + const result = await routine(context); + await context.commit(); + return result; + } + catch(e: any) { + await context.rollback(); + throw e; + } } } \ No newline at end of file diff --git a/src/routines/i18n.ts b/src/routines/i18n.ts new file mode 100644 index 0000000..464ff26 --- /dev/null +++ b/src/routines/i18n.ts @@ -0,0 +1,87 @@ +import { EntityDict } from 'oak-domain/lib/types'; +import { EntityDict as BaseEntityDict } from 'oak-domain/lib/base-app-domain'; +import { AsyncContext } from 'oak-domain/lib/store/AsyncRowStore'; +import { join } from 'node:path'; +import requireSth from '../utils/requirePrj'; +import { analyzeDepedency } from 'oak-domain/lib/compiler/dependencyBuilder'; +import assert from 'node:assert'; +import { isEqual } from 'lodash'; +import { generateNewIdAsync } from 'oak-domain/lib/utils/uuid'; + +async function checkAndUpdateI18nInner>(context: Cxt, onlyCheck?: true) { + const pwd = process.cwd(); + const i18nData = requireSth(pwd, join('lib', 'data', 'i18n'), analyzeDepedency(pwd).ascOrder) as BaseEntityDict['i18n']['OpSchema'][]; + + const originI18nData = await context.select('i18n', { + data: { + id: 1, + namespace: 1, + language: 1, + module: 1, + position: 1, + data: 1, + }, + }, { dontCollect: true }); + + const originDataDict: Record = {}; + originI18nData.forEach( + (data) => originDataDict[data.id!] = data as BaseEntityDict['i18n']['OpSchema'] + ); + + const result = i18nData.map( + async (i18n) => { + const { id, namespace, language, module, position, data } = i18n; + const origin = originDataDict[id]; + + if (origin) { + assert(namespace === origin.namespace && language === origin.language && module === origin.module && position === origin.position); + if (!isEqual(data, origin.data)) { + console.log(`[${namespace}]数据${onlyCheck ? '需要更新' : '将被更新'}`); + if (!onlyCheck) { + return context.operate('i18n', { + id: await generateNewIdAsync(), + action: 'update', + data: { + data, + }, + filter: { + id, + }, + }, {}); + } + } + } + else { + console.log(`[${namespace}]数据${onlyCheck ? '需要新建' : '将被新建'}`); + if (!onlyCheck) { + return context.operate('i18n', { + id: await generateNewIdAsync(), + action: 'create', + data: i18n, + }, {}); + } + } + return Promise.resolve(); + } + ); + + return await Promise.all(result); +} + +/** + * 检查项目目录下的i18n数据和数据库中的差异 + * @param context + * @returns + */ +export function checkI18n>(context: Cxt) { + return checkAndUpdateI18nInner(context, true); +} + +/** + * 检查项目目录下的i18n数据和数据库中的差异,并更新 + * @param context + * @returns + */ +export function checkAndUpdateI18n>(context: Cxt) { + return checkAndUpdateI18nInner(context); +} \ No newline at end of file diff --git a/src/utils/requirePrj.ts b/src/utils/requirePrj.ts new file mode 100644 index 0000000..7decd5b --- /dev/null +++ b/src/utils/requirePrj.ts @@ -0,0 +1,27 @@ +import { existsSync } from "fs"; +import { mergeConcatMany } from "oak-domain/lib/utils/lodash"; +import { join } from "path"; + +export default function requireSth(prjPath: string, filePath: string, dependencies: string[]) { + const depFilePath = join(prjPath, filePath); + let sth: any; + if (existsSync(`${depFilePath}.js`)) { + sth = require(join(prjPath, filePath)).default; + } + const sthExternal = dependencies.map( + ele => { + const depFilePath = join(prjPath, 'node_modules', ele, filePath); + if (existsSync(`${depFilePath}.js`)) { + return require(depFilePath).default + } + } + ).filter( + ele => !!ele + ); + + if (sth) { + sthExternal.push(sth); + } + + return mergeConcatMany(sthExternal); +} \ No newline at end of file