UNPKG

@specs-feup/lara

Version:

A js port of the popular framework for building source-to-source compilers

240 lines (198 loc) 6.52 kB
#!/usr/bin/env node import fs from "fs"; import yargs from "yargs"; import { hideBin } from "yargs/helpers"; import { convertSpecification } from "./convert-joinpoint-specification.js"; import { generateJoinpoints, generateEnums } from "./generate-ts-joinpoints.js"; function buildLaraJoinPoint(inputFileName, outputFileName) { console.log("Hello from build-LaraJoinPoint.js"); console.log("inputFile:", inputFileName); console.log("outputFile:", outputFileName); const jsonSpecification = fs.readFileSync(inputFileName, "utf8"); const specification = convertSpecification(JSON.parse(jsonSpecification)); // Create output file if it doesn't exist const outputFile = fs.openSync(outputFileName, "w"); fs.writeSync( outputFile, `////////////////////////////////////////////////////// // This file is generated by build-LaraJoinPoint.js // ////////////////////////////////////////////////////// /* eslint-disable @typescript-eslint/ban-types */ /* eslint-disable @typescript-eslint/no-explicit-any */ /* eslint-disable @typescript-eslint/no-unsafe-assignment */ /* eslint-disable @typescript-eslint/no-unsafe-call */ /* eslint-disable @typescript-eslint/no-unsafe-member-access */ /* eslint-disable @typescript-eslint/no-unsafe-return */ /* eslint-disable @typescript-eslint/no-duplicate-type-constituents */ import java from "java"; import JavaTypes, { Engine, engine, NodeJavaPrefix } from "./lara/util/JavaTypes.js"; /** * Type for type equality assertion. If T is equal to U, return Y, otherwise return N. * Source: https://github.com/Microsoft/TypeScript/issues/27024#issuecomment-421529650 * @example * type A = Equals<string, string, "Y", "N">; // "Y" * type B = Equals<string, number, "Y", "N">; // "N" */ type Equals<T, U, Y = unknown, N = never> = (<G>() => G extends T ? 1 : 2) extends (<G>() => G extends U ? 1 : 2) ? Y : N; type DefaultAttributeHelper< T extends typeof LaraJoinPoint, DefaultAttributeMap, PrivateMapper, > = { [K in keyof DefaultAttributeMap]: K extends keyof PrivateMapper ? Equals<T, PrivateMapper[K], DefaultAttributeMap[K], never> : never; }[keyof DefaultAttributeMap]; // Extract the type A from A | undefined type ExtractedType<T> = T extends undefined ? never : T; export type DefaultAttribute<T extends typeof LaraJoinPoint> = DefaultAttributeHelper< T, ExtractedType<T["_defaultAttributeInfo"]["map"]>, ExtractedType<T["_defaultAttributeInfo"]["type"]> >; type NameFromWrapperClassHelper<T extends typeof LaraJoinPoint, U> = { [K in keyof U]: Equals<T, U[K], K, never>; }[keyof U]; export type NameFromWrapperClass<T extends typeof LaraJoinPoint> = NameFromWrapperClassHelper< T, ExtractedType<T["_defaultAttributeInfo"]["jpMapper"]> >;\n\n` ); generateJoinpoints(specification.joinpoints, outputFile); generateEnums(specification.enums, outputFile); generateJoinpointWrapper(specification.joinpoints, outputFile); fs.closeSync(outputFile); } function generateJoinpointWrapper(joinpoints, outputFile) { fs.writeSync( outputFile, `\nexport type JoinpointMapperType = { [key: string]: typeof LaraJoinPoint };\n const JoinpointMappers: JoinpointMapperType[] = [];\n` ); fs.writeSync( outputFile, `\nexport function registerJoinpointMapper(mapper: JoinpointMapperType): void { JoinpointMappers.push(mapper); }\n` ); fs.writeSync( outputFile, `\n/** * This function is for internal use only. DO NOT USE IT! */ export function clearJoinpointMappers(): void { JoinpointMappers.length = 0; } /** * This function is for internal use only. DO NOT USE IT! */ export function getJoinpointMappers(): JoinpointMapperType[] { return JoinpointMappers; }\n` ); fs.writeSync( outputFile, `\nexport function wrapJoinPoint(obj: any): any { if (JoinpointMappers.length === 0) { return obj; } if (obj === undefined) { return obj; } if (obj instanceof LaraJoinPoint) { return obj; } if (ArrayBuffer.isView(obj)) { return Array.from(obj as any).map(wrapJoinPoint); } if (typeof obj !== "object") { return obj; } if (Array.isArray(obj)) { return obj.map(wrapJoinPoint); } if (!JavaTypes.isJavaObject(obj)) { return obj; } if ( JavaTypes.instanceOf(obj, "pt.up.fe.specs.jsengine.node.UndefinedValue") ) { return undefined; } if ( JavaTypes.instanceOf(obj, "org.suikasoft.jOptions.DataStore.DataClass") && !JavaTypes.instanceOf(obj, "pt.up.fe.specs.clava.ClavaNode") ) { return obj; } if (obj.getClass().isEnum()) { return obj.toString(); } const isJavaJoinPoint = JavaTypes.JoinPoint.isJoinPoint(obj); if (!isJavaJoinPoint) { throw new Error( // eslint-disable-next-line @typescript-eslint/restrict-template-expressions \`Given Java join point is a Java class but is not a JoinPoint: \${obj.getClass()}\` ); } const jpType: string = obj.getJoinPointType(); for (const mapper of JoinpointMappers) { if (mapper[jpType]) { return new mapper[jpType](obj); } } throw new Error("No mapper found for join point type: " + jpType); }\n` ); fs.writeSync( outputFile, `\nexport function unwrapJoinPoint(obj: any): any { if (obj instanceof LaraJoinPoint) { return obj._javaObject; } if (Array.isArray(obj)) { if (engine == Engine.NodeJS) { const isJpArray = obj.reduce((prev, curr) => { return prev && curr instanceof LaraJoinPoint; }, true); const getClassName = (jp: LaraJoinPoint) => Object.getPrototypeOf(jp._javaObject).constructor.name; if (isJpArray) { const clazz = ( obj.map(getClassName).reduce((prev, curr) => { if (prev != curr) { return undefined; } return prev; }) ?? "java.lang.Object" ) .replace(NodeJavaPrefix, "") .replaceAll("_", "."); return java.newArray(clazz, obj.map(unwrapJoinPoint)); } } return obj.map(unwrapJoinPoint); } return obj; }\n` ); } const args = yargs(hideBin(process.argv)) .scriptName("build-LaraJoinPoint") .option("i", { alias: "input", describe: "Path to JSON config file", type: "string", }) .option("o", { alias: "output", describe: "Path to the output file", type: "string", }) .help() .showHelpOnFail(true) .strict() .parse(); buildLaraJoinPoint(args.input, args.output);