| 28 | })); |
| 29 | |
| 30 | class LuaLibPlugin implements tstl.Plugin { |
| 31 | // Plugin members |
| 32 | public visitors = { |
| 33 | [ts.SyntaxKind.SourceFile]: this.lualibFileVisitor.bind(this), |
| 34 | }; |
| 35 | |
| 36 | public printer: tstl.Printer = (program, emitHost, fileName, file) => |
| 37 | new LuaLibPrinter(emitHost, program, fileName).print(file); |
| 38 | |
| 39 | public afterPrint(program: ts.Program, options: tstl.CompilerOptions, emitHost: EmitHost, result: ProcessedFile[]) { |
| 40 | void options; |
| 41 | |
| 42 | // Write lualib dependency json |
| 43 | const { result: luaLibModuleInfo, diagnostics } = this.createLuaLibModulesInfo(); |
| 44 | const emitBOM = options.emitBOM ?? false; |
| 45 | emitHost.writeFile( |
| 46 | path.join(tstl.getEmitOutDir(program), luaLibModulesInfoFileName), |
| 47 | JSON.stringify(luaLibModuleInfo, null, 2), |
| 48 | emitBOM |
| 49 | ); |
| 50 | |
| 51 | // Flatten the output folder structure; we do not want to keep the target-specific directories |
| 52 | for (const file of result) { |
| 53 | let outPath = file.fileName; |
| 54 | while (outPath.includes("lualib") && path.basename(path.dirname(outPath)) !== "lualib") { |
| 55 | const upOne = path.join(path.dirname(outPath), "..", path.basename(outPath)); |
| 56 | outPath = path.normalize(upOne); |
| 57 | } |
| 58 | file.fileName = outPath; |
| 59 | } |
| 60 | |
| 61 | // Create map of result files keyed by their 'lualib name' |
| 62 | const exportedLualibFeatures = new Map(result.map(f => [path.basename(f.fileName).split(".")[0], f.code])); |
| 63 | |
| 64 | // Figure out the order required in the bundle by recursively resolving all dependency features |
| 65 | const allFeatures = Object.values(LuaLibFeature) as LuaLibFeature[]; |
| 66 | const luaTarget = options.luaTarget ?? tstl.LuaTarget.Universal; |
| 67 | const orderedFeatures = resolveRecursiveLualibFeatures(allFeatures, luaTarget, emitHost, luaLibModuleInfo); |
| 68 | |
| 69 | // Concatenate lualib files into bundle with exports table and add lualib_bundle.lua to results |
| 70 | let lualibBundle = orderedFeatures.map(f => exportedLualibFeatures.get(LuaLibFeature[f])).join("\n"); |
| 71 | const exports = allFeatures.flatMap(feature => luaLibModuleInfo[feature].exports); |
| 72 | lualibBundle += getLualibBundleReturn(exports); |
| 73 | result.push({ fileName: "lualib_bundle.lua", code: lualibBundle }); |
| 74 | |
| 75 | return diagnostics; |
| 76 | } |
| 77 | |
| 78 | // Internals |
| 79 | protected featureExports: Map<tstl.LuaLibFeature, Set<string>> = new Map(); |
| 80 | protected featureDependencies: Map<tstl.LuaLibFeature, Set<tstl.LuaLibFeature>> = new Map(); |
| 81 | |
| 82 | protected lualibFileVisitor(file: ts.SourceFile, context: tstl.TransformationContext): tstl.File { |
| 83 | const featureName = path.basename(file.fileName, ".ts") as tstl.LuaLibFeature; |
| 84 | if (!(featureName in tstl.LuaLibFeature)) { |
| 85 | context.diagnostics.push(lualibDiagnostic(`File is not a lualib feature: ${featureName}`, file)); |
| 86 | } |
| 87 | |