in lib/generator.js [2033:2985]
visitObjectField(ast, level, env) {
let comments = DSL.comment.getFrontComments(this.comments, ast.tokenRange[0]);
this.visitComments(comments, level);
if (ast.type === 'objectField') {
var key = _name(ast.fieldName) || _string(ast.fieldName);
this.emit(`{"${key}", `, level);
this.visitObjectFieldValue(ast.expr, level, env);
} else if (ast.type === 'expandField') {
// // TODO: more cases
// this.emit(`...`, level);
// this.visitExpr(ast.expr, level);
} else {
throw new Error('unimpelemented');
}
this.emit('},\n');
}
visitObjectFieldValue(ast, level, env) {
this.visitExpr(ast, level, env);
}
visitPropertyAccess(ast, level, env) {
assert.equal(ast.type, 'property_access');
var id = _name(ast.id);
var expr = '';
if (id === '__response') {
expr += RESPONSE;
} else if (id === '__request') {
expr += REQUEST;
} else {
expr += _avoidReserveName(id);
}
var current = ast.id.inferred;
for (var i = 0; i < ast.propertyPath.length; i++) {
var name = _name(ast.propertyPath[i]);
if (current.type === 'model') {
expr += `.${_upperFirst(name)}`;
} else if (current.type === 'map') {
expr += `.Get("${name}")`;
} else {
expr += `["${name}"]`;
}
current = ast.propertyPathTypes[i];
}
this.emit(expr);
}
visitReturn(ast, level, env = {}) {
assert.equal(ast.type, 'return');
this.emit('return ', level);
if (!ast.expr) {
this.emit(';\n');
return;
}
if (ast.needCast) {
this.emit('Darabonba.Model.ToObject<');
this.visitType(ast.expectedType);
this.emit('>(');
}
if (ast.expr && ast.expr.type === 'object' && env && env.returnType && _name(env.returnType) === 'object') {
env.castToObject = true;
}
this.visitExpr(ast.expr, level, env);
if (ast.needCast) {
this.emit(')');
}
this.emit(';\n');
}
visitRetry(ast, level) {
assert.equal(ast.type, 'retry');
this.emit(`throw new DaraRetryableException(${REQUEST}, ${RESPONSE});\n`, level);
}
visitWhile(ast, level, env) {
assert.equal(ast.type, 'while');
this.emit('\n');
this.emit('while (', level);
this.visitExpr(ast.condition, level + 1, env);
this.emit(') {\n');
this.visitStmts(ast.stmts, level + 1, env);
this.emit('}\n', level);
}
visitFor(ast, level, env) {
assert.equal(ast.type, 'for');
this.emit('\n');
this.emit(`foreach (var ${_avoidReserveName(_name(ast.id))} in `, level);
this.visitExpr(ast.list, level + 1, env);
this.emit(') {\n');
this.visitStmts(ast.stmts, level + 1, env);
this.emit('}\n', level);
}
visitExtendOn(extendOn, type = 'model') {
if (!extendOn) {
if (type === 'model') {
return this.emit('Darabonba.Model');
}
this.emit('DaraException');
this.used.push('Darabonba.Exceptions');
return;
}
let namespace = this.namespace;
let modelName = _name(extendOn);
let extendType = 'Models';
if (this.predefined[modelName] && this.predefined[modelName].isException) {
extendType = 'Exceptions';
}
if (extendOn.type === 'moduleModel') {
const [moduleId, ...rest] = extendOn.path;
namespace = this.moduleClass.get(moduleId.lexeme).namespace;
modelName = rest.map((item) => {
return item.lexeme;
}).join('.');
const usedEx = this.usedExternException.get(moduleId.lexeme);
if (usedEx && usedEx.has(modelName)) {
type = 'Exceptions';
}
} else if (extendOn.type === 'subModel') {
const [moduleId, ...rest] = extendOn.path;
modelName = [moduleId.lexeme, ...rest.map((item) => {
return item.lexeme;
})].join('.');
} else if (extendOn.idType === 'builtin_model') {
if (extendOn.lexeme === '$ResponseError') {
this.emit(this.getRealModelName('Darabonba.Exceptions', 'DaraResponseException'));
}
if (extendOn.lexeme === '$Error') {
this.emit(this.getRealModelName('Darabonba.Exceptions', 'DaraException'));
}
} else {
if (extendOn.moduleName) {
this.emit(`${extendOn.moduleName}.`);
}
this.emit(this.getRealModelName(`${namespace}.${extendType}`, modelName, extendType));
}
}
visitEcxceptionBody(ast, level, exceptionName, env) {
assert.equal(ast.type, 'exceptionBody');
let node;
for (let i = 0; i < ast.nodes.length; i++) {
node = ast.nodes[i];
const fieldName = _name(node.fieldName);
// 父类里有的字段如果重复写,则表示new(隐藏父类)而不是override(覆盖父类)
if (!exceptionFields.includes(fieldName)) {
let comments = DSL.comment.getFrontComments(this.comments, node.tokenRange[0]);
this.visitComments(comments, level);
this.emit('public ', level);
this.visitFieldType(node.fieldValue, level, exceptionName, fieldName);
this.emit(` ${_escape(_upperFirst(_name(node.fieldName)))}`);
this.emit(' { get; set; }\n');
}
if (node.fieldValue.type === 'modelBody') {
this.emit(`public class ${exceptionName}${_upperFirst(node.fieldName.lexeme)} : Darabonba.Model\n`, level);
this.emit('{\n', level);
this.visitModelBody(node.fieldValue, level + 1, env, exceptionName + _upperFirst(node.fieldName.lexeme));
this.emit('}\n', level);
}
}
if (node) {
//find the last node's back comment
let comments = DSL.comment.getBetweenComments(this.comments, node.tokenRange[0], ast.tokenRange[1]);
this.visitComments(comments, level);
}
if (ast.nodes.length === 0) {
//empty block's comment
let comments = DSL.comment.getBetweenComments(this.comments, ast.tokenRange[0], ast.tokenRange[1]);
this.visitComments(comments, level);
}
}
visitExceptions(ast, filepath, level) {
const exceptions = ast.moduleBody.nodes.filter((item) => {
return item.type === 'exception';
});
const exDir = path.join(path.dirname(filepath), 'Exceptions');
for (let i = 0; i < exceptions.length; i++) {
this.used.push('System');
this.used.push('System.IO');
this.used.push('System.Collections');
this.used.push('System.Collections.Generic');
const exceptionName = _avoidReserveName(exceptions[i].exceptionName.lexeme);
const realExceptionName = `${exceptionName}Exception`;
this.fileName = realExceptionName;
this.eachException(exceptions[i], realExceptionName, level + 1);
this.exceptionAfter();
const modelFilePath = path.join(exDir, `${this.fileName ? this.fileName : exceptionName}.cs`);
this.save(modelFilePath);
}
}
visitException(ast, exceptionName, extendOn, level, env) {
this.emit(`public class ${exceptionName} : `, level);
this.visitExtendOn(extendOn, 'exception');
this.emit('\n');
this.emit('{\n', level);
this.visitEcxceptionBody(ast.exceptionBody, level + 1, exceptionName, env);
this.emit(`\n`);
for (let i = 0; i < ast.exceptionBody.nodes.length; i++) {
const node = ast.exceptionBody.nodes[i];
if (node.fieldValue.type === 'modelBody') {
this.emit(`public class ${exceptionName}${_upperFirst(node.fieldName.lexeme)} : Darabonba.Model\n`, level + 1);
this.emit('{\n', level + 1);
this.visitModelBody(node.fieldValue, level + 2, env, exceptionName + _upperFirst(node.fieldName.lexeme));
this.emit('}\n', level + 1);
}
}
this.emit('}\n\n', level);
}
/*******************************************************/
eachException(exception, realExceptionName, level, env) {
assert.equal(exception.type, 'exception');
const exceptionName = realExceptionName ? realExceptionName : _avoidReserveName(_name(exception.exceptionName));
this.visitAnnotation(exception.annotation, level);
let comments = DSL.comment.getFrontComments(this.comments, exception.tokenRange[0]);
this.visitComments(comments, level);
this.visitException(exception, exceptionName, exception.extendOn, level, env);
}
eachModel(ast, modelName, level, predefined) {
assert.equal(ast.type, 'model');
const env = {
predefined
};
// const modelName = _upperFirst(_name(ast.modelName));
this.emit(`public class ${modelName} : `, level);
this.visitExtendOn(ast.extendOn);
this.emit(' {\n');
this.visitModelBody(ast.modelBody, level + 1, env, modelName);
this.emit('}\n\n', level);
}
eachAPI(ast, level, env = {}) {
this.visitAnnotation(ast.annotation, level);
let comments = DSL.comment.getFrontComments(this.comments, ast.tokenRange[0]);
this.visitComments(comments, level);
this.emit('public ', level);
let apiName = _upperFirst(_name(ast.apiName));
if (env.isAsyncMode) {
this.emit('async ');
apiName += 'Async';
}
env.returnType = ast.returnType;
this.visitReturnType(ast, 0, env);
this.emit(apiName);
this.visitParams(ast.params, level, env);
this.emit('\n');
this.emit('{\n', level);
// Validator
// for (var i = 0; i < ast.params.params.length; i++) {
// const param = ast.params.params[i];
// if (_name(param.paramType) && !DSL.util.isBasicType(_name(param.paramType))) {
// this.emit(`${_avoidReserveName(param.paramName.lexeme)}.Validate();\n`, level + 1);
// }
// }
let baseLevel = ast.runtimeBody ? level + 2 : level;
// api level
if (ast.runtimeBody) {
this.visitRuntimeBefore(ast.runtimeBody, level + 1, env);
}
// temp level
this.visitAPIBody(ast.apiBody, baseLevel + 1, env);
if (env.isAsyncMode) {
this.emit(`Darabonba.Response ${RESPONSE} = await Core.DoActionAsync(${REQUEST}`, baseLevel + 1);
} else {
this.emit(`Darabonba.Response ${RESPONSE} = Core.DoAction(${REQUEST}`, baseLevel + 1);
}
if (ast.runtimeBody) {
this.emit(', runtime_');
}
this.emit(');\n');
if (ast.runtimeBody) {
this.emit(`_lastRequest = ${REQUEST};\n`, baseLevel + 1);
this.emit(`_lastResponse = ${RESPONSE};\n`, baseLevel + 1);
}
if (ast.returns) {
this.visitReturnBody(ast.returns, baseLevel + 1, env);
} else {
this.visitDefaultReturnBody(baseLevel + 1, env);
}
if (ast.runtimeBody) {
this.visitRuntimeAfter(ast.runtimeBody, level + 1);
}
this.emit('}\n', level);
}
importBefore(level) {
// Nothing
}
eachImport(imports, usedModels, innerModule, filepath, level) {
this.imports = {};
if (imports.length === 0) {
return;
}
if (!this.config.pkgDir) {
throw new Error(`Must specific pkgDir when have imports`);
}
let lock;
const lockPath = path.join(this.config.pkgDir, '.libraries.json');
if (fs.existsSync(lockPath)) {
lock = JSON.parse(fs.readFileSync(lockPath, 'utf8'));
}
for (let i = 0; i < imports.length; i++) {
const item = imports[i];
const aliasId = item.lexeme;
const main = item.mainModule;
const inner = item.module;
let moduleDir;
if (this.config.libraries) {
moduleDir = main ? this.config.libraries[main] : this.config.libraries[aliasId];
}
const innerPath = item.innerPath;
const importNameSpace = _nameSpace(path.join(path.dirname(filepath), _upperPath(innerPath)));
if (!moduleDir && innerPath) {
let csPath = innerPath.replace(/(\.tea)$|(\.spec)$|(\.dara)$/gi, '');
const className = this.getInnerClient(aliasId, csPath); // Common,Util,User
// 这里设置 path.join(path.dirname(csPath),`${className}.cs`))而不是cspath.cs,因为文件名需要和类名保持一致
innerModule.set(aliasId, path.join(path.dirname(csPath), `${className}.cs`));
const aliasName = this.getAliasName(`${this.namespace}.${importNameSpace}`, className, aliasId);
this.moduleClass.set(aliasId, {
namespace: `${this.namespace}.${importNameSpace}`.replace(/\.$/, ''),
className: className,
aliasName: aliasName
});
this.imports[aliasId] = {
namespace: `${this.namespace}.${importNameSpace}`.replace(/\.$/, ''),
release: '',
className: aliasId
};
continue;
}
let targetPath = '';
if (moduleDir.startsWith('./') || moduleDir.startsWith('../')) {
targetPath = path.join(this.config.pkgDir, moduleDir);
} else if (moduleDir.startsWith('/')) {
targetPath = moduleDir;
} else {
targetPath = path.join(this.config.pkgDir, lock[moduleDir]);
}
const pkgPath = fs.existsSync(path.join(targetPath, 'Teafile')) ? path.join(targetPath, 'Teafile') : path.join(targetPath, 'Darafile');
const pkg = JSON.parse(fs.readFileSync(pkgPath));
let csharpConfig = pkg.csharp;
pkg.releases = pkg.releases || {};
if (!csharpConfig) {
throw new Error(`The '${aliasId}' has no csharp supported.`);
}
csharpConfig.release = pkg.releases.csharp;
this.imports[aliasId] = csharpConfig;
let className = csharpConfig.className || 'Client';
let namespace = csharpConfig.namespace;
if (inner && pkg.exports[inner]) {
let csPath = path.dirname(pkg.exports[inner]);
const arr = csPath.split(path.sep).slice(1);
const [filename] = pkg.exports[inner].split(path.sep).slice(-1);
arr.map(key => {
namespace += '.' + _upperFirst(key);
});
const processedFilename = filename === '.' ? '' : _upperFirst(filename.toLowerCase().replace(/(\.tea)$|(\.spec)$|(\.dara)$/gi, ''));
const exportsName = csharpConfig.exports ? csharpConfig.exports[inner] : '';
className = exportsName ? exportsName : `${processedFilename}Client`;
}
const aliasName = this.getAliasName(namespace, className, aliasId);
this.moduleClass.set(aliasId, {
namespace: namespace,
className: className,
aliasName: aliasName
});
this.moduleTypedef[aliasId] = csharpConfig.typedef;
}
}
importAfter() {
// Nothing
}
moduleBefore() {
// Nothing
}
modelAfter() {
this.emit('}\n');
}
exceptionAfter() {
this.emit('}\n');
}
interfaceEachAPI(ast, level) {
this.visitAnnotation(ast.annotation, level);
let comments = DSL.comment.getFrontComments(this.comments, ast.tokenRange[0]);
this.visitComments(comments, level);
let apiName = _upperFirst(_name(ast.apiName));
let env = {};
env.returnType = ast.returnType;
this.emit('', level);
this.visitReturnType(ast, 0, env);
this.emit(apiName);
this.visitParams(ast.params, level, env);
this.emit(';\n');
}
InterfaceEachFunction(ast, level) {
let wrapName = _upperFirst(_name(ast.functionName));
this.visitAnnotation(ast.annotation, level);
let comments = DSL.comment.getFrontComments(this.comments, ast.tokenRange[0]);
this.visitComments(comments, level);
this.emit('', level);
let env = {};
env.returnType = ast.returnType;
this.visitReturnType(ast, 0, env);
this.emit(`${wrapName}`);
if (this.isExec && wrapName === 'Main') {
this.emit('(string[] args)');
} else {
this.visitParams(ast.params, level, env);
}
this.emit(';\n');
}
interfaceAfter(level) {
this.emit('}\n', level);
this.emit('}\n');
}
apiBefore(level, extendParam, filepath, main) {
this.used.push('System');
this.used.push('System.IO');
this.used.push('System.Collections');
this.used.push('System.Collections.Generic');
this.used.push('System.Threading.Tasks');
this.used.push('Darabonba');
this.used.push('Darabonba.Utils');
let className = this.className;
const fileInfo = path.parse(filepath);
if (!main) {
const beginNotes = DSL.note.getNotes(this.notes, 0, this.ast.moduleBody.nodes[0].tokenRange[0]);
const clientNote = beginNotes.find(note => note.note.lexeme === '@clientName');
if (clientNote) {
className = clientNote.arg.value.string;
} else {
className = `${_upperFirst(fileInfo.name.toLowerCase())}Client`;
}
}
this.emit(`public class ${className} `, level + 1);
if (extendParam.extend && extendParam.extend.length > 0) {
const extendsModuleName = this.getRealClientName(this.ast.extends.lexeme);
const extendsInterfaces = extendParam.extend.filter(item => item.startsWith('I'));
this.emit(`: ${extendsModuleName}${extendsInterfaces.join(', ') === '' ? '' : ', '}${extendsInterfaces.join(', ')}
{
`);
} else {
this.emit(`
{
`);
}
}
// init(level) {
// // Nothing
// }
apiAfter() {
// Nothing
}
wrapBefore() {
}
eachFunction(ast, level, env = {}) {
let wrapName = _upperFirst(_name(ast.functionName));
if (wrapName === 'Main' && env.isAsyncMode && !(this.isExec && this.asyncOnly)) {
return;
}
this.visitAnnotation(ast.annotation, level);
let comments = DSL.comment.getFrontComments(this.comments, ast.tokenRange[0]);
this.visitComments(comments, level);
this.emit('public ', level);
if (ast.isStatic) {
this.emit('static ');
}
if (env.isAsyncMode) {
this.emit('async ');
if (wrapName !== 'Main') {
wrapName += 'Async';
}
}
env.returnType = ast.returnType;
this.visitReturnType(ast, 0, env);
this.emit(`${wrapName}`);
if (this.isExec && wrapName === 'Main') {
this.emit('(string[] args)');
} else {
this.visitParams(ast.params, level, env);
}
this.emit('\n');
this.emit('{\n', level);
if (ast.functionBody) {
this.visitWrapBody(ast.functionBody, level + 1, env);
} else {
this.emit('throw new NotImplementedException();\n', level + 1);
}
this.emit('}\n', level);
}
wrapAfter() {
// Nothing
}
moduleAfter() {
this.emit(`
}
}\n`, 0);
}
isIterator(returnType) {
if (returnType.type === 'iterator' || returnType.type === 'asyncIterator') {
return true;
}
return false;
}
visitWrapBody(ast, level, env) {
assert.equal(ast.type, 'functionBody');
this.visitStmts(ast.stmts, level, env);
}
visitInit(ast, types, main, filepath, level, env) {
assert.equal(ast.type, 'init');
types.forEach((item) => {
let comments = DSL.comment.getFrontComments(this.comments, item.tokenRange[0]);
this.visitComments(comments, level + 2);
this.emit('protected ', level + 2);
if (item.value.type || item.value.idType) {
this.visitType(item.value);
this.emit(' ');
} else if (this.imports[_name(item.value)]) {
const realClsName = this.getRealClientName(_name(item.value));
this.emit(`${realClsName || 'Client'} `);
} else {
this.emit(`${this._type(_name(item.value))} `);
}
this.emit(`${_vid(item.vid)};\n`);
});
this.emit('\n');
this.visitAnnotation(ast.annotation, level + 2);
let comments = DSL.comment.getFrontComments(this.comments, ast.tokenRange[0]);
this.visitComments(comments, level + 2);
let className = this.className;
if (!main) {
const fileInfo = path.parse(filepath);
const beginNotes = DSL.note.getNotes(this.notes, 0, this.ast.moduleBody.nodes[0].tokenRange[0]);
const clientNote = beginNotes.find(note => note.note.lexeme === '@clientName');
if (clientNote) {
className = clientNote.arg.value.string;
} else {
className = `${_upperFirst(fileInfo.name.toLowerCase())}Client`;
}
}
this.emit(`public ${className || 'Client'}`, level + 2);
this.visitParams(ast.params);
if (ast.initBody && ast.initBody.stmts[0] && ast.initBody.stmts[0].type === 'super') {
this.emit(`: base(`);
for (let i = 0; i < ast.initBody.stmts[0].args.length; i++) {
if (i > 0) {
this.emit(', ');
}
this.visitExpr(ast.initBody.stmts[0].args[i], level, env);
}
this.emit(`)`);
}
this.emit('\n');
this.emit('{\n', level + 2);
if (ast.initBody) {
this.visitStmts(ast.initBody, level + 3, {
isAsyncMode: false
});
}
this.emit('}\n\n', level + 2);
}
visitAnnotation(annotation, level) {
if (!annotation || !annotation.value) {
return;
}
let comments = DSL.comment.getFrontComments(this.comments, annotation.index);
this.visitComments(comments, level);
var ast = Annotation.parse(annotation.value);
var description = ast.items.find((item) => {
return item.type === 'description';
});
var summary = ast.items.find((item) => {
return item.type === 'summary';
});
var _return = ast.items.find((item) => {
return item.type === 'return';
});
var deprecated = ast.items.find((item) => {
return item.type === 'deprecated';
});
var params = ast.items.filter((item) => {
return item.type === 'param';
}).map((item) => {
return {
name: item.name.id,
text: item.text.text
};
});
var throws = ast.items.filter((item) => {
return item.type === 'throws';
}).map((item) => {
return item.text.text;
});
const deprecatedText = deprecated ? deprecated.text.text : '';
const summaryText = summary ? summary.text.text : '';
const descriptionText = description ? description.text.text.trimEnd() : '';
const returnText = _return ? _return.text.text.trimEnd() : '';
let hasNextSection = false;
if (deprecated) {
this.emit(`/// <term><b>Deprecated</b></term>\n`, level);
this.emit(`/// \n`, level);
deprecatedText.trimEnd().split('\n').forEach((line) => {
this.emit(`/// ${line}\n`, level);
});
hasNextSection = true;
}
if (summaryText !== '') {
if (hasNextSection) {
this.emit(`/// \n`, level);
}
this.emit(`/// <term><b>Summary:</b></term>\n`, level);
this.emit(`/// <summary>\n`, level);
const summaryTexts = md2Xml(summaryText);
summaryTexts.split('\n').forEach((line) => {
this.emit(`/// ${line}\n`, level);
});
this.emit(`/// </summary>\n`, level);
hasNextSection = true;
}
if (descriptionText !== '') {
if (hasNextSection) {
this.emit(`/// \n`, level);
}
this.emit(`/// <term><b>Description:</b></term>\n`, level);
this.emit(`/// <description>\n`, level);
const descriptionTexts = md2Xml(descriptionText);
descriptionTexts.split('\n').forEach((line) => {
this.emit(`/// ${line}\n`, level);
});
this.emit(`/// </description>\n`, level);
hasNextSection = true;
}
if (params.length > 0) {
if (hasNextSection) {
this.emit(`/// \n`, level);
}
params.forEach((item) => {
this.emit(`/// <param name="${item.name}">\n`, level);
item.text.trimEnd().split('\n').forEach((line) => {
this.emit(`/// ${line}\n`, level);
});
this.emit(`/// </param>\n`, level);
});
hasNextSection = true;
}
if (returnText) {
if (hasNextSection) {
this.emit(`/// \n`, level);
}
this.emit(`/// <returns>\n`, level);
returnText.split('\n').forEach((line) => {
this.emit(`/// ${line}\n`, level);
});
this.emit(`/// </returns>\n`, level);
hasNextSection = true;
}
if (throws.length > 0) {
if (hasNextSection) {
this.emit(`/// \n`, level);
}
throws.forEach((item, index) => {
this.emit(`/// <term><b>Exception:</b></term>\n`, level);
item.trimEnd().split('\n').forEach((line) => {
this.emit(`/// ${line}\n`, level);
});
if (index < throws.length - 1) {
this.emit(`/// \n`, level);
}
});
}
if (deprecated) {
this.emit(`[Obsolete("`, level);
const lines = deprecatedText.trimEnd().split('\n');
lines.forEach((line, index) => {
if (index === lines.length - 1) {
this.emit(`${line}`);
} else {
this.emit(`${line}\\n`);
}
});
this.emit(`")]\n`);
}
}
visitComments(comments, level) {
comments.forEach(comment => {
this.emit(`${comment.value}`, level);
this.emit(`\n`);
});
}
visitConsoleCSProj(uniqueUsed) {
let csprojPath = path.join(this.csprojOutputDir, (this.config.packageInfo.name || 'client') + '.csproj');
let json = {};
json = parse(fs.readFileSync(path.join(__dirname, 'files', 'consoleCsproj.tmpl')));
//填写包的基本信息
let propertyGroup = json.Project.PropertyGroup;
propertyGroup.forEach((property) => {
if (Object.hasOwn(property, 'RootNamespace')) {
property['RootNamespace'] = this.config.namespace;
}
});
let dependenciesClass = [];
if (uniqueUsed.includes('Newtonsoft.Json')) {
dependenciesClass.push('Newtonsoft.Json:13.0.1');
}
Object.keys(this.imports).forEach((key) => {
dependenciesClass.push(this.imports[key].release);
});
// 兜底依赖 Darabonba 的 1.0.0 版本
const teaVersion = '1.0.0';
dependenciesClass.push(`Darabonba:${teaVersion}`);
let currentItemGroup = {};
dependenciesClass.forEach((item, index) => {
let dependency = item.split(':');
currentItemGroup[dependency[0]] = dependency[1];
});
const newItemGroup = { ...currentItemGroup, ...this.packageManager };
//寻找用来写入的itemGroup, 避开有特殊参数的itemGroup
let itemGroup = {};
//添加或更新依赖包
Object.entries(newItemGroup || {}).forEach(([key, value]) => {
let writeReference = {};
itemGroup.PackageReference = itemGroup.PackageReference || [];
writeReference.$ = { 'Include': key, 'Version': value };
itemGroup.PackageReference.push(writeReference);
});
if (this.typedef) {
Object.keys(this.typedef).map(key => {
if (!this.typedef[key].package) {
return;
}
dependenciesClass.push(this.typedef[key].package);
});
}
json.Project.ItemGroup = itemGroup;
const builder = new xml2js.Builder();
const newCsproj = builder.buildObject(json);
fs.writeFileSync(csprojPath, Entities.decode(newCsproj));
}
visitCSProj(uniqueUsed) {
let csprojPath = path.join(this.csprojOutputDir, (this.config.packageInfo.name || 'client') + '.csproj');
let json = {};
// 保留本地已有的包
if (!fs.existsSync(csprojPath)) {
json = parse(fs.readFileSync(path.join(__dirname, 'files', 'csproj.tmpl')));
} else {
json = parse(fs.readFileSync(csprojPath));
}
//填写包的基本信息
let propertyGroup = json.Project.PropertyGroup;
let assemblyInfo = this.release.split(':');
propertyGroup.forEach((property) => {
if (Object.hasOwn(property, 'RootNamespace')) {
property['RootNamespace'] = this.config.namespace;
if (this.config.packageInfo && this.config.packageInfo.company) {
property['Authors'] = this.config.packageInfo.company;
} else if (this.config.maintainers && this.config.maintainers.name) {
property['Authors'] = this.config.maintainers.name;
}
if (this.config.packageInfo && this.config.packageInfo.description) {
property['Description'] = this.config.packageInfo.description;
}
if (this.config.packageInfo && this.config.packageInfo.property) {
Object.assign(property, this.config.packageInfo.property);
}
}
if (Object.hasOwn(property, 'AssemblyName')) {
property['AssemblyName'] = assemblyInfo[0];
}
// 支持 packageInfo 中配置当前包发布的版本(之前是<Version/>)
if (Object.hasOwn(property, 'Version') && this.packageVersion) {
property['Version'] = this.packageVersion;
}
});
let dependenciesClass = [];
if (uniqueUsed.includes('Newtonsoft.Json')) {
dependenciesClass.push('Newtonsoft.Json:13.0.1');
}
Object.keys(this.imports).forEach((key) => {
if (!this.imports[key].release) {
return;
}
dependenciesClass.push(this.imports[key].release);
});
if (this.typedef) {
Object.keys(this.typedef).map(key => {
if (!this.typedef[key].package) {
return;
}
dependenciesClass.push(this.typedef[key].package);
});
}
// 兜底依赖 Darabonba 的 1.0.0 版本
const teaVersion = '1.0.0';
dependenciesClass.push(`Darabonba:${teaVersion}`);
//寻找用来写入的itemGroup, 避开有特殊参数的itemGroup
let itemGroup = json.Project.ItemGroup;
let writeItem = {};
itemGroup.forEach((item) => {
if (!item.$) {
writeItem = item;
}
});
let newDependenciesClass = [];
if (this.packageManager) {
const needAddPackages = Object.entries(this.packageManager || {}).map(([key, value]) => `${key}:${value}`);
const needAddPackageName = new Set(needAddPackages.map(item => item.split(':')[0]));
newDependenciesClass = [...needAddPackages];
dependenciesClass.forEach(item => {
const [pkgName] = item.split(':');
if (!needAddPackageName.has(pkgName)) {
newDependenciesClass.push(item);
}
});
} else {
newDependenciesClass = dependenciesClass;
}
//添加或更新依赖包
newDependenciesClass.forEach((item, index) => {
if (item) {
let dependency = item.split(':');
//遍历所有的itemGroup,判断是否已存在该依赖
let writeReference = null;
itemGroup.forEach((group) => {
if (group.PackageReference) {
group.PackageReference.forEach((reference) => {
if (reference.$.Include === dependency[0]) {
writeReference = reference;
}
});
}
});
if (writeReference) {
writeReference.$.Version = dependency[1];
} else {
writeReference = {};
writeItem.PackageReference = writeItem.PackageReference || [];
writeReference.$ = { 'Include': dependency[0], 'Version': dependency[1] };
writeItem.PackageReference.push(writeReference);
}
}
});
const builder = new xml2js.Builder();
const newCsproj = builder.buildObject(json);
fs.writeFileSync(csprojPath, Entities.decode(newCsproj));
}
visitAssemblyInfo() {
let propertiesDir = path.join(this.csprojOutputDir, 'Properties');
if (!fs.existsSync(propertiesDir)) {
fs.mkdirSync(propertiesDir, {
recursive: true
});
}
let assemblyPath = path.join(propertiesDir, 'AssemblyInfo.cs');
let content = {};
if (!fs.existsSync(assemblyPath)) {
content = fs.readFileSync(path.join(__dirname, 'files', 'assemblyInfo.tmpl')).toString();
let params = {
title: this.config.packageInfo.title || '',
description: this.config.packageInfo.description || '',
company: this.config.packageInfo.company || '',
product: this.config.packageInfo.product || '',
guid: UUID.v1(),
version: this.release.split(':')[1],
copyRight: this.config.packageInfo.copyRight || '',
};
if (content !== '') {
content = render(content, params);
}
fs.writeFileSync(assemblyPath, content);
} else {
content = fs.readFileSync(assemblyPath).toString();
content = content.replace(/AssemblyVersion\("[\S\s].*?"\)/, `AssemblyVersion("${this.release.split(':')[1]}.0")`);
content = content.replace(/AssemblyFileVersion\("[\S\s].*?"\)/, `AssemblyFileVersion("${this.release.split(':')[1]}.0")`);
fs.writeFileSync(assemblyPath, content);
}
}
}