From d5b41e2bd4dd2d2d0822f5bf7c9a953874d9459c Mon Sep 17 00:00:00 2001 From: Lucien Greathouse Date: Fri, 8 Dec 2017 16:50:30 -0800 Subject: [PATCH] Remove plugin source, moved to rojo-plugin --- .editorconfig | 5 - .gitmodules | 15 -- .travis.yml | 29 +--- modules/lemur | 1 - modules/roact | 1 - modules/roact-rodux | 1 - modules/rodux | 1 - modules/testez | 1 - plugin/.luacheckrc | 56 ------- plugin/src/Config.lua | 5 - plugin/src/Config.spec.lua | 7 - plugin/src/Http.lua | 67 -------- plugin/src/HttpError.lua | 57 ------- plugin/src/HttpResponse.lua | 20 --- plugin/src/Main.server.lua | 42 ----- plugin/src/Plugin.lua | 178 --------------------- plugin/src/Promise.lua | 311 ------------------------------------ plugin/src/Promise.spec.lua | 70 -------- plugin/src/Reconciler.lua | 269 ------------------------------- plugin/src/Server.lua | 69 -------- plugin/src/runTests.lua | 4 - rojo.json | 26 --- spec.lua | 69 -------- 23 files changed, 4 insertions(+), 1300 deletions(-) delete mode 100644 .gitmodules delete mode 160000 modules/lemur delete mode 160000 modules/roact delete mode 160000 modules/roact-rodux delete mode 160000 modules/rodux delete mode 160000 modules/testez delete mode 100644 plugin/.luacheckrc delete mode 100644 plugin/src/Config.lua delete mode 100644 plugin/src/Config.spec.lua delete mode 100644 plugin/src/Http.lua delete mode 100644 plugin/src/HttpError.lua delete mode 100644 plugin/src/HttpResponse.lua delete mode 100644 plugin/src/Main.server.lua delete mode 100644 plugin/src/Plugin.lua delete mode 100644 plugin/src/Promise.lua delete mode 100644 plugin/src/Promise.spec.lua delete mode 100644 plugin/src/Reconciler.lua delete mode 100644 plugin/src/Server.lua delete mode 100644 plugin/src/runTests.lua delete mode 100644 rojo.json delete mode 100644 spec.lua diff --git a/.editorconfig b/.editorconfig index 50456de4..c2c2496b 100644 --- a/.editorconfig +++ b/.editorconfig @@ -4,11 +4,6 @@ root = true end_of_line = lf charset = utf-8 -[*.lua] -indent_style = tab -trim_trailing_whitespace = true -insert_final_newline = true - [*.rs] indent_style = space indent_size = 4 diff --git a/.gitmodules b/.gitmodules deleted file mode 100644 index f181740d..00000000 --- a/.gitmodules +++ /dev/null @@ -1,15 +0,0 @@ -[submodule "modules/roact"] - path = modules/roact - url = https://github.com/Roblox/roact.git -[submodule "modules/rodux"] - path = modules/rodux - url = https://github.com/Roblox/rodux.git -[submodule "modules/roact-rodux"] - path = modules/roact-rodux - url = https://github.com/Roblox/roact-rodux.git -[submodule "modules/testez"] - path = modules/testez - url = https://github.com/Roblox/testez.git -[submodule "modules/lemur"] - path = modules/lemur - url = https://github.com/LPGhatguy/lemur.git diff --git a/.travis.yml b/.travis.yml index c24c36df..2657bd4d 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,26 +1,5 @@ -language: python +language: rust -env: - - RUST="stable" LUA="lua=5.1" - - RUST="beta" LUA="lua=5.1" - -before_install: - - pip install hererocks - - hererocks lua_install -r^ --$LUA - - curl https://sh.rustup.rs -sSf | sh -s -- -y --default-toolchain $RUST - - export PATH=$PATH:$PWD/lua_install/bin:$HOME/.cargo/bin - -install: - - luarocks install luafilesystem - - luarocks install busted - - luarocks install luacov - - luarocks install luacov-coveralls - - luarocks install luacheck - -script: - - cd plugin && luacheck . && cd .. - - lua -lluacov spec.lua - - cargo test --verbose - -after_success: - - luacov-coveralls -e $TRAVIS_BUILD_DIR/lua_install \ No newline at end of file +rust: + - stable + - beta \ No newline at end of file diff --git a/modules/lemur b/modules/lemur deleted file mode 160000 index c7b1cc33..00000000 --- a/modules/lemur +++ /dev/null @@ -1 +0,0 @@ -Subproject commit c7b1cc335d3a77be1e45e8c0208c1a384b6e57d6 diff --git a/modules/roact b/modules/roact deleted file mode 160000 index 8eaabac5..00000000 --- a/modules/roact +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 8eaabac5c1e03c9f6a389c4c0b8b808b8e9ee90e diff --git a/modules/roact-rodux b/modules/roact-rodux deleted file mode 160000 index 57f3fc62..00000000 --- a/modules/roact-rodux +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 57f3fc62207827baf11af40359c04492a35c8fed diff --git a/modules/rodux b/modules/rodux deleted file mode 160000 index 6e1dcc9c..00000000 --- a/modules/rodux +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 6e1dcc9c4d56c9d13e20a568fe632ee965d730e7 diff --git a/modules/testez b/modules/testez deleted file mode 160000 index 3c421758..00000000 --- a/modules/testez +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 3c42175897f7133d10fdc269c040df98a55906d6 diff --git a/plugin/.luacheckrc b/plugin/.luacheckrc deleted file mode 100644 index bce1d4dd..00000000 --- a/plugin/.luacheckrc +++ /dev/null @@ -1,56 +0,0 @@ -stds.roblox = { - read_globals = { - game = { - other_fields = true, - }, - - -- Roblox globals - "script", - - -- Extra functions - "tick", "warn", "spawn", - "wait", "settings", - - -- Types - "Vector2", "Vector3", - "Color3", - "UDim", "UDim2", - "Rect", - "CFrame", - "Enum", - "Instance", - } -} - -stds.plugin = { - read_globals = { - "plugin", - } -} - -stds.testez = { - read_globals = { - "describe", - "it", "itFOCUS", "itSKIP", - "FOCUS", "SKIP", "HACK_NO_XPCALL", - "expect", - } -} - -ignore = { - "212", -- unused arguments - "421", -- shadowing local variable - "422", -- shadowing argument - "431", -- shadowing upvalue - "432", -- shadowing upvalue argument -} - -std = "lua51+roblox" - -files["**/*.server.lua"] = { - std = "+plugin", -} - -files["**/*.spec.lua"] = { - std = "+testez", -} \ No newline at end of file diff --git a/plugin/src/Config.lua b/plugin/src/Config.lua deleted file mode 100644 index 9e90fd85..00000000 --- a/plugin/src/Config.lua +++ /dev/null @@ -1,5 +0,0 @@ -return { - pollingRate = 0.3, - version = "v0.2.3", - dev = false, -} diff --git a/plugin/src/Config.spec.lua b/plugin/src/Config.spec.lua deleted file mode 100644 index ce9b43fd..00000000 --- a/plugin/src/Config.spec.lua +++ /dev/null @@ -1,7 +0,0 @@ -return function() - local Config = require(script.Parent.Config) - - it("should have 'dev' disabled", function() - expect(Config.dev).to.equal(false) - end) -end diff --git a/plugin/src/Http.lua b/plugin/src/Http.lua deleted file mode 100644 index 98997b9f..00000000 --- a/plugin/src/Http.lua +++ /dev/null @@ -1,67 +0,0 @@ -local HttpService = game:GetService("HttpService") - -local HTTP_DEBUG = false - -local Promise = require(script.Parent.Promise) -local HttpError = require(script.Parent.HttpError) -local HttpResponse = require(script.Parent.HttpResponse) - -local function dprint(...) - if HTTP_DEBUG then - print(...) - end -end - -local Http = {} -Http.__index = Http - -function Http.new(baseUrl) - assert(type(baseUrl) == "string", "Http.new needs a baseUrl!") - - local http = { - baseUrl = baseUrl - } - - setmetatable(http, Http) - - return http -end - -function Http:get(endpoint) - dprint("\nGET", endpoint) - return Promise.new(function(resolve, reject) - spawn(function() - local ok, result = pcall(function() - return HttpService:GetAsync(self.baseUrl .. endpoint, true) - end) - - if ok then - dprint("\t", result, "\n") - resolve(HttpResponse.new(result)) - else - reject(HttpError.fromErrorString(result)) - end - end) - end) -end - -function Http:post(endpoint, body) - dprint("\nPOST", endpoint) - dprint(body) - return Promise.new(function(resolve, reject) - spawn(function() - local ok, result = pcall(function() - return HttpService:PostAsync(self.baseUrl .. endpoint, body) - end) - - if ok then - dprint("\t", result, "\n") - resolve(HttpResponse.new(result)) - else - reject(HttpError.fromErrorString(result)) - end - end) - end) -end - -return Http diff --git a/plugin/src/HttpError.lua b/plugin/src/HttpError.lua deleted file mode 100644 index 9da4b946..00000000 --- a/plugin/src/HttpError.lua +++ /dev/null @@ -1,57 +0,0 @@ -local HttpError = {} -HttpError.__index = HttpError - -HttpError.Error = { - HttpNotEnabled = { - message = "Rojo requires HTTP access, which is not enabled.\n" .. - "Check your game settings, located in the 'Home' tab of Studio.", - }, - ConnectFailed = { - message = "Rojo plugin couldn't connect to the Rojo server.\n" .. - "Make sure the server is running -- use 'Rojo serve' to run it!", - }, - Unknown = { - message = "Rojo encountered an unknown error: {{message}}", - }, -} - -function HttpError.new(type, extraMessage) - extraMessage = extraMessage or "" - local message = type.message:gsub("{{message}}", extraMessage) - - local err = { - type = type, - message = message, - } - - setmetatable(err, HttpError) - - return err -end - -function HttpError:__tostring() - return self.message -end - ---[[ - This method shouldn't have to exist. Ugh. -]] -function HttpError.fromErrorString(err) - err = err:lower() - - if err:find("^http requests are not enabled") then - return HttpError.new(HttpError.Error.HttpNotEnabled) - end - - if err:find("^curl error") then - return HttpError.new(HttpError.Error.ConnectFailed) - end - - return HttpError.new(HttpError.Error.Unknown, err) -end - -function HttpError:report() - warn(self.message) -end - -return HttpError diff --git a/plugin/src/HttpResponse.lua b/plugin/src/HttpResponse.lua deleted file mode 100644 index 0b85db94..00000000 --- a/plugin/src/HttpResponse.lua +++ /dev/null @@ -1,20 +0,0 @@ -local HttpService = game:GetService("HttpService") - -local HttpResponse = {} -HttpResponse.__index = HttpResponse - -function HttpResponse.new(body) - local response = { - body = body, - } - - setmetatable(response, HttpResponse) - - return response -end - -function HttpResponse:json() - return HttpService:JSONDecode(self.body) -end - -return HttpResponse diff --git a/plugin/src/Main.server.lua b/plugin/src/Main.server.lua deleted file mode 100644 index 2d393e8d..00000000 --- a/plugin/src/Main.server.lua +++ /dev/null @@ -1,42 +0,0 @@ -if not plugin then - return -end - -local Plugin = require(script.Parent.Plugin) -local Config = require(script.Parent.Config) - -local function main() - local pluginInstance = Plugin.new() - - local displayedVersion = Config.dev and "DEV" or Config.version - - local toolbar = plugin:CreateToolbar("Rojo Plugin " .. displayedVersion) - - toolbar:CreateButton("Test Connection", "Connect to Rojo Server", "") - .Click:Connect(function() - pluginInstance:connect() - :catch(function(err) - warn(err) - end) - end) - - toolbar:CreateButton("Sync In", "Sync into Roblox Studio", "") - .Click:Connect(function() - pluginInstance:syncIn() - :catch(function(err) - warn(err) - end) - end) - - toolbar:CreateButton("Toggle Polling", "Poll server for changes", "") - .Click:Connect(function() - spawn(function() - pluginInstance:togglePolling() - :catch(function(err) - warn(err) - end) - end) - end) -end - -main() diff --git a/plugin/src/Plugin.lua b/plugin/src/Plugin.lua deleted file mode 100644 index 79d7418d..00000000 --- a/plugin/src/Plugin.lua +++ /dev/null @@ -1,178 +0,0 @@ -local Config = require(script.Parent.Config) -local Http = require(script.Parent.Http) -local Server = require(script.Parent.Server) -local Promise = require(script.Parent.Promise) -local Reconciler = require(script.Parent.Reconciler) - -local function collectMatch(source, pattern) - local result = {} - - for match in source:gmatch(pattern) do - table.insert(result, match) - end - - return result -end - -local Plugin = {} -Plugin.__index = Plugin - -function Plugin.new() - local address = "localhost" - local port = Config.dev and 8001 or 8000 - - local remote = ("http://%s:%d"):format(address, port) - - local foop = { - _http = Http.new(remote), - _server = nil, - _polling = false, - } - - setmetatable(foop, Plugin) - - do - local screenGui = Instance.new("ScreenGui") - screenGui.Name = "Rojo UI" - screenGui.Parent = game.CoreGui - screenGui.DisplayOrder = -1 - screenGui.Enabled = false - - local label = Instance.new("TextLabel") - label.Font = Enum.Font.SourceSans - label.TextSize = 20 - label.Text = "Rojo polling..." - label.BackgroundColor3 = Color3.fromRGB(31, 31, 31) - label.BackgroundTransparency = 0.5 - label.BorderSizePixel = 0 - label.TextColor3 = Color3.new(1, 1, 1) - label.Size = UDim2.new(0, 120, 0, 28) - label.Position = UDim2.new(0, 0, 0, 0) - label.Parent = screenGui - - foop._label = screenGui - end - - return foop -end - -function Plugin:server() - if not self._server then - self._server = Server.connect(self._http) - :catch(function(err) - self._server = nil - return Promise.reject(err) - end) - end - - return self._server -end - -function Plugin:connect() - print("Testing connection...") - - return self:server() - :andThen(function(server) - return server:getInfo() - end) - :andThen(function(result) - print("Server found!") - print("Protocol version:", result.protocolVersion) - print("Server version:", result.serverVersion) - end) -end - -function Plugin:togglePolling() - if self._polling then - self:stopPolling() - - return Promise.resolve(nil) - else - return self:startPolling() - end -end - -function Plugin:stopPolling() - if not self._polling then - return - end - - print("Stopped polling.") - - self._polling = false - self._label.Enabled = false -end - -function Plugin:_pull(server, project, routes) - local items = server:read(routes):await() - - for index = 1, #routes do - local route = routes[index] - local partitionName = route[1] - local partition = project.partitions[partitionName] - local item = items[index] - - local fullRoute = collectMatch(partition.target, "[^.]+") - for i = 2, #route do - table.insert(fullRoute, routes[index][i]) - end - - Reconciler.reconcileRoute(fullRoute, item) - end -end - -function Plugin:startPolling() - if self._polling then - return - end - - print("Starting to poll...") - - self._polling = true - self._label.Enabled = true - - return self:server() - :andThen(function(server) - self:syncIn():await() - - local project = server:getInfo():await().project - - while self._polling do - local changes = server:getChanges():await() - - local routes = {} - - for _, change in ipairs(changes) do - table.insert(routes, change.route) - end - - self:_pull(server, project, routes) - - wait(Config.pollingRate) - end - end) - :catch(function() - self:stopPolling() - end) -end - -function Plugin:syncIn() - print("Syncing from server...") - - return self:server() - :andThen(function(server) - local project = server:getInfo():await().project - - local routes = {} - - for name in pairs(project.partitions) do - table.insert(routes, {name}) - end - - self:_pull(server, project, routes) - - print("Sync successful!") - end) -end - -return Plugin diff --git a/plugin/src/Promise.lua b/plugin/src/Promise.lua deleted file mode 100644 index cdcea791..00000000 --- a/plugin/src/Promise.lua +++ /dev/null @@ -1,311 +0,0 @@ ---[[ - An implementation of Promises similar to Promise/A+. -]] - -local PROMISE_DEBUG = false - --- If promise debugging is on, use a version of pcall that warns on failure. --- This is useful for finding errors that happen within Promise itself. -local wpcall -if PROMISE_DEBUG then - wpcall = function(f, ...) - local result = { pcall(f, ...) } - - if not result[1] then - warn(result[2]) - end - - return unpack(result) - end -else - wpcall = pcall -end - ---[[ - Creates a function that invokes a callback with correct error handling and - resolution mechanisms. -]] -local function createAdvancer(callback, resolve, reject) - return function(...) - local result = { wpcall(callback, ...) } - local ok = table.remove(result, 1) - - if ok then - resolve(unpack(result)) - else - reject(unpack(result)) - end - end -end - -local function isEmpty(t) - return next(t) == nil -end - -local Promise = {} -Promise.__index = Promise - -Promise.Status = { - Started = "Started", - Resolved = "Resolved", - Rejected = "Rejected", -} - ---[[ - Constructs a new Promise with the given initializing callback. - - This is generally only called when directly wrapping a non-promise API into - a promise-based version. - - The callback will receive 'resolve' and 'reject' methods, used to start - invoking the promise chain. - - For example: - - local function get(url) - return Promise.new(function(resolve, reject) - spawn(function() - resolve(HttpService:GetAsync(url)) - end) - end) - end - - get("https://google.com") - :andThen(function(stuff) - print("Got some stuff!", stuff) - end) -]] -function Promise.new(callback) - local promise = { - -- Used to locate where a promise was created - _source = debug.traceback(), - - -- A tag to identify us as a promise - _type = "Promise", - - _status = Promise.Status.Started, - - -- A table containing a list of all results, whether success or failure. - -- Only valid if _status is set to something besides Started - _value = nil, - - -- If an error occurs with no observers, this will be set. - _unhandledRejection = false, - - -- Queues representing functions we should invoke when we update! - _queuedResolve = {}, - _queuedReject = {}, - } - - setmetatable(promise, Promise) - - local function resolve(...) - promise:_resolve(...) - end - - local function reject(...) - promise:_reject(...) - end - - local ok, err = wpcall(callback, resolve, reject) - - if not ok and promise._status == Promise.Status.Started then - reject(err) - end - - return promise -end - ---[[ - Create a promise that represents the immediately resolved value. -]] -function Promise.resolve(value) - return Promise.new(function(resolve) - resolve(value) - end) -end - ---[[ - Create a promise that represents the immediately rejected value. -]] -function Promise.reject(value) - return Promise.new(function(_, reject) - reject(value) - end) -end - ---[[ - Returns a new promise that: - * is resolved when all input promises resolve - * is rejected if ANY input promises reject -]] -function Promise.all(...) - error("unimplemented", 2) -end - ---[[ - Is the given object a Promise instance? -]] -function Promise.is(object) - if type(object) ~= "table" then - return false - end - - return object._type == "Promise" -end - ---[[ - Creates a new promise that receives the result of this promise. - - The given callbacks are invoked depending on that result. -]] -function Promise:andThen(successHandler, failureHandler) - self._unhandledRejection = false - - -- Create a new promise to follow this part of the chain - return Promise.new(function(resolve, reject) - -- Our default callbacks just pass values onto the next promise. - -- This lets success and failure cascade correctly! - - local successCallback = resolve - if successHandler then - successCallback = createAdvancer(successHandler, resolve, reject) - end - - local failureCallback = reject - if failureHandler then - failureCallback = createAdvancer(failureHandler, resolve, reject) - end - - if self._status == Promise.Status.Started then - -- If we haven't resolved yet, put ourselves into the queue - table.insert(self._queuedResolve, successCallback) - table.insert(self._queuedReject, failureCallback) - elseif self._status == Promise.Status.Resolved then - -- This promise has already resolved! Trigger success immediately. - successCallback(unpack(self._value)) - elseif self._status == Promise.Status.Rejected then - -- This promise died a terrible death! Trigger failure immediately. - failureCallback(unpack(self._value)) - end - end) -end - ---[[ - Used to catch any errors that may have occurred in the promise. -]] -function Promise:catch(failureCallback) - return self:andThen(nil, failureCallback) -end - ---[[ - Yield until the promise is completed. - - This matches the execution model of normal Roblox functions. -]] -function Promise:await() - self._unhandledRejection = false - - if self._status == Promise.Status.Started then - local result - local bindable = Instance.new("BindableEvent") - - self:andThen(function(...) - result = {...} - bindable:Fire(true) - end, function(...) - result = {...} - bindable:Fire(false) - end) - - local ok = bindable.Event:Wait() - bindable:Destroy() - - if not ok then - error(tostring(result[1]), 2) - end - - return unpack(result) - elseif self._status == Promise.Status.Resolved then - return unpack(self._value) - elseif self._status == Promise.Status.Rejected then - error(tostring(self._value[1]), 2) - end -end - -function Promise:_resolve(...) - if self._status ~= Promise.Status.Started then - return - end - - -- If the resolved value was a Promise, we chain onto it! - if Promise.is((...)) then - -- Without this warning, arguments sometimes mysteriously disappear - if select("#", ...) > 1 then - local message = ( - "When returning a Promise from andThen, extra arguments are " .. - "discarded! See:\n\n%s" - ):format( - self._source - ) - warn(message) - end - - (...):andThen(function(...) - self:_resolve(...) - end, function(...) - self:_reject(...) - end) - - return - end - - self._status = Promise.Status.Resolved - self._value = {...} - - -- We assume that these callbacks will not throw errors. - for _, callback in ipairs(self._queuedResolve) do - callback(...) - end -end - -function Promise:_reject(...) - if self._status ~= Promise.Status.Started then - return - end - - self._status = Promise.Status.Rejected - self._value = {...} - - -- If there are any rejection handlers, call those! - if not isEmpty(self._queuedReject) then - -- We assume that these callbacks will not throw errors. - for _, callback in ipairs(self._queuedReject) do - callback(...) - end - else - -- At this point, no one was able to observe the error. - -- An error handler might still be attached if the error occurred - -- synchronously. We'll wait one tick, and if there are still no - -- observers, then we should put a message in the console. - - self._unhandledRejection = true - local err = tostring((...)) - - spawn(function() - -- Someone observed the error, hooray! - if not self._unhandledRejection then - return - end - - -- Build a reasonable message - local message = ("Unhandled promise rejection:\n\n%s\n\n%s"):format( - err, - self._source - ) - warn(message) - end) - end -end - -return Promise diff --git a/plugin/src/Promise.spec.lua b/plugin/src/Promise.spec.lua deleted file mode 100644 index 60cc9cbe..00000000 --- a/plugin/src/Promise.spec.lua +++ /dev/null @@ -1,70 +0,0 @@ -return function() - local Promise = require(script.Parent.Promise) - - describe("Promise.new", function() - it("should instantiate with a callback", function() - local promise = Promise.new(function() end) - - expect(promise).to.be.ok() - end) - - it("should invoke the given callback with resolve and reject", function() - local callCount = 0 - local resolveArg - local rejectArg - - local promise = Promise.new(function(resolve, reject) - callCount = callCount + 1 - resolveArg = resolve - rejectArg = reject - end) - - expect(promise).to.be.ok() - - expect(callCount).to.equal(1) - expect(resolveArg).to.be.a("function") - expect(rejectArg).to.be.a("function") - expect(promise._status).to.equal(Promise.Status.Started) - end) - - it("should resolve promises on resolve()", function() - local callCount = 0 - - local promise = Promise.new(function(resolve) - callCount = callCount + 1 - resolve() - end) - - expect(promise).to.be.ok() - expect(callCount).to.equal(1) - expect(promise._status).to.equal(Promise.Status.Resolved) - end) - - it("should reject promises on reject()", function() - local callCount = 0 - - local promise = Promise.new(function(resolve, reject) - callCount = callCount + 1 - reject() - end) - - expect(promise).to.be.ok() - expect(callCount).to.equal(1) - expect(promise._status).to.equal(Promise.Status.Rejected) - end) - - it("should reject on error in callback", function() - local callCount = 0 - - local promise = Promise.new(function() - callCount = callCount + 1 - error("hahah") - end) - - expect(promise).to.be.ok() - expect(callCount).to.equal(1) - expect(promise._status).to.equal(Promise.Status.Rejected) - expect(promise._value[1]:find("hahah")).to.be.ok() - end) - end) -end diff --git a/plugin/src/Reconciler.lua b/plugin/src/Reconciler.lua deleted file mode 100644 index 062f0dee..00000000 --- a/plugin/src/Reconciler.lua +++ /dev/null @@ -1,269 +0,0 @@ -local Reconciler = {} - ---[[ - The set of file names that should pass as init files - These files usurp their parents. -]] -local initNames = { - ["init.lua"] = true, - ["init.server.lua"] = true, - ["init.client.lua"] = true, -} - -local function isInit(item, itemFileName) - if item and item.type == "dir" then - return - end - - return initNames[itemFileName] or false -end - ---[[ - Determines if the given VFS item has an init file. Yields information about - the file. -]] -local function findInit(item) - if item.type ~= "dir" then - return nil, nil - end - - for childFileName, childItem in pairs(item.children) do - if isInit(childItem, childFileName) then - return childItem, childFileName - end - end - - return nil, nil -end - ---[[ - Given a VFS item, returns a Name and ClassName for a corresponding Roblox - instance. - - Doesn't take into account init files. -]] -local function itemToName(item, fileName) - if item and item.type == "dir" then - return fileName, "Folder" - elseif item and item.type == "file" or not item then - if fileName:find("%.server%.lua$") then - return fileName:match("^(.-)%.server%.lua$"), "Script" - elseif fileName:find("%.client%.lua$") then - return fileName:match("^(.-)%.client%.lua$"), "LocalScript" - elseif fileName:find("%.lua") then - return fileName:match("^(.-)%.lua$"), "ModuleScript" - else - return fileName, "StringValue" - end - else - error("unknown item type " .. tostring(item.type)) - end -end - ---[[ - Given a VFS item, assigns all relevant values (except Name!) to a Roblox - instance. -]] -local function setValues(rbx, item, fileName) - local _, className = itemToName(item, fileName) - - if className:find("Script") then - rbx.Source = item.contents - else - rbx.Value = item.contents - end -end - -function Reconciler._reifyShallow(item, fileName) - if item.type == "dir" then - local initItem, initFileName = findInit(item) - - if initItem then - local rbx = Reconciler._reify(initItem, initFileName) - rbx.Name = fileName - - return rbx - else - local rbx = Instance.new("Folder") - rbx.Name = fileName - - return rbx - end - elseif item.type == "file" then - local objectName, className = itemToName(item, fileName) - - local rbx = Instance.new(className) - rbx.Name = objectName - - setValues(rbx, item, fileName) - - return rbx - else - error("unknown item type " .. tostring(item.type)) - end -end - ---[[ - Construct a new Roblox instance tree that corresponds to the given VFS item. -]] -function Reconciler._reify(item, fileName, parent) - local rbx = Reconciler._reifyShallow(item, fileName) - - if item.type == "dir" then - for childFileName, childItem in pairs(item.children) do - if not isInit(childItem, childFileName) then - local childRbx = Reconciler._reify(childItem, childFileName) - childRbx.Parent = rbx - end - end - end - - rbx.Parent = parent - - return rbx -end - -function Reconciler.reconcile(rbx, item, fileName, parent) - -- Item was deleted! - if not item then - if isInit(item, fileName) then - if not parent then - return - end - - -- Un-usurp parent! - local newParent = Instance.new("Folder") - newParent.Name = parent.Name - - for _, child in ipairs(parent:GetChildren()) do - child.Parent = newParent - end - - newParent.Parent = parent.Parent - parent:Destroy() - - return - else - if rbx then - rbx:Destroy() - end - - return - end - end - - if item.type == "dir" then - -- Folder was created! - if not rbx then - return Reconciler._reify(item, fileName, parent) - end - - local initItem, initFileName = findInit(item) - - if initItem then - local _, initClassName = itemToName(initItem, initFileName) - - if rbx.ClassName == initClassName then - setValues(rbx, initItem, initFileName) - else - rbx:Destroy() - return Reconciler._reify(item, fileName, parent) - end - else - if rbx.ClassName ~= "Folder" then - -- Certain objects (services) can't be destroyed. - -- If we target one of these, leave it alone! - local ok = pcall(rbx.Destroy, rbx) - - if ok then - return Reconciler._reify(item, fileName, parent) - end - end - end - - local visitedChildren = {} - - for childFileName, childItem in pairs(item.children) do - if not isInit(childItem, childFileName) then - local childName = itemToName(childItem, childFileName) - - visitedChildren[childName] = true - - Reconciler.reconcile(rbx:FindFirstChild(childName), childItem, childFileName, rbx) - end - end - - for _, childRbx in ipairs(rbx:GetChildren()) do - -- Child was deleted! - if not visitedChildren[childRbx.Name] then - childRbx:Destroy() - end - end - - return rbx - elseif item.type == "file" then - if isInit(item, fileName) then - -- Usurp our container! - local _, className = itemToName(item, fileName) - - if parent.ClassName == className then - rbx = parent - else - rbx = Reconciler._reify(item, fileName, parent.Parent) - rbx.Name = parent.Name - - for _, child in ipairs(parent:GetChildren()) do - child.Parent = rbx - end - - parent:Destroy() - end - - setValues(rbx, item, fileName) - - return rbx - else - if not rbx then - return Reconciler._reify(item, fileName, parent) - end - - local _, className = itemToName(item, fileName) - - if rbx.ClassName ~= className then - rbx:Destroy() - return Reconciler._reify(item, fileName, parent) - end - - setValues(rbx, item, fileName) - - return rbx - end - else - error("unknown item type " .. tostring(item.type)) - end -end - -function Reconciler.reconcileRoute(route, item) - local location = game - - for i = 1, #route - 1 do - local piece = route[i] - local newLocation = location:FindFirstChild(piece) - - if not newLocation then - newLocation = Instance.new("Folder") - newLocation.Name = piece - newLocation.Parent = location - end - - location = newLocation - end - - local fileName = route[#route] - - local name = itemToName(item, fileName) - local rbx = location:FindFirstChild(name) - Reconciler.reconcile(rbx, item, fileName, location) -end - -return Reconciler diff --git a/plugin/src/Server.lua b/plugin/src/Server.lua deleted file mode 100644 index 02268220..00000000 --- a/plugin/src/Server.lua +++ /dev/null @@ -1,69 +0,0 @@ -local HttpService = game:GetService("HttpService") - -local Server = {} -Server.__index = Server - ---[[ - Create a new Server using the given HTTP implementation and replacer. - - If the context becomes invalid, `replacer` will be invoked with a new - context that should be suitable to replace this one. - - Attempting to invoke methods on an invalid conext will throw errors! -]] -function Server.connect(http) - local context = { - http = http, - serverId = nil, - currentTime = 0, - } - - setmetatable(context, Server) - - return context:_start() -end - -function Server:_start() - return self:getInfo() - :andThen(function(response) - self.serverId = response.serverId - self.currentTime = response.currentTime - - return self - end) -end - -function Server:getInfo() - return self.http:get("/") - :andThen(function(response) - response = response:json() - - return response - end) -end - -function Server:read(paths) - local body = HttpService:JSONEncode(paths) - - return self.http:post("/read", body) - :andThen(function(response) - response = response:json() - - return response.items - end) -end - -function Server:getChanges() - local url = ("/changes/%f"):format(self.currentTime) - - return self.http:get(url) - :andThen(function(response) - response = response:json() - - self.currentTime = response.currentTime - - return response.changes - end) -end - -return Server diff --git a/plugin/src/runTests.lua b/plugin/src/runTests.lua deleted file mode 100644 index 9b1da76e..00000000 --- a/plugin/src/runTests.lua +++ /dev/null @@ -1,4 +0,0 @@ -return function() - local TestEZ = require(script.Parent.Parent.TestEZ) - TestEZ.TestBootstrap:run(script.Parent) -end diff --git a/rojo.json b/rojo.json deleted file mode 100644 index 821517a3..00000000 --- a/rojo.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "name": "rojo", - "servePort": 8000, - "partitions": { - "plugin": { - "path": "plugin/src", - "target": "ReplicatedStorage.Rojo" - }, - "modules/roact": { - "path": "modules/roact/lib", - "target": "ReplicatedStorage.Rojo.modules.Roact" - }, - "modules/rodux": { - "path": "modules/rodux/lib", - "target": "ReplicatedStorage.Rojo.modules.Rodux" - }, - "modules/roact-rodux": { - "path": "modules/roact-rodux/lib", - "target": "ReplicatedStorage.Rojo.modules.RoactRodux" - }, - "modules/testez": { - "path": "modules/testez/lib", - "target": "ReplicatedStorage.TestEZ" - } - } -} \ No newline at end of file diff --git a/spec.lua b/spec.lua deleted file mode 100644 index dd0edde0..00000000 --- a/spec.lua +++ /dev/null @@ -1,69 +0,0 @@ ---[[ - Loads our library and all of its dependencies, then runs tests using TestEZ. -]] - --- If you add any dependencies, add them to this table so they'll be loaded! -local LOAD_MODULES = { - {"plugin/src", "Plugin"}, - {"modules/testez/lib", "TestEZ"}, -} - --- This makes sure we can load Lemur and other libraries that depend on init.lua -package.path = package.path .. ";?/init.lua" - --- If this fails, make sure you've run `lua bin/install-dependencies.lua` first! -local lemur = require("modules.lemur") - ---[[ - Collapses ModuleScripts named 'init' into their parent folders. - - This is the same result as the collapsing mechanism from Rojo. -]] -local function collapse(root) - local init = root:FindFirstChild("init") - if init then - init.Name = root.Name - init.Parent = root.Parent - - for _, child in ipairs(root:GetChildren()) do - child.Parent = init - end - - root:Destroy() - root = init - end - - for _, child in ipairs(root:GetChildren()) do - if child:IsA("Folder") then - collapse(child) - end - end - - return root -end - --- Create a virtual Roblox tree -local habitat = lemur.Habitat.new() - --- We'll put all of our library code and dependencies here -local Root = lemur.Instance.new("Folder") -Root.Name = "Root" - --- Load all of the modules specified above -for _, module in ipairs(LOAD_MODULES) do - local container = lemur.Instance.new("Folder", Root) - container.Name = module[2] - habitat:loadFromFs(module[1], container) -end - -collapse(Root) - --- Load TestEZ and run our tests -local TestEZ = habitat:require(Root.TestEZ) - -local results = TestEZ.TestBootstrap:run(Root.Plugin, TestEZ.Reporters.TextReporter) - --- Did something go wrong? -if results.failureCount > 0 then - os.exit(1) -end