Skip to content

Commit 664cead

Browse files
committed
Initial push
1 parent cec6896 commit 664cead

10 files changed

+492
-0
lines changed

.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
node_modules
2+
.DS_Store
3+
Thumbs.db

.prettierignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
node_modules
2+
yarn.lock

.prettierrc.json

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
{
2+
"$schema": "https://json.schemastore.org/prettierrc",
3+
"semi": true,
4+
"singleQuote": true,
5+
"useTabs": true
6+
}

.vscode/settings.json

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
{
2+
"editor.formatOnSave": true,
3+
"editor.insertSpaces": false,
4+
"editor.formatOnPaste": true,
5+
"editor.tabSize": 2,
6+
"editor.detectIndentation": false,
7+
"[typescript]": {
8+
"editor.defaultFormatter": "esbenp.prettier-vscode"
9+
},
10+
"[md]": {
11+
"editor.defaultFormatter": "esbenp.prettier-vscode"
12+
}
13+
}

README.md

Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,112 @@
1+
# tstl-simple-inline-func
2+
3+
TypeScriptToLua plugin that performs [inline expansion](https://en.wikipedia.org/wiki/Inline_expansion) to functions that you annotate.
4+
5+
This plugin is intended to handle functions that do NOT take parameters. If you need to handle parameters, try [TSTL-extensions by @Cheatoid](https://github.com/Cheatoid/TSTL-extensions) instead.
6+
7+
Inline expansion may or may not provide any performance benefit depending on your Lua runtime. Always measure with real world code.
8+
9+
## Usage
10+
11+
Add a comment containing `@inlineStart` before the function you want to inline, and `@inlineEnd` directly afterwards.
12+
13+
Example:
14+
15+
```ts
16+
/** @inlineStart */
17+
const FOO = () => {
18+
const BAR = 1 + 2 + 3;
19+
};
20+
/** @inlineEnd */
21+
22+
FOO();
23+
```
24+
25+
Becomes:
26+
27+
```lua
28+
-- @inlineStart@inlineEnd
29+
local BAR = 1 + 2 + 3
30+
```
31+
32+
### Subsequent comments
33+
34+
Keep in mind, TSTL may choose to strip comments. If you have multiple inline functions next to each other, you may have to combine comments.
35+
36+
This example may NOT work because the first `@inlineEnd` may get stripped:
37+
38+
```ts
39+
/** @inlineStart */
40+
const FOO = () => {
41+
...
42+
};
43+
/** @inlineEnd */
44+
/** @inlineStart */
45+
const BAR = () => {
46+
...
47+
};
48+
/** @inlineEnd */
49+
```
50+
51+
This example may work because we've combined the middle comments:
52+
53+
```ts
54+
/** @inlineStart */
55+
const FOO = () => {
56+
...
57+
};
58+
/** @inlineEnd @inlineStart */
59+
const BAR = () => {
60+
...
61+
};
62+
/** @inlineEnd */
63+
```
64+
65+
### Removing return
66+
67+
To strip the `return` keyword from your function, add a comment with `@removeReturn` somewhere after `@inlineStart`.
68+
69+
Example:
70+
71+
```ts
72+
/** @inlineStart @removeReturn */
73+
const FOO = () => {
74+
return 7;
75+
};
76+
/** @inlineEnd */
77+
78+
const BAR = FOO();
79+
```
80+
81+
Becomes:
82+
83+
```lua
84+
-- @inlineStart@inlineEnd
85+
local BAR = 7
86+
```
87+
88+
## Installation
89+
90+
1. Install this plugin
91+
92+
```bash
93+
yarn add git+https://[email protected]/thinknathan/tstl-simple-inline-func.git#^1.0.0 -D
94+
# or
95+
npm install git+https://[email protected]/thinknathan/tstl-simple-inline-func.git#^1.0.0 --save-dev
96+
```
97+
98+
2. Add `tstl-simple-inline-func` to `tstl.luaPlugins` in `tsconfig.json`
99+
100+
```diff
101+
{
102+
"tstl": {
103+
"luaPlugins": [
104+
+ { "name": "tstl-simple-inline-func" }
105+
],
106+
}
107+
}
108+
```
109+
110+
## License
111+
112+
CC0

dist/tstl-simple-inline-function.cjs

Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
'use strict';
2+
Object.defineProperty(exports, '__esModule', { value: true });
3+
// Find every instance of inline start and end
4+
const pattern = /@inlineStart(.*?)@inlineEnd/gs;
5+
// Variable to capture matches
6+
let match;
7+
// Running only once doesn't find all values, so we re-run the function this many times
8+
const maxLoop = 200;
9+
// Store list of function names for logging
10+
const changedFunctions = new Set();
11+
function inlineFunction(file) {
12+
const functionsToInline = {};
13+
while ((match = pattern.exec(file.code)) !== null) {
14+
const betweenComments = match[1];
15+
// Check for local function X()
16+
const localFunctionMatch = betweenComments.match(
17+
/function\s+(\w+)\s*\([^)]*\)/,
18+
);
19+
if (localFunctionMatch) {
20+
const functionName = localFunctionMatch[1];
21+
// console.log(`Inlining local function: ${functionName}`);
22+
const start = betweenComments.indexOf(')') + 1;
23+
const end = betweenComments.lastIndexOf('end');
24+
let content = betweenComments.substring(start, end).trim();
25+
// Check for @removeReturn
26+
if (betweenComments.includes('@removeReturn')) {
27+
content = content.replace(/\breturn\b/g, ''); // Remove "return" keywords
28+
}
29+
// console.log(`Captured content: ${content}`);
30+
changedFunctions.add(functionName);
31+
// Store result for later
32+
if (functionsToInline[functionName] === undefined)
33+
functionsToInline[functionName] = content;
34+
}
35+
// Check for X = function()
36+
const functionAssignmentMatch = betweenComments.match(
37+
/(\w+)\s*=\s*function\s*\([^)]*\)/,
38+
);
39+
if (functionAssignmentMatch) {
40+
const functionName = functionAssignmentMatch[1];
41+
// console.log(`Inlining function: ${functionName}`);
42+
const start = betweenComments.indexOf(')') + 1;
43+
const end = betweenComments.lastIndexOf('end');
44+
let content = betweenComments.substring(start, end).trim();
45+
// Check for @removeReturn
46+
if (betweenComments.includes('@removeReturn')) {
47+
content = content.replace(/\breturn\b/g, ''); // Remove "return" keywords
48+
}
49+
// console.log(`Captured content: ${content}`);
50+
changedFunctions.add(functionName);
51+
// Store result for later
52+
if (functionsToInline[functionName] === undefined)
53+
functionsToInline[functionName] = content;
54+
}
55+
}
56+
// Iterate through stored functions and replace their occurrences
57+
Object.entries(functionsToInline).forEach(([functionName, content]) => {
58+
const functionPattern = new RegExp(
59+
`\\b(?<!function\\s)${functionName}\\s*\\([^)]*\\)`,
60+
'g',
61+
);
62+
file.code = file.code.replace(functionPattern, content);
63+
});
64+
}
65+
function removeInlinedFunction(file) {
66+
while ((match = pattern.exec(file.code)) !== null) {
67+
const betweenComments = match[1];
68+
// Check for local function X()
69+
const localFunctionMatch = betweenComments.match(
70+
/function\s+(\w+)\s*\([^)]*\)/,
71+
);
72+
// Check for X = function()
73+
const functionAssignmentMatch = betweenComments.match(
74+
/(\w+)\s*=\s*function\s*\([^)]*\)/,
75+
);
76+
if (functionAssignmentMatch || localFunctionMatch) {
77+
// Remove function that will be inlined
78+
file.code = file.code.replace(betweenComments, '');
79+
}
80+
}
81+
}
82+
const plugin = {
83+
afterEmit: (_program, _options, emitHost, result) => {
84+
for (const file of result) {
85+
for (let index = 0; index < maxLoop; index++) {
86+
inlineFunction(file);
87+
}
88+
for (let index = 0; index < maxLoop; index++) {
89+
removeInlinedFunction(file);
90+
}
91+
// Write the changed code
92+
emitHost.writeFile(file.outputPath, file.code, false);
93+
}
94+
// Display log of function names
95+
changedFunctions.forEach((changedFunctionName) => {
96+
// @ts-expect-error Missing definition for `console`
97+
console.log(`Inlining function ${changedFunctionName}`);
98+
});
99+
},
100+
};
101+
exports.default = plugin;

