change build system

This commit is contained in:
세젤귀 고양이들 2021-12-24 17:32:19 +09:00
parent 9ec0bf5377
commit 24a6e0f6b7
6 changed files with 18 additions and 672 deletions

9
build.project.json Normal file
View file

@ -0,0 +1,9 @@
{
"name": "Plugin",
"tree": {
"$properties": {
"Name": "quad"
},
"$path": "src"
}
}

View file

@ -1,648 +0,0 @@
<roblox version="4">
<Item class="ModuleScript" referent="0">
<Properties>
<string name="Name">Plugin</string>
<string name="Name">quad</string>
<string name="Source"><![CDATA[local module = {};
-- TODO : style should be can edited with anytimes, and the object's styles can be changed (add, remove ...)
-- and also, styles can be affect by the objects sorts
--[[
this feature should be like :
local style_all = style {
BackgroundTransparency = 0.2;
}
frame{
Size = UDim2.new(1,0,1,0);
textBox "#Input" {
[event.property "Text"] = function (this,text)
print(this,"의 글자가",text,"로 변경됨");
end;
};
[style.set] = {
style_all
};
};
]]
local require = require(script.require);
local event = require("event"); ---@module "src.event"
local store = require("store"); ---@module "src.store"
--local style = require("style");
local class = require("class"); ---@module "src.class"
local mount = require("mount"); ---@module "src.mount"
function module.init()
local this = {items = {}};
this.event = event.init(this);
this.store = store.init(this);
--this.style = style.init(this);
this.class = class.init(this);
this.mount = mount.init(this);
--this.makeClass = makeClass;
--this.tween = tween;
--this.plugin = plugin;
return this;
end
return module;
]]></string>
</Properties>
<Item class="ModuleScript" referent="1">
<Properties>
<string name="Name">class</string>
<string name="Source">local module = {};
-- local exportItemMeta = {
-- __index = function (self,key)
-- local methods = self.__methods;
-- local events = self.__events;
-- return (methods and methods[key]) or (events and events[key]) or (self.getters[key](self.__this));
-- end;
-- __newindex = function (self,key,value)
-- self.__setters[key](self.__this,value);
-- end;
-- };
function module.init(shared)
local new = {};
local bind = shared.event.bind;
local addObject = shared.store.addObject;
local storeNew = shared.store.new;
function new.getHolder(item)
return (type(item) == "table") and (item._holder or item.holder or item.__holder) or item;
end
local getHolder = new.getHolder;
-- make object that from instance, class and more
function new.make(ClassName,...) -- render object
-- make thing
local item;
local classOfClassName = type(ClassName);
if classOfClassName == "string" then -- if classname is a string value, cdall instance.new for making new roblox instance
item = Instance.new(ClassName);
elseif classOfClassName == "function" then -- if classname is a function value, call it for making new object (OOP object)
item = ClassName();
elseif classOfClassName == "table" then -- if classname is a calss what is included new function, call it for making new object (object)
local func = ClassName.new or ClassName.New or ClassName.__new;
if ClassName.__noSetup then -- if is support initing props
local childs,props = {},{...};
local parsed;
for iprop = #props,1,-1 do
local prop = props[iprop];
for i,v in ipairs(prop) do
childs[i] = ((iprop == 1) and v or v:Clone());
prop[i] = nil;
end
if next(prop) then -- there are (key/value)s
if parsed then
for i,v in pairs(prop) do
parsed[i] = v;
end
else
parsed = prop;
end
end
end
item = func(parsed);
local holder = getHolder(item);
for _,v in ipairs(childs) do
v.Parent = holder;
end
return item;
end
item = func();
end
if not item then -- if cannot make new object, ignore this call
local str = tostring(ClassName);
print(("fail to make item '%s', did you forget to checking the class '%s' is exist?"):format(str,str));
end
-- set property and adding child and binding functions
local holder = getHolder(item); -- to __holder or holder or it self (for tabled)
-- for iprop,prop in ipairs({...}) do
for iprop = select("#",...),1,-1 do
local prop = select(iprop,...);
for index,value in pairs(prop) do
local valueType = typeof(value);
local indexType = typeof(index);
-- child
if indexType == "string" and valueType == "table" and value.t == "reg" then -- register (bind to store event)
-- store binding
local with = value.wfunc;
local set = value.store[value.key];
if set then
if with then
set = with(set);
end
item[index] = set;
else
local dset = value.dvalue;
if dset then
item[index] = dset;
end
end
value.register(function (newValue,store)
if with then
newValue = with(newValue,item,store);
end
item[index] = newValue;
end);
elseif (valueType == "function" or valueType == "table") and bind(item,index,value,valueType) then -- connect event
-- event binding
elseif indexType == "string" then
-- prop set
item[index] = value; -- set property
elseif indexType == "number" then -- object
-- child object
((iprop == 1) and value or value:Clone()).Parent = holder;
end
end
end
return item;
end
local make = new.make;
-- import quad object
function new.import(ClassName,defaultProperties) -- make new quad class object
local this = defaultProperties or {};
setmetatable(this,{
__call = function (self,prop)
if type(prop) == "string" then
local lastName = prop;
return function (nprop)
nprop.Name = lastName;
local item = make(ClassName,nprop);
addObject(lastName,item);
return item;
end;
end
return make(ClassName,prop,this);
end;
});
return this;
end
-- function new.export(newFn,setters,getters,methods,events) -- make quad importable class
-- return function ()
-- return setmetatable({
-- __this = newFn();
-- __setters = setters;
-- __getters = getters;
-- __methods = methods;
-- __events = events;
-- },exportItemMeta);
-- end;
-- end
-- set module calling function
setmetatable(new,{
__call = function (self,...)
return new.import(...);
end;
});
-- make class
function new.extend()
local this = {};
--- make new object
function this.new(prop)
-- make metatable
prop = storeNew(prop);
local parent = prop and (prop.Parent or prop.parent);
local self = {__prop = prop; __parent = parent};
local init = this.init;
if init then
init(self,prop);
end
setmetatable(self,this);
-- render that
local object = self:render(prop);
rawset(self,"__object",object);
rawset(self,"__holder",object);
if parent then
rawset(self,"__parent",parent);
object.Parent = getHolder(parent);
end
return self;
end
--- re-render object (if some props chaged, call this to render again)
function this:update() -- swap object
local object = rawget(self,"__object"); -- get last instance
local parent = rawget(self,"__parent") or (object and object.Parent); -- date parent
local lastObject = object;
if lastObject then
lastObject.Parent = nil;
end
object = self:render(self.__prop); -- new instance
rawset(self,"__holder",object);
rawset(self,"__object",object);
object.Parent = getHolder(parent); -- update parent
if lastObject then -- remove old instance
self:Destroy(lastObject);
end
end
-- define destroy method
function this:Destroy(object)
local unload = rawget(self,"unload");
object = object or rawget(self,"__object");
if object then
if unload then
unload(self,object);
else
local destroy = (object.Destroy or object.destroy);
if destroy then
pcall(destroy,object);
end
end
end
end
--- link to new
function this.__call(self,...)
return (self.new or self.New or self.__new)(...);
end;
-- indexer (getter)
function this:__index(k)
if k == "destroy" then
return self.Destroy;
end
local getter = this.getter[k];
if getter then
return getter(self,rawget(self,"__object"));
end
-- from this (have more priority)
local fromThis = this[k];
if fromThis then
return fromThis;
end
-- from prop, not start with '_' (private value)
if k:sub(1,1) ~= "_" then
return self.__prop[k];
end
end
--- new indexer (setter)
function this:__newindex(k,v)
-- from setter
local setter = this.setter[k];
if setter then
return setter(self,v,rawget(self,"__object"));
end
-- is private (self value)
if k == "holder" or k:sub(1,1) == "_" then
return rawset(self,k,v);
end
-- prop update
self.__prop[k] = v;
if this.updateTriggers[k] then
self:update();
end
end
this.getter = {};
this.setter = {
Parent = function(self,parent,object)
rawset(self,"__parent",parent);
if object then
object.Parent = getHolder(parent);
end
end;
};
this.updateTriggers = {};
this.__noSetup = true;
return this;
end
return new;
end
return module;</string>
</Properties>
</Item>
<Item class="ModuleScript" referent="2">
<Properties>
<string name="Name">event</string>
<string name="Source">local module = {};
function module.init(shared)
local new = {};
local unpack = table.unpack;
local wrap = coroutine.wrap;
local prefix = "Event::";
local special = {
["Property::(.+)"] = function (this,func,property)
this.GetPropertyChangedSignal(property):Connect(function()
func(this,this[property]);
end);
end;
["CreatedSync::"] = function (this,func)
func(this);
end;
["Created::"] = function (this,func)
wrap(func)(this);
end;
};
local prefixLen = #prefix;
setmetatable(new,{
__call = function(self,eventName)
return prefix .. eventName;
end;
});
-- try binding, if key dose match with anything, ignore call
function new.bind(this,key,func,typefunc)
-- if is advanced binding (self setted)
typefunc = typefunc or type(func);
local self;
if typefunc == "table" then
self = func.self;
func = func.func;
end
-- check prefix
if key:sub(1,prefixLen) ~= prefix then
return;
elseif not func then
return true;
end
key = key:sub(prefixLen + 1,-1);
-- find special bindings
for specKey,specFunc in pairs(special) do
local find = {key:match(specKey)};
if #find ~= 0 then
specFunc(this,func,unpack(find));
return true;
end
end
-- binding normal events
local event = this[key];
if event then
event:Connect(function(...)
func(self or this,...);
end);
return true;
end
end
-- property changed binding
local prefixProperty = prefix .. "Property::";
function new.prop(name)
return prefixProperty .. name;
end
-- when created binding
new.created = prefix .. "Created::";
new.createdSync = prefix .. "CreatedSync::";
return new;
end
return module;</string>
</Properties>
</Item>
<Item class="ModuleScript" referent="3">
<Properties>
<string name="Name">mount</string>
<string name="Source">local module = {};
function module.init(shared)
local new = {};
local mount = {};
mount.__index = mount;
function mount:unmount()
local this = self.this;
local typeThis = type(this);
if typeThis == "userdata" then
this:Destroy();
elseif typeThis == "table" then
pcall(function()
this.Parent = nil;
end);
local destroyThis = this.Destroy;
if destroyThis then
pcall(destroyThis);
end
end
end
-- we should add plugin support
function new.mount(to,this)
this.Parent = to;
return setmetatable({to = to,this = this},mount);
end
setmetatable(new,{
__call = function (self,...)
return new.mount(...);
end;
});
return new;
end
return module;</string>
</Properties>
</Item>
<Item class="ModuleScript" referent="4">
<Properties>
<string name="Name">require</string>
<string name="Source">-- remove the roblox's require system,
-- now, we can call modules with string path
if (not workspace) and (not game) and (not script) then
return;
end
return function (query)
local typeQuery = type(query);
if typeQuery == "string" then
local object = script.Parent;
query = query:gsub("/",".");
-- local index = 0;
query:gsub("[^%.]+",function (this)
-- index = index + 1;
-- if index == 1 and this == "src" then
-- return;
-- end
local lastObject = object;
object = object[this];
if not object then
object = lastObject.libs
error(("[require] : object %s was not found from this worktree, require failed"):format(query));
end
end);
return require(object);
elseif typeQuery == "userdata" then
return require(query);
end
end;</string>
</Properties>
</Item>
<Item class="ModuleScript" referent="5">
<Properties>
<string name="Name">store</string>
<string name="Source"><![CDATA[local module = {};
--[[
this feature allows get object without making some created callback and local var
but, it can't allows mulit id and object
this feature should be upgraded
]]
local wrap = coroutine.wrap;
local insert = table.insert;
local remove = table.remove;
local function catch(...)
local passed,err = pcall(...);
if not passed then
wran("[QUAD] Error occured while operating async task\n" .. tostring(err));
end
end
function module.init(shared)
local new = {};
local items = shared.items;
-- id space (array of object)
local objSpace = {};
function objSpace:each(func)
for i,v in ipairs(self) do
wrap(catch)(func,i,v);
end
end
function objSpace:eachSync(func)
for i,v in ipairs(self) do
local ret = func(i,v);
if ret then
break;
end
end
end
function objSpace:remove(indexOrItem)
local thisType = type(indexOrItem);
if thisType == "number" then
remove(self,indexOrItem);
else
for i,v in pairs(self) do
if v == indexOrItem then
remove(self,i);
break;
end
end
end
end
function objSpace.__new()
return setmetatable({},objSpace);
end
function objSpace:__newIndex(key,value) -- props setter
self:each(function (this)
this[key] = value;
end);
end
objSpace.__mode = "kv"; -- week link for gc
objSpace.__index = objSpace;
-- get object array with id (objSpace)
function new.getObjects(id)
return items[id];
end
-- get first object with id (not array)
function new.getObject(id)
local item = items[id];
return item and item[1];
end
--TODO: if item is exist already, ignore this call
-- adding object with id
function new.addObject(ids,object)
for id in ids:gmatch("[^,]+") do -- split by ,
-- remove trailing, heading spaces
id = id:gsub("^ +",""):gsub(" +$","");
local array = items[id];
if not array then
array = objSpace.__new();
items[id] = array;
end
insert(array, object);
end
end
-- bindable store object
local store = {};
function store:__index(key)
return self.__self[key];
end
function store:__newindex(key,value)
self.__self[key] = value;
local event = self.__evt[key];
if event then
for _,v in ipairs(event) do
wrap(catch)(v,value,store);
end
end
end
function store:__call(key,func)
local register = self.__reg[key];
if not register then
local event = {}
self.__evt[key] = event;
register = {
register = function (efunc)
insert(event,efunc);
end;
with = function (s,efunc)
return setmetatable({wfunc = efunc},{__index = s});
end;
default = function (s,value)
return setmetatable({dvalue = value},{__index = s});
end;
key = key;
store = self;
t = "reg";
};
self.__reg[key] = register;
end
if func then
register.register(func);
end
return register;
end
function new.new(self)
return setmetatable(
{__self = self or {},__evt = {},__reg = {}},store
);
end
return new;
end
return module;
]]></string>
</Properties>
</Item>
</Item>
</roblox>

