intelligen
Version:
Generate VS Code intellisense from Service Now Instance data
229 lines (205 loc) • 9.05 kB
JavaScript
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')
}