UNPKG

intelligen

Version:

Generate VS Code intellisense from Service Now Instance data

229 lines (205 loc) 9.05 kB
import { Console } from "console"; import fs from 'fs'; import directory from "./data.cjs"; const libPath = '\\..\\lib'; const dataPath = `${libPath}\\data\\`; const errorOutput = fs.createWriteStream('./stderr.log'); const checkFileTypeIsAllowed = (type) => { let check = false; switch(type) { case 'string': check = true; break; case 'integer': check = true; break; case 'boolean': check = true; break; case 'glide_date_time': check = true; break; case 'float': check = true; break; default: break; } return check; } //new<T extends tableNames>(tableName: T): ref<T>; const methodFunc = `interface m<tb> extends Omit<GlideRecord_proto, ch>{/** Retrieves the underlying value of a field */ getValue(fieldName: tb): s; /** Adds a filter to return records based on a relationship in a related table */ addJoinQuery<t extends tableNames>(joinTable: t, primaryField: tb, joinTableField: tables[t]['f']): q<t>; /** Sets the value for the specified field. */ setValue(fieldName: tb, value: a): vv; /** Adds a filter to return records by specifying a field and value. You can use an optional 'operator' as a second parameter */ addQuery(name: tb, value: s): s; /** Adds a filter to return records by specifying a field and value. You can use an optional 'operator' as a second parameter */ addQuery<q extends n_s>(name: tb, operator: q | s, value: q extends mut ? n | s : q extends so ? s : q extends no ? n : a): vv; /** Adds a filter to return active records */ addActiveQuery(): GlideQueryCondition; /** Adds a filter to return records where the specified field is null */ addNullQuery(fieldName: tb): vv; /** Adds a filter to return records where the specified field is not null */ addNotNullQuery(fieldName: tb): vv; /** Retrieves the GlideElement for a specified field */ getElement(fieldName: tb): GlideElement; /** Retrieves the display value for the current record */ getDisplayValue(fieldName: tb): s; /** Determines if the given field is defined in the current table */ isValidField(fieldName: tb): b; /** Specifies an orderBy column */ orderBy(fieldName: tb): vv; /** Specifies a descending orderBy */ orderByDesc(fieldName: tb): vv; /** Adds an aggregate * * -Glide Aggregate method- */ addAggregate(aggregate: s, field: tb): vv; /** Gets the value of the specified aggregate * * -Glide Aggregate method- */ getAggregate(aggregate: s, field: tb): s; /** Retrieves the n of rows in the GlideRecord * * -Glide Aggregate method- */ getRowCount(): n; /** Gets the query necessary to return the current aggregate * * -Glide Aggregate method- */ getAggregateEncodedQuery(): s; /** Provides the name of a field to use in grouping the aggregates. May be called numerous times to set multiple group fields * * -Glide Aggregate method- */ groupBy(field: tb): vv; /** Sorts the aggregates based on the specified aggregate and field * * -Glide Aggregate method- */ orderByAggregate(aggregate: s, field: tb): vv; /** * Sets whether the results are to be grouped * * -Glide Aggregate method- */ setGroup(value: b): b; } interface L<tb> { byLabel: { [key in keyof tb as tb[key]['label']] : key; } } ` const internal_types = { 'string': 's', 'integer': 'n', 'boolean': 'b', 'glide_date_time': 'GlideDate_proto', 'float': 'n' } export const dataFieldsIntellisenseGen = (data, path='.\\') => { let arr = []; let tables = {}; if(data) { data = JSON.parse(data); } arr = data.records; tables = data.tables; console.log('Generating intellisense from local data...'); const fileName = 'con.d.ts' const output = fs.createWriteStream(`${path}${fileName}`); const logger = new Console(output, errorOutput); const types = ` type fp = {getLabel(): string}; type vv = void; type s = string; type b = boolean; type n = number; type a = any; type ff= Function; type ch = 'getValue'|'addJoinQuery'|'setValue'|'addQuery'|'addActiveQuery'|'addNullQuery'|'addNotNullQuery'|'getElement'|'getDisplayValue'|'isValidField'|'orderBy'|'orderByDesc'|'addAggregate'|'getAggregate'|'getRowCount'|'getAggregateEncodedQuery'|'groupBy'|'orderByAggregate'|'setGroup'; type nch = 'insert'|'query'|'get'|'update'|'updateMultiple'| 'deleteRecord'|'deleteMultiple'| 'setAbortAction'| 'setWorkflow'| 'getTableName'|'getRecordClassName'|'getEncodedQuery'|'addEncodedQuery'| 'next'|'hasNext'|'getUniqueValue'|'getDisplayName'|'getClassDisplayValue'|'isValidRecord'|'initialize'| 'newRecord'| 'isNewRecord'|'isValid'|'operation'|'setLimit'| 'chooseWindow'| 'canCreate'|'canDelete'|'canRead'|'canWrite'|'setNewGuidValue'| 'getLink'|'getLastErrorMessage'|'getAttribute'|'getCategory'|'setCategory'| 'autoSysFields'| 'isActionAborted'|'addFunction' ` + methodFunc; const fieldsByTable = {}; arr.forEach( field => { let {name, element: fieldName, reference, internal_type: type, column_label: label} = field; let fieldObj = { fieldName, type, label } if(reference) { fieldObj.reference = reference; } if(fieldsByTable[name]) { fieldsByTable[name].push(fieldObj); } else { fieldsByTable[name] = []; } }); const tableNames = Object.keys(fieldsByTable); const tableNameDecl = `type tableNames =${tableNames.map((_, i)=> `T${i}`).join('|')};${tableNames.map((tbName, i)=> `type T${i}='${tbName}';`).join('')}`; logger.log(types + tableNameDecl); let tableNamesInstace= `interface GlideRecord{ new<t extends tableNames>(tableName: t): tables[t]['p']; new(): {}; } ` const ref = `type tables = {${tableNames.map((tbName, i) => { return `${tbName}:{p:t${i}; M: m<t${i}_f>; L: L<t${i}v>; f: t${i}_f};` }).join('')}}`; logger.log(ref + '\n' + tableNamesInstace); tableNames.forEach((tbName, tbI) => { let extension = tables[tbName]; let extensionExists = !!extension && !!tableNames.includes(extension); let extensionNumber = tableNames.findIndex(a => a == extension); let extensionTable = extensionExists ? `extends t${extensionNumber}` : ''; let extendFields = extensionExists ? `& t${extensionNumber}v` : ''; let properties = fieldsByTable[tbName]; let pairProps = properties.map( prop => { let { fieldName, reference, type, label } = prop; let res; let letters = label.split('"'); label = letters.filter(l => { return l != "'"; }).join(''); let refIndex = tableNames.findIndex((tb) => reference == tb); if(reference && refIndex!= -1) { res =`\t/** References ${reference} \n*\n\t* Label: ${label}*/\n\t${fieldName} : t${refIndex} & fp & {label: "${label}"};`; } else { res =`\t/** Label: ${label || 'p'} */\n\t${fieldName} : ${internal_types[type] || 's'} & fp & {label: "${label}"};` } return res; }).join('\n'); let typeFields = `\n\ttype t${tbI}_f = ${properties.map(prop => `'${prop.fieldName}'`).join('|')} ${extensionExists ? `| t${extensionNumber}_f`: ''};`; // let valueAutofill = methodsTemplate(`t${tbI}_f`); let prototypeDeclaration = `${typeFields} \n\ttype t${tbI}v = {\n` + pairProps + `\n}${extendFields} \n` + `type t${tbI} = t${tbI}v & tables[T${tbI}]['M'] & tables[T${tbI}]['L'];`; let res = prototypeDeclaration + '\n'; logger.log(res); }); console.log('Finished generating Intellisense from the local data.'); } export const snippetIntellisenseGen = (data) => { const fdataPath = directory + dataPath; const fdtsPath = directory + '\\..\\..\\..\\autocomplete'; const clientAPI = fs.readFileSync(fdataPath + '\\clientAPI.txt','utf-8'); const serverAPI = fs.readFileSync(fdataPath + '\\serverAPI.txt','utf-8'); const clientAPIout = fs.createWriteStream(fdtsPath + '\\client.d.ts'); const serverAPIout = fs.createWriteStream(fdtsPath + '\\server.d.ts'); const clientLogger = new Console(clientAPIout, errorOutput); const serverLogger = new Console(serverAPIout, errorOutput); clientLogger.log(clientAPI); serverLogger.log(serverAPI); return dataFieldsIntellisenseGen(data, fdtsPath + '\\'); } export const scopedIntellisenseGen = (data) => { return dataFieldsIntellisenseGen(data ,directory + '\\..\\lib\\dts') }