UNPKG

@specs-feup/lara

Version:

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

279 lines (229 loc) 7.38 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, `/** * Converts Java join point objects to TypeScript objects. */ export interface JoinpointMapper { toJpClass(jpTypename: string): typeof LaraJoinPoint | undefined; toJpInstance(jpTypename: string, javaJp: any): LaraJoinPoint | undefined; fromJpClass(jpType: typeof LaraJoinPoint): string | undefined; } const JoinpointMappers: JoinpointMapper[] = []; /** * 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(): JoinpointMapper[] { return JoinpointMappers; } /** * For mappers based on objects */ export type JoinpointMapperType = { [key: string]: typeof LaraJoinPoint }; export function registerJoinpointMapper(mapper: JoinpointMapperType): void { // Create mapper from object const jpMapper: JoinpointMapper = { toJpClass(jpTypename: string) { return mapper[jpTypename]; }, toJpInstance(jpTypename: string, javaJp: any) { const jpClass = this.toJpClass(jpTypename); if (jpClass) { return new jpClass(javaJp); } return undefined; }, fromJpClass(jpType: typeof LaraJoinPoint) { return Object.keys(mapper).find((key) => mapper[key] === jpType); }, }; JoinpointMappers.push(jpMapper); } /** * For mappers based on functions */ export type JoinpointMapperFunction = ( jpTypename: string ) => typeof LaraJoinPoint | undefined; export function registerJoinpointMapperFunction( mapper: JoinpointMapperFunction ): void { // Create mapper from function const jpMapper = { toJpClass(jpTypename: string): typeof LaraJoinPoint | undefined { return mapper(jpTypename); }, toJpInstance(jpTypename: string, javaJp: any): LaraJoinPoint | undefined { const jpClass = this.toJpClass(jpTypename); if (jpClass) { return new jpClass(javaJp); } return undefined; }, // Not possible to implement with just a function fromJpClass(jpType: typeof LaraJoinPoint): string | undefined { return undefined; }, }; JoinpointMappers.push(jpMapper); } ` ); 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) { const laraJp = mapper.toJpInstance(jpType, obj); if (laraJp) { return laraJp; } } 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)) { 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);