@polytoria-ts/pojo 0.0.0-stage → 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +4 -2
- package/index.mjs +154 -0
- package/package.json +19 -4
package/README.md
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
-
|
|
1
|
+
## Pojo
|
|
2
|
+
A crude replica of **Rojo** for Polytoria's polytoria-ts.
|
|
2
3
|
|
|
3
|
-
|
|
4
|
+
## Bugs
|
|
5
|
+
- There is nothing to track orphans. A synchronized luau file will remain in the game if it was deleted without Pojo running.
|
package/index.mjs
ADDED
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
import express from "express";
|
|
4
|
+
import fs from "node:fs";
|
|
5
|
+
import chokidar from "chokidar";
|
|
6
|
+
import path from "node:path";
|
|
7
|
+
|
|
8
|
+
const WATCH_DIR = "out/";
|
|
9
|
+
const GAME_DIR = "game/";
|
|
10
|
+
const TREE_JSON_PATH = "default.project.json";
|
|
11
|
+
|
|
12
|
+
let kvOutToHierarchy = {}
|
|
13
|
+
function walk() {
|
|
14
|
+
const treeFileContents = fs.readFileSync(TREE_JSON_PATH);
|
|
15
|
+
const tree = JSON.parse(treeFileContents)?.tree;
|
|
16
|
+
if (!tree) {
|
|
17
|
+
console.error(`Invalid game tree (${TREE_JSON_PATH}). Missing tree key.`);
|
|
18
|
+
return;
|
|
19
|
+
}
|
|
20
|
+
kvOutToHierarchy = {};
|
|
21
|
+
|
|
22
|
+
const walkChild = (node, currentPath) => {
|
|
23
|
+
for (const [key, value] of Object.entries(node)) {
|
|
24
|
+
if (key.startsWith("$")) {
|
|
25
|
+
if (key == "$path") {
|
|
26
|
+
const diskPath = path.resolve(path.dirname(path.resolve(TREE_JSON_PATH)), value);
|
|
27
|
+
kvOutToHierarchy[diskPath] = currentPath;
|
|
28
|
+
}
|
|
29
|
+
continue;
|
|
30
|
+
}
|
|
31
|
+
if (typeof value !== "object" || value === null || Array.isArray(value)) {
|
|
32
|
+
continue;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
const next = [...currentPath, key];
|
|
36
|
+
walkChild(value, next);
|
|
37
|
+
}
|
|
38
|
+
};
|
|
39
|
+
walkChild(tree, []);
|
|
40
|
+
console.log(kvOutToHierarchy)
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
function getHierarchyForFile(filePath) {
|
|
44
|
+
const absPath = path.resolve(filePath);
|
|
45
|
+
|
|
46
|
+
const entries = Object.entries(kvOutToHierarchy);
|
|
47
|
+
for (const [diskPath, treePath] of entries) {
|
|
48
|
+
const relativePath = path.relative(diskPath, absPath)
|
|
49
|
+
if (relativePath.startsWith("..") || path.isAbsolute(relativePath)) continue;
|
|
50
|
+
const segments = relativePath.split(path.sep);
|
|
51
|
+
const fileName = segments.pop(); // distinct from filePath, lacks dir indicators
|
|
52
|
+
|
|
53
|
+
let baseType = ""; // "ClientScript" || "ServerScript" || "ModuleScript"
|
|
54
|
+
let cleanFileName = fileName.split(".")[0];
|
|
55
|
+
if (fileName.endsWith(".server.luau")) {
|
|
56
|
+
baseType = "ServerScript";
|
|
57
|
+
} else if (fileName.endsWith(".client.luau")) {
|
|
58
|
+
baseType = "ClientScript";
|
|
59
|
+
} else if (fileName.endsWith(".luau")) {
|
|
60
|
+
baseType = "ModuleScript";
|
|
61
|
+
} else {
|
|
62
|
+
console.error(`${fileName} does not appear to be luau?`)
|
|
63
|
+
continue;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
segments.push(cleanFileName);
|
|
67
|
+
const fullHierarchy = [...treePath, ...segments];
|
|
68
|
+
// console.log(`${filePath} logically belongs in ${fullHierarchy} as ${baseType}`);
|
|
69
|
+
return {
|
|
70
|
+
hierarchy : fullHierarchy,
|
|
71
|
+
type : baseType,
|
|
72
|
+
};
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
console.error(`Don't know where to place ${filePath} within the game. Check your ${TREE_JSON_PATH}!`);
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
const treeWatcher = chokidar.watch(TREE_JSON_PATH, {
|
|
79
|
+
ignoreInitial: false,
|
|
80
|
+
|
|
81
|
+
awaitWriteFinish: {
|
|
82
|
+
stabilityThreshold: 100,
|
|
83
|
+
pollInterval: 50,
|
|
84
|
+
},
|
|
85
|
+
})
|
|
86
|
+
|
|
87
|
+
treeWatcher.on("add", (_path, _stats) => { walk(); });
|
|
88
|
+
treeWatcher.on("change", (_path, _stats) => { walk(); });
|
|
89
|
+
|
|
90
|
+
const watcher = chokidar.watch(WATCH_DIR, {
|
|
91
|
+
ignored: (path, stats) => stats?.isFile() && !path.endsWith(".luau"),
|
|
92
|
+
ignoreInitial: false,
|
|
93
|
+
awaitWriteFinish: {
|
|
94
|
+
stabilityThreshold: 100,
|
|
95
|
+
pollInterval: 50,
|
|
96
|
+
},
|
|
97
|
+
});
|
|
98
|
+
|
|
99
|
+
let work = [];
|
|
100
|
+
|
|
101
|
+
function handleAdd(filePath) {
|
|
102
|
+
const {hierarchy, type} = getHierarchyForFile(filePath);
|
|
103
|
+
|
|
104
|
+
const gameScriptPath = path.join(GAME_DIR, "scripts", hierarchy.join(path.sep) + ".luau");
|
|
105
|
+
const editorScriptPath = path.join("scripts", hierarchy.join(path.sep) + ".luau");
|
|
106
|
+
console.log(`cp ${filePath} ${gameScriptPath}`)
|
|
107
|
+
fs.cpSync(filePath, gameScriptPath);
|
|
108
|
+
|
|
109
|
+
const existingWorkItem = work.find(workItem => workItem.hierarchy.join("/") === hierarchy.join("/"));
|
|
110
|
+
if (existingWorkItem) return;
|
|
111
|
+
|
|
112
|
+
work.push({
|
|
113
|
+
operation: "add",
|
|
114
|
+
hierarchy: hierarchy,
|
|
115
|
+
full_path: editorScriptPath,
|
|
116
|
+
type: type,
|
|
117
|
+
});
|
|
118
|
+
console.log(work);
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
watcher.on("add", (filePath, _stats) => {
|
|
122
|
+
console.log(`+${filePath}`);
|
|
123
|
+
handleAdd(filePath)
|
|
124
|
+
});
|
|
125
|
+
|
|
126
|
+
watcher.on("change", (filePath, _stats) => {
|
|
127
|
+
console.log(`~${filePath}`);
|
|
128
|
+
handleAdd(filePath);
|
|
129
|
+
});
|
|
130
|
+
|
|
131
|
+
function handleUnlink(filePath) {
|
|
132
|
+
const {hierarchy, type} = getHierarchyForFile(filePath);
|
|
133
|
+
const gameScriptPath = path.join(GAME_DIR, "scripts", hierarchy.join(path.sep));
|
|
134
|
+
fs.rmSync(gameScriptPath + ".luau");
|
|
135
|
+
fs.rmSync(gameScriptPath + ".luau.meta");
|
|
136
|
+
|
|
137
|
+
work.push({
|
|
138
|
+
operation: "rm",
|
|
139
|
+
hierarchy: hierarchy
|
|
140
|
+
});
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
watcher.on("unlink", (filePath, _stats) => {
|
|
144
|
+
console.log(`-${filePath}`);
|
|
145
|
+
handleUnlink(filePath);
|
|
146
|
+
});
|
|
147
|
+
|
|
148
|
+
const app = express();
|
|
149
|
+
app.get("/", (req, res) => {
|
|
150
|
+
res.send(JSON.stringify(work));
|
|
151
|
+
work = [];
|
|
152
|
+
})
|
|
153
|
+
|
|
154
|
+
app.listen(8080, "127.0.0.1", () => { console.log("running") });
|
package/package.json
CHANGED
|
@@ -1,6 +1,21 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@polytoria-ts/pojo",
|
|
3
|
-
"version": "
|
|
4
|
-
"
|
|
5
|
-
"
|
|
6
|
-
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "Synchronization server for Polytoria's Pojo extension.",
|
|
5
|
+
"type": "commonjs",
|
|
6
|
+
"main": "index.js",
|
|
7
|
+
"repository": {
|
|
8
|
+
"type": "git",
|
|
9
|
+
"url": "git+https://github.com/pine-forest-dweller/polyts-pojo.git"
|
|
10
|
+
},
|
|
11
|
+
"scripts": {
|
|
12
|
+
"run": "node index.mjs"
|
|
13
|
+
},
|
|
14
|
+
"dependencies": {
|
|
15
|
+
"chokidar": "^5.0.0",
|
|
16
|
+
"express": "^5.3.0"
|
|
17
|
+
},
|
|
18
|
+
"bin": {
|
|
19
|
+
"pojo": "./index.mjs"
|
|
20
|
+
}
|
|
21
|
+
}
|