UNPKG

@lcap/nasl-parser

Version:

Take Nasl text to Nasl AST with the help of generalized parsing.

256 lines (210 loc) 7.15 kB
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; } }); }