package.json

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
{
2+
"name": "tstl-simple-inline-func",
3+
"version": "1.0.0",
4+
"description": "TypeScriptToLua plugin that performs inline expansion to simple functions",
5+
"repository": {
6+
"type": "git",
7+
"url": "https://github.com/thinknathan/tstl-simple-inline-func.git"
8+
},
9+
"author": "Nathan Bolton (https://thinknathan.ca/)",
10+
"license": "CC0-1.0",
11+
"main": "dist/tstl-simple-inline-function.cjs",
12+
"type": "commonjs",
13+
"scripts": {
14+
"build": "tsc",
15+
"prettier": "prettier --write ./"
16+
},
17+
"devDependencies": {
18+
"prettier": "^3.1.0",
19+
"tsc": "^2.0.4",
20+
"typescript": "~5.2.2",
21+
"typescript-to-lua": "~1.22.0"
22+
}
23+
}

tsconfig.json

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
{
2+
"$schema": "https://raw.githubusercontent.com/TypeScriptToLua/TypeScriptToLua/master/tsconfig-schema.json",
3+
"compilerOptions": {
4+
"lib": ["esnext"],
5+
"module": "CommonJS",
6+
"outDir": "./dist",
7+
"rootDir": ".",
8+
"sourceMap": false,
9+
"strict": true,
10+
"target": "ES2020",
11+
"typeRoots": [
12+
"./@types",
13+
"./node_modules/@types",
14+
"./node_modules/@typescript-to-lua"
15+
]
16+
},
17+
"exclude": ["./node_modules/*", "./dist/*"]
18+
}

0 commit comments

Comments
 (0)