From c4c6efe7c7ad28f2af87b97d786a7193d84f4218 Mon Sep 17 00:00:00 2001 From: Pavel Feldman Date: Mon, 27 Sep 2021 13:25:07 -0700 Subject: [PATCH] chore: dedupe return types in the dotnet api generator (#9181) --- utils/doclint/generateDotnetApi.js | 83 ++++++++++++------------------ 1 file changed, 33 insertions(+), 50 deletions(-) diff --git a/utils/doclint/generateDotnetApi.js b/utils/doclint/generateDotnetApi.js index 303feb6391..1f630e8350 100644 --- a/utils/doclint/generateDotnetApi.js +++ b/utils/doclint/generateDotnetApi.js @@ -40,7 +40,6 @@ const optionTypes = new Map(); const customTypeNames = new Map([ ['domcontentloaded', 'DOMContentLoaded'], ['networkidle', 'NetworkIdle'], - ['File', 'FilePayload'], ]); const outputDir = process.argv[2] || path.join(__dirname, 'generate_types', 'csharp'); @@ -394,8 +393,28 @@ function generateNameDefault(member, name, t, parent) { if (attemptedName.endsWith('s') && !["properties", "httpcredentials"].includes(attemptedName.toLowerCase())) attemptedName = attemptedName.substring(0, attemptedName.length - 1); - if (customTypeNames.get(attemptedName)) - attemptedName = customTypeNames.get(attemptedName); + + // For some of these we don't want to generate generic types. + // For some others we simply did not have the code that was deduping the names. + if (attemptedName === 'BoundingBox') + attemptedName = `${parent.name}BoundingBoxResult`; + if (attemptedName === 'BrowserContextCookie') + attemptedName = 'BrowserContextCookiesResult'; + if (attemptedName === 'File') + attemptedName = `FilePayload`; + if (attemptedName === 'Size') + attemptedName = 'RequestSizesResult'; + if (attemptedName === 'ViewportSize' && parent.name === 'Page') + attemptedName = 'PageViewportSizeResult'; + if (attemptedName === 'SecurityDetail') + attemptedName = 'ResponseSecurityDetailsResult'; + if (attemptedName === 'ServerAddr') + attemptedName = 'ResponseServerAddrResult'; + if (attemptedName === 'Timing') + attemptedName = 'RequestTimingResult'; + if (attemptedName === 'HeadersArray') + attemptedName = 'Header'; + let probableType = modelTypes.get(attemptedName); if ((probableType && typesDiffer(t, probableType)) || (["Value"].includes(attemptedName))) { @@ -457,18 +476,6 @@ function renderMethod(member, parent, name, options, out) { if (options.trimRunAndPrefix) name = name.substring('RunAnd'.length); - /** - * @param {Documentation.Type} type - * @returns - */ - function resolveType(type) { - return translateType(type, parent, (t) => { - let newName = `${parent.name}${toMemberName(member)}Result`; - documentedResults.set(newName, `Result of calling .`); - return newName; - }); - } - /** @type {Map} */ const paramDocs = new Map(); const addParamsDoc = (paramName, docs) => { @@ -479,32 +486,8 @@ function renderMethod(member, parent, name, options, out) { paramDocs.set(paramName, docs); }; - /** @type {string} */ - let type = null; - // need to check the original one - if (member.type.name === 'Object' || member.type.name === 'Array') { - let innerType = member.type; - let isArray = false; - if (innerType.name === 'Array') { - // we want to influence the name, but also change the object type - innerType = member.type.templates[0]; - isArray = true; - } + let type = translateType(member.type, parent, t => generateNameDefault(member, name, t, parent), false, true); - if (innerType.expression === '[Object]<[string], [string]>') { - // do nothing, because this is handled down the road - } else if (!isArray && !innerType.properties) { - type = `dynamic`; - } else { - type = classNameMap.get(innerType.name); - if (!type) - type = resolveType(innerType); - if (isArray) - type = `IReadOnlyList<${type}>`; - } - } - - type = type || resolveType(member.type); // TODO: this is something that will probably go into the docs // translate simple getters into read-only properties, and simple // set-only methods to settable properties @@ -737,14 +720,14 @@ function renderMethod(member, parent, name, options, out) { * @param {boolean=} optional * @returns {string} */ -function translateType(type, parent, generateNameCallback = t => t.name, optional = false) { +function translateType(type, parent, generateNameCallback = t => t.name, optional = false, isReturnType = false) { // a few special cases we can fix automatically if (type.expression === '[null]|[Error]') return 'void'; if (type.union) { if (type.union[0].name === 'null' && type.union.length === 2) - return translateType(type.union[1], parent, generateNameCallback, true); + return translateType(type.union[1], parent, generateNameCallback, true, isReturnType); if (type.expression === '[string]|[Buffer]') return `byte[]`; // TODO: make sure we implement extension methods for this! @@ -769,8 +752,8 @@ function translateType(type, parent, generateNameCallback = t => t.name, optiona if (type.templates.length != 1) throw new Error(`Array (${type.name} from ${parent.name}) has more than 1 dimension. Panic.`); - let innerType = translateType(type.templates[0], parent, generateNameCallback); - return `IEnumerable<${innerType}>`; + let innerType = translateType(type.templates[0], parent, generateNameCallback, false, isReturnType); + return isReturnType ? `IReadOnlyList<${innerType}>` : `IEnumerable<${innerType}>`; } if (type.name === 'Object') { @@ -778,8 +761,8 @@ function translateType(type, parent, generateNameCallback = t => t.name, optiona // TODO: this can be genericized if (type.templates && type.templates.length == 2) { // get the inner types of both templates, and if they're strings, it's a keyvaluepair string, string, - let keyType = translateType(type.templates[0], parent, generateNameCallback); - let valueType = translateType(type.templates[1], parent, generateNameCallback); + let keyType = translateType(type.templates[0], parent, generateNameCallback, false, isReturnType); + let valueType = translateType(type.templates[1], parent, generateNameCallback, false, isReturnType); if (parent.name === 'Request' || parent.name === 'Response') return `Dictionary<${keyType}, ${valueType}>`; return `IEnumerable>`; @@ -803,8 +786,8 @@ function translateType(type, parent, generateNameCallback = t => t.name, optiona if (type.name === 'Map') { if (type.templates && type.templates.length == 2) { // we map to a dictionary - let keyType = translateType(type.templates[0], parent, generateNameCallback); - let valueType = translateType(type.templates[1], parent, generateNameCallback); + let keyType = translateType(type.templates[0], parent, generateNameCallback, false, isReturnType); + let valueType = translateType(type.templates[1], parent, generateNameCallback, false, isReturnType); return `Dictionary<${keyType}, ${valueType}>`; } else { throw 'Map has invalid number of templates.'; @@ -817,7 +800,7 @@ function translateType(type, parent, generateNameCallback = t => t.name, optiona let argsList = ''; if (type.args) { - let translatedCallbackArguments = type.args.map(t => translateType(t, parent, generateNameCallback)); + let translatedCallbackArguments = type.args.map(t => translateType(t, parent, generateNameCallback, false, isReturnType)); if (translatedCallbackArguments.includes(null)) throw new Error('There was an argument we could not parse. Aborting.'); @@ -828,7 +811,7 @@ function translateType(type, parent, generateNameCallback = t => t.name, optiona // this is an Action return `Action<${argsList}>`; } else { - let returnType = translateType(type.returnType, parent, generateNameCallback); + let returnType = translateType(type.returnType, parent, generateNameCallback, false, isReturnType); if (returnType == null) throw new Error('Unexpected null as return type.');