diff --git a/abap-api-tools/README.md b/abap-api-tools/README.md index c1d42044..d4000bab 100644 --- a/abap-api-tools/README.md +++ b/abap-api-tools/README.md @@ -97,8 +97,11 @@ ABAP API for Value Help annotations, if exposed in backend system (see [ABAP hel ```yaml MME: search_help_api: - determine: YWS_SHLP_DETERMINE - dom_values: YWS_SHLP_DOMVALUES_GET + determine: /COE/RBP_FE_SHLP_DETERM_SEARCH + FV_descriptor_get: /COE/RBP_FE_SHLP_DOMVALUES_GET + CT_descriptor_get: FDT_GET_DDIC_METADATA + SH_descriptor_get: /COE/RBP_FE_SHLP_METADATA_GET + search: /COE/RBP_FE_SHLP_GET ``` Run `abap` command, to show help: diff --git a/abap-api-tools/package-lock.json b/abap-api-tools/package-lock.json index f311108f..747a3b46 100644 --- a/abap-api-tools/package-lock.json +++ b/abap-api-tools/package-lock.json @@ -11,7 +11,7 @@ ], "license": "Apache-2.0", "dependencies": { - "abap-value-help": "file:../abap-value-help", + "abap-value-help": "^1.0.0", "chalk": "^4.1.0", "js-yaml": "^4.0.0", "loglevel": "^1.7.1", @@ -37,28 +37,6 @@ "node": "~10 >=10.23 || ~12 >=12.17 || >= 14.0" } }, - "../abap-value-help": { - "version": "0.9.6", - "cpu": [ - "!arm" - ], - "license": "Apache-2.0", - "dependencies": { - "loglevel": "^1.7.1", - "node-rfc": "^2.4.0" - }, - "devDependencies": { - "@types/node": "^14.14.31", - "@typescript-eslint/eslint-plugin": "^4.15.2", - "@typescript-eslint/parser": "^4.15.2", - "eslint": "^7.20.0", - "jest": "^26.6.3", - "typescript": "^4.2.2" - }, - "engines": { - "node": "~10 >=10.23 || ~12 >=12.17 || >= 14.0" - } - }, "node_modules/@babel/code-frame": { "version": "7.12.11", "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.12.11.tgz", @@ -1284,8 +1262,19 @@ "dev": true }, "node_modules/abap-value-help": { - "resolved": "../abap-value-help", - "link": true + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/abap-value-help/-/abap-value-help-1.0.0.tgz", + "integrity": "sha512-bWztYAC5MFC5ioNYKLM2x++C+7g1o/Xu20CDF97nADrJgvElcRSxLo4jTxBR2P1DxEmXLpuxOCro90jPg5ugdA==", + "cpu": [ + "!arm" + ], + "dependencies": { + "loglevel": "^1.7.1", + "node-rfc": "^2.4.0" + }, + "engines": { + "node": "~10 >=10.23 || ~12 >=12.17 || >= 14.0" + } }, "node_modules/acorn": { "version": "7.4.1", @@ -8339,16 +8328,12 @@ "dev": true }, "abap-value-help": { - "version": "file:../abap-value-help", + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/abap-value-help/-/abap-value-help-1.0.0.tgz", + "integrity": "sha512-bWztYAC5MFC5ioNYKLM2x++C+7g1o/Xu20CDF97nADrJgvElcRSxLo4jTxBR2P1DxEmXLpuxOCro90jPg5ugdA==", "requires": { - "@types/node": "^14.14.31", - "@typescript-eslint/eslint-plugin": "^4.15.2", - "@typescript-eslint/parser": "^4.15.2", - "eslint": "^7.20.0", - "jest": "^26.6.3", "loglevel": "^1.7.1", - "node-rfc": "^2.4.0", - "typescript": "^4.2.2" + "node-rfc": "^2.4.0" } }, "acorn": { diff --git a/abap-api-tools/package.json b/abap-api-tools/package.json index 4e786915..e85744a1 100644 --- a/abap-api-tools/package.json +++ b/abap-api-tools/package.json @@ -1,7 +1,7 @@ { "name": "abap-api-tools", "description": "ABAP api tools", - "version": "2.0.0", + "version": "2.1.0", "homepage": "https://github.com/sap/fundamental-tools", "author": "SAP", "license": "Apache-2.0", @@ -45,7 +45,7 @@ "nodejs" ], "dependencies": { - "abap-value-help": "file:../abap-value-help", + "abap-value-help": "^1.0.0", "chalk": "^4.1.0", "js-yaml": "^4.0.0", "loglevel": "^1.7.1", diff --git a/abap-api-tools/src/ts/backend.ts b/abap-api-tools/src/ts/backend.ts index 3b6e6d8e..bca3fce6 100644 --- a/abap-api-tools/src/ts/backend.ts +++ b/abap-api-tools/src/ts/backend.ts @@ -28,19 +28,13 @@ import { import { Alpha, AlphaCatalogType } from "./alpha"; -import { - deleteFile, - isEmpty, - log, - fileLoad, - fileSave, - fileExists, -} from "./utils"; +import { isEmpty, log, fileLoad, fileSave, fileExists, rmDir } from "./utils"; import { ShlpApiType, ValueInputHelp, DescriptorType, + FVDescriptorType, ValueHelpType, } from "abap-value-help"; @@ -355,18 +349,17 @@ export class Backend { result.format.valueInputType = ValueInput.list; // Binary / List type - const descriptor = this.Descriptors[helpFound.id]; + const descriptor = this.Descriptors[helpFound.id] as FVDescriptorType; if (descriptor) { - if (descriptor["valueInputType"]) { - result.format.valueInputType = descriptor["valueInputType"]; - } + if (descriptor.valueInputType === ValueInput.binary) { + result.format.valueInputType = ValueInput.binary; - // Checkbox uses SHLP only when values differ from "X" and ""; - if ( - result.format.valueInputType === ValueInput.binary && - !descriptor["customCheckbox"] - ) { - delete result.input.shlpId; + // Checkbox SHLP used only when values differ from "X" and "" + if (descriptor.customCheckbox) { + //result.input.customCheckbox = "X"; + } else { + delete result.input.shlpId; + } } } } @@ -384,6 +377,24 @@ export class Backend { // write search help id into selection field descriptor if (selectionHelpFound.id) { field.shlpId = selectionHelpFound.id; + field.valueInputType = ValueInput.list; + + // Binary / List type + const descriptor = this.Descriptors[ + selectionHelpFound.id + ] as FVDescriptorType; + if (descriptor) { + if (descriptor.valueInputType === ValueInput.binary) { + field.valueInputType = ValueInput.binary; + + // Checkbox SHLP used only when values differ from "X" and "" + if (descriptor.customCheckbox) { + field.customCheckbox = "X"; + // } else { + // delete field.shlpId; + } + } + } } } } @@ -865,26 +876,9 @@ export class Backend { } annotations_clean(): void { - const folder_yaml = path.join( - this.argv.output as string, - this.api_name, - "yaml" - ); - - log.debug(`AnnotationsType clean ${folder_yaml}`); - - for (const fileName of [ - "parameters", - "fields", - "helps", - "stat", - "alpha", - "usage", - "texts", - "descriptors", - ]) { - deleteFile(path.join(folder_yaml, `${fileName}.yaml`)); - } + const rootdir = path.join(this.argv.output as string, this.api_name); + log.debug("Clean annotations", rootdir); + rmDir(rootdir); } } diff --git a/abap-api-tools/src/ts/frontend.ts b/abap-api-tools/src/ts/frontend.ts index 20ff1a5b..65aa06ef 100644 --- a/abap-api-tools/src/ts/frontend.ts +++ b/abap-api-tools/src/ts/frontend.ts @@ -6,7 +6,15 @@ import chalk from "chalk"; import path from "path"; import { sprintf } from "sprintf-js"; -import { EmptyObject, Writer, isEmpty, log, fileLoad } from "./utils"; +import { + EmptyObject, + Writer, + isEmpty, + log, + fileLoad, + makeDir, + rmDir, +} from "./utils"; import { ParamClass, @@ -30,14 +38,14 @@ import { import { ElementaryHelpType, EHDescriptorType } from "abap-value-help"; -import { RfcStructure } from "node-rfc"; +import { RfcStructure, RfcTable } from "node-rfc"; import { Command, Arguments, Signature } from "./abap"; interface IElementaryHelp { id: string; title: string; - selectionFields: FieldType[]; + selectionFields: RfcStructure[]; // FieldType[]; selectionParameters: string[]; blacklisted: boolean; } @@ -562,45 +570,171 @@ export class Frontend { } valueHelps(): { js: string; html?: string } { - const fileName = path.join( + const outDir = path.join( this.argv.output || "", this.api_name, "valueHelps" ); - const htmlWriter = new Writer( - `${fileName}.html`, - this.argv.save as boolean - ); + if (this.argv.save) { + rmDir(outDir); + makeDir(outDir); + } + + function newWriter(suffix: "js" | "html", shlpId, title, save: boolean) { + const writer = new Writer( + path.join( + outDir, + `${shlpId + .toLowerCase() + .replace(/\//g, "_") + .replace(" ", "_")}.${suffix}` + ), + save + ); + writer.write( + suffix === "js" + ? `// ${shlpId} ${title} : ${Signature}\n` + : `}\n` + ); + + if (suffix === "html") return writer; + writer.write( + `const helpSign = [{ id: 'I', name: 'Include' }, { id: 'E', name: 'Exclude' }]; +const helpOption = [ + { id: 'EQ', name: 'is' }, + { id: 'NE', name: 'is not' }, + { id: 'GT', name: 'greater than' }, + { id: 'LT', name: 'less than' }, + { id: 'GE', name: 'not less' }, + { id: 'LE', name: 'not greater' }, + { id: 'BT', name: 'between' }, + { id: 'NB', name: 'not between' }, + { id: 'CP', name: 'with pattern' }, + { id: 'NP', name: 'w/o pattern' } +];\n` + ); + return writer; + } + + function selectionParams(jsWriter, FIELDDESCR: RfcTable): void { + jsWriter.write(`const selectParams = [`); + jsWriter.addindent(); + for (const field of FIELDDESCR) { + jsWriter.write(`{`); + jsWriter.addindent(); + for (const k of ["FIELDNAME", "DATATYPE", "LENG", "DECIMALS"]) { + jsWriter.write( + `${k}: ${ + typeof field[k] === "string" ? '"' + field[k] + '"' : field[k] + },` + ); + } + for (const k of ["MEMORYID", "PARVA"]) { + if (k in field && field[k]) + jsWriter.write( + `${k}: ${ + typeof field[k] === "string" ? '"' + field[k] + '"' : field[k] + }` + ); + } + + jsWriter.deindent(); + jsWriter.write(`},`); + } + jsWriter.deindent(); + jsWriter.write(`];`); + } + + let JS = "", + HTML = ""; // // html header // - htmlWriter.write(``); - - for (const [shlp_key, shelp] of Object.entries( + for (const [shlp_key, shlp] of Object.entries( this.abap.helps as HelpsCatalogType )) { - const stype = shlp_key.split(" ")[0]; - if (stype !== "SH") { + if (shlp_key.substr(0, 2) !== "SH") { continue; } - log.info(shlp_key, shelp.title); - if (shelp.elementaryHelps) { - for (const eh of shelp.elementaryHelps) { - const skey = Object.keys(eh)[0]; - const title = eh[skey]; - log.info(" ", skey, title); - this.elementaryHelp(skey); + if (shlp.elementaryHelps) { + // html + const htmlWriter = newWriter( + "html", + shlp_key, + `${shlp.title} (${shlp.elementaryHelps.length})`, + this.argv.save as boolean + ); + htmlWriter.write( + `` + ); + HTML += htmlWriter.save(); + + // js + const jsWriter = newWriter( + "js", + shlp_key, + `${shlp.title} (${shlp.elementaryHelps.length})`, + this.argv.save as boolean + ); + jsWriter.write("const helpSelector = ["); + jsWriter.addindent(); + shlp.elementaryHelps.map((eh) => + jsWriter.write(JSON.stringify(eh) + ",") + ); + jsWriter.deindent(); + jsWriter.write("];"); + JS += jsWriter.save(); + + for (const elem of shlp.elementaryHelps) { + const shlpId = Object.keys(elem)[0]; + const EH = this.elementaryHelp(shlpId); + + // html + const htmlWriter = newWriter( + "html", + shlpId, + elem[shlpId].title, + this.argv.save as boolean + ); + EH.selectionParameters.map((sp) => htmlWriter.write(sp)); + HTML += htmlWriter.save(); + // js + const jsWriter = newWriter( + "js", + shlpId, + elem[shlpId].title, + this.argv.save as boolean + ); + selectionParams(jsWriter, EH.selectionFields); + + JS += jsWriter.save(); } } else { - this.elementaryHelp(shlp_key); + const htmlWriter = newWriter( + "html", + shlp_key, + shlp.title, + this.argv.save as boolean + ); + const jsWriter = newWriter( + "js", + shlp_key, + shlp.title, + this.argv.save as boolean + ); + const EH = this.elementaryHelp(shlp_key); + EH.selectionParameters.map((sp) => htmlWriter.write(sp)); + HTML += htmlWriter.save(); + selectionParams(jsWriter, EH.selectionFields); + JS += jsWriter.save(); } } - return { js: "", html: "" }; // htmlWriter.save() }; + return { js: JS, html: HTML }; } elementaryHelp(shlp_key: string): IElementaryHelp { @@ -615,28 +749,26 @@ export class Frontend { const result: IElementaryHelp = { id: shlp_key, title: selection.INTDESCR.DDTEXT as string, - selectionFields: [] as FieldType[], + selectionFields: [] as RfcStructure[], // FieldType[], selectionParameters: [] as string[], blacklisted: false, }; if (VH.blacklist) { result.blacklisted = true; - log.error(`Value Help black-listed: ${shlp_key}`); + log.debug(`Value Help black-listed: ${shlp_key}`); return result; } for (const field of selection.FIELDDESCR) { - const selField = Frontend.dfiesFieldToABAP(field); - const Parameter: ParameterType = { paramType: ParamType.struct, PARAMCLASS: "paramClass", TABNAME: field.TABNAME as string, FIELDNAME: field.FIELDNAME as string, - PARAMTEXT: selField.text.FIELDTEXT as string, + PARAMTEXT: field.FIELDTEXT as string, functionName: `valueHelp`, - paramName: `selection`, + paramName: `searchParamLow`, required: "", //default?: string; // nativeKey?: string; @@ -644,11 +776,11 @@ export class Frontend { const html_field = this.html_field( Parameter, - selField, + Frontend.dfiesFieldToABAP(field), field.FIELDNAME as string ); - result.selectionFields.push(selField); + result.selectionFields.push(field); result.selectionParameters.push(html_field.html); } @@ -690,6 +822,14 @@ export class Frontend { if (field.CONVEXIT) result.input.CONVEXIT = field.CONVEXIT as string; if (field.MEMORYID) result.input.MEMORYID = field.MEMORYID as string; if (field.shlpId) result.input.shlpId = field.shlpId as string; + if (field.valueInputType) { + result.format.valueInputType = field.valueInputType as string; + if (field.valueInputType === ValueInput.binary) { + if (!field.customCheckbox) { + delete result.input.shlpId; + } + } + } if (isEmpty(result.input)) delete result.input; if (field.valueInputType) { @@ -913,12 +1053,17 @@ export class Frontend { result.abap.unit = Field.format.REFFIELD; } else { result.abap.unit = "!notfound"; - log.error( - `${Field["format"]["DATATYPE"]} unit not found for rfm: ${Param.functionName} parameter: ${Param.paramName}` + - field_name - ? ` field: ${field_name}` - : "" - ); + if (Param.functionName === "valueHelp") { + log.error( + `${Field.format.DATATYPE} unit not found for ${ + field_name ? field_name : Param.FIELDNAME + }` + ); + } else { + log.error( + `${Field.format.DATATYPE} unit not found for rfm: ${Param.functionName} parameter: ${Param.paramName}` + ); + } } } diff --git a/abap-api-tools/src/ts/utils.ts b/abap-api-tools/src/ts/utils.ts index 1b45fc47..8ebbe33a 100644 --- a/abap-api-tools/src/ts/utils.ts +++ b/abap-api-tools/src/ts/utils.ts @@ -68,6 +68,11 @@ export function makeDir(dir: string): void { log.debug(`mkdir ${dir}`); } +export function rmDir(dir: string): void { + fs.rmSync(dir, { recursive: true, force: true }); + log.debug(`rmdir ${dir}`); +} + export function isEmpty(obj?: unknown[] | Record): boolean { if (obj === undefined) return true; if (Array.isArray(obj)) return obj.length === 0; @@ -127,7 +132,8 @@ export class Writer { this.indent = this.SPACE.repeat(this.indent_count); } - write(line = ""): void { + write(line: string | string[] = ""): void { + if (Array.isArray(line)) line = line.join(""); this.output.push(line.length > 0 ? this.indent + line : line); } diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 00000000..d8339bf0 --- /dev/null +++ b/package-lock.json @@ -0,0 +1,6 @@ +{ + "name": "fundamental-tools", + "lockfileVersion": 2, + "requires": true, + "packages": {} +} diff --git a/package.json b/package.json new file mode 100644 index 00000000..0967ef42 --- /dev/null +++ b/package.json @@ -0,0 +1 @@ +{}