Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 0 additions & 17 deletions build-lualib.js

This file was deleted.

3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -18,13 +18,14 @@
"dist/**/*.js",
"dist/**/*.lua",
"dist/**/*.ts",
"dist/lualib/*.json",
"language-extensions/**/*.ts"
],
"main": "dist/index.js",
"types": "dist/index.d.ts",
"scripts": {
"build": "tsc && npm run build-lualib",
"build-lualib": "node build-lualib.js",
"build-lualib": "node dist/tstl.js -p src/lualib/tsconfig.json",
"pretest": "npm run lint && npm run check:language-extensions && npm run build-lualib",
"test": "jest",
"lint": "npm run lint:eslint && npm run lint:prettier",
Expand Down
1 change: 0 additions & 1 deletion src/CompilerOptions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,6 @@ export type CompilerOptions = OmitIndexSignature<ts.CompilerOptions> & {

export enum LuaLibImportKind {
None = "none",
Always = "always",
Inline = "inline",
Require = "require",
}
Expand Down
140 changes: 76 additions & 64 deletions src/LuaLib.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import * as path from "path";
import { EmitHost } from "./transpilation";
import * as lua from "./LuaAST";

export enum LuaLibFeature {
ArrayConcat = "ArrayConcat",
Expand Down Expand Up @@ -99,81 +100,54 @@ export enum LuaLibFeature {
Unpack = "Unpack",
}

/* eslint-disable @typescript-eslint/naming-convention */
const luaLibDependencies: Partial<Record<LuaLibFeature, LuaLibFeature[]>> = {
ArrayConcat: [LuaLibFeature.ArrayIsArray],
ArrayFlat: [LuaLibFeature.ArrayConcat, LuaLibFeature.ArrayIsArray],
ArrayFlatMap: [LuaLibFeature.ArrayConcat, LuaLibFeature.ArrayIsArray],
Await: [LuaLibFeature.InstanceOf, LuaLibFeature.New, LuaLibFeature.Promise],
Decorate: [LuaLibFeature.ObjectGetOwnPropertyDescriptor, LuaLibFeature.SetDescriptor, LuaLibFeature.ObjectAssign],
DelegatedYield: [LuaLibFeature.StringAccess],
Delete: [LuaLibFeature.ObjectGetOwnPropertyDescriptors, LuaLibFeature.Error, LuaLibFeature.New],
Error: [LuaLibFeature.Class, LuaLibFeature.ClassExtends, LuaLibFeature.New],
FunctionBind: [LuaLibFeature.Unpack],
Generator: [LuaLibFeature.Symbol],
InstanceOf: [LuaLibFeature.Symbol],
Iterator: [LuaLibFeature.Symbol],
NumberToString: [LuaLibFeature.StringAccess],
ObjectDefineProperty: [LuaLibFeature.CloneDescriptor, LuaLibFeature.SetDescriptor],
ObjectFromEntries: [LuaLibFeature.Iterator, LuaLibFeature.Symbol],
Promise: [
LuaLibFeature.ArrayPush,
LuaLibFeature.Class,
LuaLibFeature.FunctionBind,
LuaLibFeature.InstanceOf,
LuaLibFeature.New,
],
PromiseAll: [LuaLibFeature.InstanceOf, LuaLibFeature.New, LuaLibFeature.Promise, LuaLibFeature.Iterator],
PromiseAllSettled: [LuaLibFeature.InstanceOf, LuaLibFeature.New, LuaLibFeature.Promise, LuaLibFeature.Iterator],
PromiseAny: [
LuaLibFeature.ArrayPush,
LuaLibFeature.InstanceOf,
LuaLibFeature.New,
LuaLibFeature.Promise,
LuaLibFeature.Iterator,
],
PromiseRace: [
LuaLibFeature.ArrayPush,
LuaLibFeature.InstanceOf,
LuaLibFeature.New,
LuaLibFeature.Promise,
LuaLibFeature.Iterator,
],
ParseFloat: [LuaLibFeature.StringAccess],
ParseInt: [LuaLibFeature.StringSubstr, LuaLibFeature.StringSubstring],
SetDescriptor: [LuaLibFeature.CloneDescriptor],
Spread: [LuaLibFeature.Iterator, LuaLibFeature.StringAccess, LuaLibFeature.Unpack],
StringSplit: [LuaLibFeature.StringSubstring, LuaLibFeature.StringAccess],
SymbolRegistry: [LuaLibFeature.Symbol],

Map: [LuaLibFeature.InstanceOf, LuaLibFeature.Iterator, LuaLibFeature.Symbol, LuaLibFeature.Class],
Set: [LuaLibFeature.InstanceOf, LuaLibFeature.Iterator, LuaLibFeature.Symbol, LuaLibFeature.Class],
WeakMap: [LuaLibFeature.InstanceOf, LuaLibFeature.Iterator, LuaLibFeature.Symbol, LuaLibFeature.Class],
WeakSet: [LuaLibFeature.InstanceOf, LuaLibFeature.Iterator, LuaLibFeature.Symbol, LuaLibFeature.Class],
};
/* eslint-enable @typescript-eslint/naming-convention */

export function loadLuaLibFeatures(features: Iterable<LuaLibFeature>, emitHost: EmitHost): string {
let result = "";
export interface LuaLibFeatureInfo {
dependencies?: LuaLibFeature[];
exports: string[];
}
export type LuaLibModulesInfo = Record<LuaLibFeature, LuaLibFeatureInfo>;

export const luaLibModulesInfoFileName = "lualib_module_info.json";
let luaLibModulesInfo: LuaLibModulesInfo | undefined;
export function getLuaLibModulesInfo(emitHost: EmitHost): LuaLibModulesInfo {
if (luaLibModulesInfo === undefined) {
const lualibPath = path.resolve(__dirname, `../dist/lualib/${luaLibModulesInfoFileName}`);
const result = emitHost.readFile(lualibPath);
if (result !== undefined) {
luaLibModulesInfo = JSON.parse(result) as LuaLibModulesInfo;
} else {
throw new Error(`Could not load lualib dependencies from '${lualibPath}'`);
}
}
return luaLibModulesInfo;
}

export function readLuaLibFeature(feature: LuaLibFeature, emitHost: EmitHost): string {
const featurePath = path.resolve(__dirname, `../dist/lualib/${feature}.lua`);
const luaLibFeature = emitHost.readFile(featurePath);
if (luaLibFeature === undefined) {
throw new Error(`Could not load lualib feature from '${featurePath}'`);
}
return luaLibFeature;
}

export function resolveRecursiveLualibFeatures(
features: Iterable<LuaLibFeature>,
emitHost: EmitHost,
luaLibModulesInfo: LuaLibModulesInfo = getLuaLibModulesInfo(emitHost)
): LuaLibFeature[] {
const loadedFeatures = new Set<LuaLibFeature>();
const result: LuaLibFeature[] = [];

function load(feature: LuaLibFeature): void {
if (loadedFeatures.has(feature)) return;
loadedFeatures.add(feature);

const dependencies = luaLibDependencies[feature];
const dependencies = luaLibModulesInfo[feature]?.dependencies;
if (dependencies) {
dependencies.forEach(load);
}

const featurePath = path.resolve(__dirname, `../dist/lualib/${feature}.lua`);
const luaLibFeature = emitHost.readFile(featurePath);
if (luaLibFeature !== undefined) {
result += luaLibFeature + "\n";
} else {
throw new Error(`Could not load lualib feature from '${featurePath}'`);
}
result.push(feature);
}

for (const feature of features) {
Expand All @@ -183,6 +157,44 @@ export function loadLuaLibFeatures(features: Iterable<LuaLibFeature>, emitHost:
return result;
}

export function loadInlineLualibFeatures(features: Iterable<LuaLibFeature>, emitHost: EmitHost): string {
let result = "";

for (const feature of resolveRecursiveLualibFeatures(features, emitHost)) {
const luaLibFeature = readLuaLibFeature(feature, emitHost);
result += luaLibFeature + "\n";
}

return result;
}

export function loadImportedLualibFeatures(features: Iterable<LuaLibFeature>, emitHost: EmitHost): lua.Statement[] {
const luaLibModuleInfo = getLuaLibModulesInfo(emitHost);

const imports = Array.from(features).flatMap(feature => luaLibModuleInfo[feature].exports);

const requireCall = lua.createCallExpression(lua.createIdentifier("require"), [
lua.createStringLiteral("lualib_bundle"),
]);
if (imports.length === 0) {
return [];
}

const luaLibId = lua.createIdentifier("____lualib");
const importStatement = lua.createVariableDeclarationStatement(luaLibId, requireCall);
const statements: lua.Statement[] = [importStatement];
// local <export> = ____luaLib.<export>
for (const item of imports) {
statements.push(
lua.createVariableDeclarationStatement(
lua.createIdentifier(item),
lua.createTableIndexExpression(luaLibId, lua.createStringLiteral(item))
)
);
}
return statements;
}

let luaLibBundleContent: string;
export function getLuaLibBundle(emitHost: EmitHost): string {
if (luaLibBundleContent === undefined) {
Expand Down
21 changes: 10 additions & 11 deletions src/LuaPrinter.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,11 @@
import * as path from "path";
import { Mapping, SourceMapGenerator, SourceNode } from "source-map";
import { getEmitPath } from ".";
import * as ts from "typescript";
import { CompilerOptions, isBundleEnabled, LuaLibImportKind } from "./CompilerOptions";
import * as lua from "./LuaAST";
import { loadLuaLibFeatures, LuaLibFeature } from "./LuaLib";
import { loadInlineLualibFeatures, LuaLibFeature, loadImportedLualibFeatures } from "./LuaLib";
import { isValidLuaIdentifier, shouldAllowUnicode } from "./transformation/utils/safe-names";
import { EmitHost } from "./transpilation";
import { EmitHost, getEmitPath } from "./transpilation";
import { intersperse, normalizeSlashes } from "./utils";

// https://www.lua.org/pil/2.4.html
Expand Down Expand Up @@ -233,18 +232,18 @@ export class LuaPrinter {
if (!this.options.noHeader) {
header += tstlHeader;
}
let statements = file.statements;

const luaLibImport = this.options.luaLibImport ?? LuaLibImportKind.Require;
if (
luaLibImport === LuaLibImportKind.Always ||
(luaLibImport === LuaLibImportKind.Require && file.luaLibFeatures.size > 0)
) {
// Require lualib bundle
header += 'require("lualib_bundle");\n';
if (luaLibImport === LuaLibImportKind.Require && file.luaLibFeatures.size > 0) {
// Import lualib features
const importStatements = loadImportedLualibFeatures(file.luaLibFeatures, this.emitHost);

statements = importStatements.concat(statements);
} else if (luaLibImport === LuaLibImportKind.Inline && file.luaLibFeatures.size > 0) {
// Inline lualib features
header += "-- Lua Library inline imports\n";
header += loadLuaLibFeatures(file.luaLibFeatures, this.emitHost);
header += loadInlineLualibFeatures(file.luaLibFeatures, this.emitHost);
}

if (this.options.sourceMapTraceback && !isBundleEnabled(this.options)) {
Expand All @@ -253,7 +252,7 @@ export class LuaPrinter {
header += `${LuaPrinter.sourceMapTracebackPlaceholder}\n`;
}

return this.concatNodes(header, ...this.printStatementArray(file.statements));
return this.concatNodes(header, ...this.printStatementArray(statements));
}

protected pushIndent(): void {
Expand Down
1 change: 1 addition & 0 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,3 +8,4 @@ export { LuaLibFeature } from "./LuaLib";
export * from "./LuaPrinter";
export * from "./transformation/context";
export * from "./transpilation";
export { ProcessedFile } from "./transpilation/utils";
Loading