View file

@ -1 +1 @@
rojo build default.project.json -o build.rbxmx
rojo build build.project.json -o build.rbxmx

View file

@ -1,9 +1,12 @@
{
"name": "Plugin",
"tree": {
"$properties": {
"Name": "quad"
},
"$path": "src"
"$className": "DataModel",
"ReplicatedStorage": {
"$className": "ReplicatedStorage",
"Quad": {
"$path": "src"
}
}
}
}

View file

@ -1,18 +0,0 @@
{
"name": "Plugin",
"tree": {
"$className": "DataModel",
"StarterGui": {
"$className": "StarterGui",
"testGUI": {
"$className": "ScreenGui",
"testScript": {
"$path": "testScript.client.lua"
},
"quad": {
"$path": "src"
}
}
}
}
}

View file

@ -1,6 +1,6 @@
-- 이렇게 모듈을 부를 수 있다, 뒤에 if 가 붇은것은 자동완성이 뜨도록 하기 위해서 사용된다
---@module "src/init.lua"
local quad = require(script.Parent.quad);
local quad = require(game.ReplicatedStorage:WaitForChild "Quad");
local render = quad.init();
-- init 함수를 이용해 여러 스크립트가 이 모듈을 호출해도 완전히 별계의
-- 환경에서 실행될 수 있도록 만든다, init 를 호출하면 완전히 새로운 store 와 style