@lcap/nasl-parser
Version:
Take Nasl text to Nasl AST with the help of generalized parsing.
256 lines (210 loc) • 7.15 kB
text/typescript
import * as nasl from '@lcap/nasl';
import { isIdentifier } from '@lcap/nasl-concepts/asserts';
export type AstCstPack = {
nasl: any,
cst: any
}
export const NASL = 'nasl';
export const NASL_CORE_NL = 'nasl::core';
export const NASL_CORE_AST = 'nasl.core';
export const NASL_UTIL_NL = 'nasl::util';
export const NASL_UTIL_AST = 'nasl.util';
export const NASL_LOGGING_AST = 'nasl.logging';
export const NASL_COLLECTION_AST = 'nasl.collection';
export const APIS = 'apis';
export const APP = 'app';
export const APP_LOGICS_NL = 'app::logics';
export const APP_LOGICS_AST = 'app.logics';
export const APP_STRUCTURE_AST = 'app.structures';
export const APP_ENTITY_AST = 'app.dataSources.defaultDS.entities';
export const APP_ENUM = 'app.enums';
export const CONNECTOR = 'connector';
export const PRIMITIVE_TYPES : string[] = ['Boolean', 'String', 'Integer', 'Decimal', 'Date', 'Time', 'DateTime', 'Unit'];
export const CODEWAVE = 'CodeWave';
export const NAMESPACE_SEP = '::';
export const NAMESPACE_SEP_AST = '.';
export const projectIdentifier = (id : any): string => (id?.namespace ?? []).concat(id.name).join(NAMESPACE_SEP);
export const projectIdentifierAST = (id : any): string => (id?.namespace ?? []).concat(id?.name).join(NAMESPACE_SEP_AST);
export const isBuiltinPrimitiveType = (name : string) => PRIMITIVE_TYPES.includes(name);
export const head = <T>(arr: Array<T>): T => {
if (isEmpty(arr)) {
throw new Error('empty array');
}
return arr[0];
}
export const last = <T>(arr: Array<T>): T => {
if (isEmpty(arr)) {
throw new Error('empty array');
}
return arr[arr.length - 1];
}
export const tail = <T>(arr: Array<T>): Array<T> => arr.slice(1);
export function zipWith<A, B, C>(f: (a : A, b : B) => C , arr1: Array<A>, arr2 : Array<B>) {
const res = [];
for (let i = 0; i < arr1.length; i++) {
res.push(f(arr1[i], arr2[i]));
}
return res;
}
export function foldR<A, B>(lam: (a : A, b : B) => B, acc: B, arr : Array<A>): B {
if (isEmpty(arr)) {
return acc;
}
return lam(head(arr), foldR(lam, acc, tail(arr)));
}
export const foldR1 = <A, B>(lam: (a : A, b : B) => B, morph: (a: A) => B) =>
(arr : Array<A>) => {
if (isEmpty(arr)) {
throw new Error('empty array');
}
if (arr.length === 1) {
return morph(arr[0]);
}
return lam(head(arr), foldR1(lam, morph)(tail(arr)));
}
export const identity = <T>(x: T): T => x;
export function isEmpty<T>(arr: Array<T>): boolean {
if (!arr) {
throw new Error('input is null or undefined');
}
return arr.length === 0;
}
export function splitByPredicate<T>(arr : Array<T>, pred : (_ : T) => boolean) : [Array<T>, Array<T>] {
const sat = [];
const unsat = [];
arr.forEach(e => {
if (pred(e)) {
sat.push(e);
} else {
unsat.push(e);
}
})
return [sat, unsat];
}
export function composeWithEnv<T, A, B, C>(
f : (env: T, _0: A) => B,
g : (env: T, _0: B) => C) :
(env: T, _0: A) => C {
return (env: T, a : A) => g(env, f(env, a));
}
export function sequenceWithEnv_<T, A, B, C>(
f : (env: T, _0: A) => B,
g : (env: T, _0: A) => C) :
(env: T, _0: A) => C {
return (env: T, a : A) => { f(env, a); return g(env, a) };
}
export class Visitor {
preOrderVisitAll<T, R1, R2>(
anyInfo: T,
obj: any,
f: (_0: T, _1: any) => R1,
postWork?: (_0: T, _1: R1) => R2) {
obj = f(anyInfo, obj);
if (Array.isArray(obj)) {
for (let i = 0; i < obj.length; i++) {
const newElem = this.preOrderVisitAll(anyInfo, obj[i], f, postWork);
obj[i] = newElem;
}
} else if (obj && typeof obj === 'object') {
for (const prop in obj) {
if (prop === 'parentNode') { // 厉害!
continue;
}
const newProp = this.preOrderVisitAll(anyInfo, obj[prop], f, postWork);
if (newProp !== obj[prop]) {
obj[prop] = newProp;
}
}
}
if (postWork) {
return postWork(anyInfo, obj);
} else {
return obj;
}
}
}
export const createQIdentifier = (name : string, namespace : Array<any> = []) => TYPE('QIdentifier', { namespace, name });
export const withNoEnv = lam => (env, obj) => lam(obj);
export const prependNamespace = (ns: Array<string>, name: string | { namespace: Array<string>, name: string }): string => {
if (typeof name === 'string') {
return ns.concat(name).join(NAMESPACE_SEP_AST);
} else if ('namespace' in name) {
return ns.concat(name.namespace, name.name).join(NAMESPACE_SEP_AST);
} else {
throw new Error(`prependNamespace: invalid input ${ns.toString()} ${name}`);
}
}
// const createTypeConstructor = (name : string) => createIdentifier(name, []);
export const createNamedType = (tyCon, tyVars = [], isConst : boolean = false) => {
return TYPE('NamedType', { tyCon, tyVars })
}
export const extractIdent = (me: nasl.MemberExpression) => isIdentifier(me.object)? me.object : extractIdent(me.object as nasl.MemberExpression);
export const createReferenceType = (name : string) => {
return createQIdentifier(name, []);
}
export function wellDefined<T>(node : T) : boolean {
return node !== undefined && node !== null;
}
export function SimpleSillyDeepClone<T>(obj : T) : T {
return JSON.parse(JSON.stringify(obj));
}
export function TYPE(ty : string, data? : any) {
if (data) {
data['__type'] = ty;
return data;
} else {
return (d: any) => {
d[0]['__type'] = ty;
return d[0];
}
}
}
export function PackNaslAndCst(nasl : any, cst : any) {
return { nasl, cst };
}
export function PackNaslAndCstSeq(ls) {
// if (!ls) {
// return undefined;
// }
// if (!Array.isArray(ls)) {
// return ls;
// }
return PackNaslAndCst(ls.map(getNasl), ls.map(getCst));
}
export function AutoPackNaslAndCst(obj) {
const res = { nasl: {}, cst: {} };
for (const prop in obj) {
if (Object.hasOwn(obj, prop)) {
res.nasl[prop] = obj[prop]?.nasl;
res.cst[prop] = obj[prop]?.cst;
}
}
return res;
}
// export function AutoLiftNaslAndCst(obj) {
// const res = { nasl: {}, cst: {} };
// for (const prop in obj?.nasl) {
// if (Object.hasOwn(obj?.nasl, prop)) {
// res.nasl[prop] = prop;
// }
// }
// for (const prop in obj?.cst) {
// if (Object.hasOwn(obj?.cst, prop)) {
// res.cst[prop] = prop;
// }
// }
// return res;
// }
export const getCst = o => o.cst;
export const getNasl = o => o.nasl;
export function removeDup<T>(list: T[]): T[] {
const seen = new Set<T>();
return list.filter(element => {
if (seen.has(element)) {
return false;
} else {
seen.add(element);
return true;
}
});
}