From 95e90568dba7d002686236847e30fcf339cfd0ed Mon Sep 17 00:00:00 2001 From: metacryst Date: Mon, 8 Apr 2024 20:19:22 -0500 Subject: [PATCH] removing logs, moving parse function to bottom --- Test/observedobject.test.js | 3 + Test/parse.test.js | 308 +++++++++++++++++++++--------------- Test/test.js | 18 +-- index.js | 302 ++++++++++++++++++++++++----------- 4 files changed, 396 insertions(+), 235 deletions(-) diff --git a/Test/observedobject.test.js b/Test/observedobject.test.js index ae87fd6..c9a6288 100644 --- a/Test/observedobject.test.js +++ b/Test/observedobject.test.js @@ -39,10 +39,13 @@ window.testSuites.push( class testObservedObject { } } + // throw some sort of warning if a global OO is accessed without "this" + NotExtensible() { return "not done" } + // MustInitAllFields() { // class Form extends ObservedObject { // id diff --git a/Test/parse.test.js b/Test/parse.test.js index f1764af..edc1bb5 100644 --- a/Test/parse.test.js +++ b/Test/parse.test.js @@ -1,152 +1,198 @@ window.testSuites.push( class testParse { -testParseConstructor() { - class Space extends Shadow { - form - contents = [] - - constructor(...params) { - super(...params) + testParseConstructor() { + class Space extends Shadow { + form + contents = [] + + constructor(...params) { + super(...params) + } } - } - let newClass = window.Registry.parseConstructor(Space) - if(!newClass.prototype.constructor.toString().includes("window.Registry.construct(")) { - return "'window.Registry.construct(' not detected!" - } -} - -testParseConstructorIfNoneProvided() { - class Space extends Shadow { - $form - } - - let newClass = window.Registry.parseConstructor(Space) - if(!newClass.prototype.constructor.toString().includes("window.Registry.construct(")) { - return "'window.Registry.construct(' not detected!" - } -} - -testParseConstructorFailsIfNoSuper() { - class Space extends Shadow { - form - contents = [] - - constructor() { - } - } - - try { let newClass = window.Registry.parseConstructor(Space) - return "No error thrown!" - } catch(e) { - - } -} - -testParseClassFieldsWithNoDefault() { - class Space extends Shadow { - form - contents = [] - - constructor(...params) { - super(...params) + if(!newClass.prototype.constructor.toString().includes("window.Registry.construct(")) { + return "'window.Registry.construct(' not detected!" } } - const fields = window.Registry.parseClassFields(Space); - if(!(JSON.stringify(fields) === JSON.stringify(["form", "contents"]))) { - return `Fields don't match` - } -} + testParseConstructorIfNoneProvided() { + class Space extends Shadow { + $form + } -testParseClassFieldsWithEqualityCheck() { - class Space extends Shadow { - form = Forms.observe(window.location.pathname, this) - - contents = [ - ...this.form.children.map(form => { - switch(form.type) { - case "file" === "file": - return File(form) - case "space": - return ChildSpace(form) - case "link": - return Link() - } - }) - ] - - constructor(...params) { - super(...params) + let newClass = window.Registry.parseConstructor(Space) + if(!newClass.prototype.constructor.toString().includes("window.Registry.construct(")) { + return "'window.Registry.construct(' not detected!" } } - const fields = window.Registry.parseClassFields(Space); - if(!(JSON.stringify(fields) === JSON.stringify(["form", "contents"]))) { - return `Fields don't match` - } -} + testParseConstructorFailsIfNoSuper() { + class Space extends Shadow { + form + contents = [] + + constructor() { + } + } -testParseClassFieldsWithInnerFunctionVariable() { - class Space extends Shadow { - form = Forms.observe(window.location.pathname, this) - - contents = [ - ...this.form.children.map(form => { - let file; - file = "hey" - switch(form.type) { - case "file" === "file": - return File(form) - case "space": - return ChildSpace(form) - case "link": - return Link() - } - }) - ] - - constructor(...params) { - super(...params) + try { + let newClass = window.Registry.parseConstructor(Space) + return "No error thrown!" + } catch(e) { + + } + } + + testParseClassFieldsWithNoDefault() { + class Space extends Shadow { + form + contents = [] + + constructor(...params) { + super(...params) + } + } + + const fields = window.Registry.parseClassFields(Space); + if(!(JSON.stringify(fields) === JSON.stringify(["form", "contents"]))) { + return `Fields don't match` } } - const fields = window.Registry.parseClassFields(Space); - if(!(JSON.stringify(fields) === JSON.stringify(["form", "contents"]))) { - return `Fields don't match` - } -} + testParseClassFieldsWithEqualityCheck() { + class Space extends Shadow { + form = Forms.observe(window.location.pathname, this) + + contents = [ + ...this.form.children.map(form => { + switch(form.type) { + case "file" === "file": + return File(form) + case "space": + return ChildSpace(form) + case "link": + return Link() + } + }) + ] + + constructor(...params) { + super(...params) + } + } -ParseConstructorWithFunctionsBelow() { - class Space extends Shadow { - $$form = Forms.observe(window.location.pathname, this) - - render = () => { - ForEach(this.form.children, (form) => { - switch(form.type) { - case "file": - File(form) - break - case "space": - ChildSpace(form) - break - case "link": - Link() - break - } - }) - } - - constructor() { - super() - } - - connectedCallback() { + const fields = window.Registry.parseClassFields(Space); + if(!(JSON.stringify(fields) === JSON.stringify(["form", "contents"]))) { + return `Fields don't match` } } - - window.Registry.parseConstructor(Space) -} + + testParseClassFieldsWithInnerFunctionVariable() { + class Space extends Shadow { + form = Forms.observe(window.location.pathname, this) + + contents = [ + ...this.form.children.map(form => { + let file; + file = "hey" + switch(form.type) { + case "file" === "file": + return File(form) + case "space": + return ChildSpace(form) + case "link": + return Link() + } + }) + ] + + constructor(...params) { + super(...params) + } + } + + const fields = window.Registry.parseClassFields(Space); + if(!(JSON.stringify(fields) === JSON.stringify(["form", "contents"]))) { + return `Fields don't match` + } + } + + ParseConstructorWithFunctionsBelow() { + class Space extends Shadow { + $$form = Forms.observe(window.location.pathname, this) + + render = () => { + ForEach(this.form.children, (form) => { + switch(form.type) { + case "file": + File(form) + break + case "space": + ChildSpace(form) + break + case "link": + Link() + break + } + }) + } + + constructor() { + super() + } + + connectedCallback() { + } + } + + window.Registry.parseConstructor(Space) + } + + ParseRender() { + class Sidebar extends Shadow { + $$windowState = windowState + $$form = Forms.observe(window.location.pathname) + $sidebarPos = -200 + + render = () => { + VStack(() => { + ForEach(this.form.children, (form) => { + switch(form.constructor.name) { + case "File": + SidebarFile(form) + break + case "Space": + SidebarSpace(form) + break + } + }) + }) + .background("black") + .positionType("absolute") + .x(this.windowState.sidebarOut ? 0 : -200) + .y(0) + .width(200, "px") + .height(100, "vh") + } + } + + let result = Registry.parseRender(Sidebar) + console.log(result) + + let expectedOutput = "[[VStack.ForEach, form.children], [VStack.x, windowState.sidebarOut]]" + + if(JSON.stringify(result) !== JSON.stringify(expectedOutput)) { + return "Result does not match expected array!" + } + } + + CopyTo() { + let str = "render=()=>{VStack(()=>{" + let ret = str.copyTo("{") + console.log(ret) + + if(ret !== "render=()=>") return "Copy 1 failed!" + } }) \ No newline at end of file diff --git a/Test/test.js b/Test/test.js index 5e6d7bd..cd9a6a2 100644 --- a/Test/test.js +++ b/Test/test.js @@ -2,9 +2,9 @@ console.log("Tests initializing.") window.testSuites = []; await import ("./parse.test.js") -await import ("./init.test.js") -await import ("./render.test.js") -await import ("./observedobject.test.js") +// await import ("./init.test.js") +// await import ("./render.test.js") +// await import ("./observedobject.test.js") window.randomName = function randomName(prefix) { const sanitizedPrefix = prefix.toLowerCase().replace(/[^a-z0-9]/g, ''); @@ -75,13 +75,13 @@ window.test = async function() { console.log("") let elapsed = new Date() - start; if(failed === 0) { - console.log(`%cRan ${failed+success} tests in ${elapsed}ms`, 'background: #222; color: #00FF00'); - console.log(`%c ${success} passed`, 'background: #222; color: #00FF00'); - console.log(`%c ${failed} failed`, 'background: #222;'); + console.log(`%cRan ${failed+success} tests in ${elapsed}ms`, 'color: #00FF00'); + console.log(`%c ${success} passed`, 'color: #00FF00'); + console.log(`%c ${failed} failed`); } else { - console.log(`%cRan ${failed+success} tests in ${elapsed}ms`, 'background: #222; color: rgb(254, 62, 43)'); - console.log(`%c ${success} `, 'background: #222; color: #00FF00', "passed"); - console.log(`%c ${failed} failed`, 'background: #222; color: rgb(254, 62, 43)'); + console.log(`%cRan ${failed+success} tests in ${elapsed}ms`, 'color: rgb(254, 62, 43)'); + console.log(`%c ${success} `, 'color: #00FF00', "passed"); + console.log(`%c ${failed} failed`, 'color: rgb(254, 62, 43)'); } } diff --git a/index.js b/index.js index b855a7f..8a22caf 100644 --- a/index.js +++ b/index.js @@ -308,7 +308,7 @@ window.Registry = class Registry { if(!objName) return; let valueCheck = parent[objName][objField] - if(valueCheck && valueCheck === value) { + if(valueCheck !== undefined && valueCheck === value) { if(!parent[objName]._observers[objField].get(elem)) { parent[objName]._observers[objField].set(elem, []) } @@ -380,14 +380,14 @@ window.Registry = class Registry { Object.defineProperty(elem, name, { set: function(newValue) { - elem[backingFieldName] = newValue; // Use the backing field to store the value + elem[backingFieldName] = newValue; elem.setAttribute(name, typeof newValue === "object" ? "{..}" : newValue); - for (let [observer, properties] of elem._observers[name]) { + for (let [element, properties] of elem._observers[name]) { for (let property of properties) { if(Array.isArray(property)) { - observer[property[0]][property[1]] = newValue; + element[property[0]][property[1]] = newValue; } else { - observer[property] = newValue; + element[property] = newValue; } } } @@ -495,95 +495,6 @@ window.Registry = class Registry { return elIncarnate } } - - static parseClassFields(classObject) { - let str = classObject.toString(); - const lines = str.split('\n'); - const fields = []; - let braceDepth = 0; // Tracks the depth of curly braces to identify when we're inside a function/method - - for (let line of lines) { - const trimmedLine = line.trim(); - - // Update braceDepth based on the current line - braceDepth += (trimmedLine.match(/{/g) || []).length; - braceDepth -= (trimmedLine.match(/}/g) || []).length; - - // Check if the line is outside any function/method (top-level within the class) - if (braceDepth === 1) { - // Attempt to match a class field declaration with or without initialization - const fieldMatch = trimmedLine.match(/^([a-zA-Z_$][0-9a-zA-Z_$]*)\s*(=|;|\n|$)/); - if (fieldMatch) { - fields.push(fieldMatch[1]); - } - } - - // If we encounter the constructor, stop the parsing as we're only interested in fields above it - if (trimmedLine.startsWith('constructor')) { - break; - } - } - - return fields; - } - - static parseConstructor(classObject) { - let str = classObject.toString(); - const lines = str.split('\n'); - let modifiedLines = []; - let braceDepth = 0; - let constructorFound = false - let superCallFound = false; - let constructorEndFound = false; - - for (let i = 0; i < lines.length; i++) { - let line = lines[i]; - const trimmedLine = line.trim(); - - modifiedLines.push(line); - - braceDepth += (trimmedLine.match(/{/g) || []).length; - braceDepth -= (trimmedLine.match(/}/g) || []).length; - - if (trimmedLine.startsWith('constructor(')) { - constructorFound = true; - } - - if (constructorFound && trimmedLine.startsWith('super(') && !superCallFound) { - superCallFound = true; - modifiedLines.push(` window.Registry.construct(this);`); - } - - if (constructorFound && braceDepth === 1 && superCallFound && !constructorEndFound) { - modifiedLines.splice(modifiedLines.length - 1, 0, ' Object.preventExtensions(this);'); - modifiedLines.splice(modifiedLines.length - 1, 0, ' window.Registry.testInitialized(this);'); - constructorEndFound = true - } - } - - if(superCallFound) { - let modifiedStr = modifiedLines.join('\n'); - modifiedStr = '(' + modifiedStr + ')' - modifiedStr += `//# sourceURL=${classObject.prototype.constructor.name}.shadow` - return eval(modifiedStr); - } - - if(constructorFound) { - throw new Error("Quill: Constructor must have super()! " + lines[0]) - } else { - let constructorString = ` - constructor(...params) { - super(...params) - window.Registry.construct(this) - Object.preventExtensions(this); - window.Registry.testInitialized(this); - } - ` - let closingBracket = str.lastIndexOf("}"); - str = str.slice(0, closingBracket - 1) + constructorString + "\n}" - return eval('(' + str + `) //# sourceURL=${classObject.prototype.constructor.name}.shadow`); - } - } } /* DEFAULT WRAPPERS */ @@ -843,5 +754,206 @@ HTMLElement.prototype.onHover = function(cb) { return this } +/* PARSE */ + +Registry.parseClassFields = function(classObject) { + let str = classObject.toString(); + const lines = str.split('\n'); + const fields = []; + let braceDepth = 0; // Tracks the depth of curly braces to identify when we're inside a function/method + + for (let line of lines) { + const trimmedLine = line.trim(); + + // Update braceDepth based on the current line + braceDepth += (trimmedLine.match(/{/g) || []).length; + braceDepth -= (trimmedLine.match(/}/g) || []).length; + + // Check if the line is outside any function/method (top-level within the class) + if (braceDepth === 1) { + // Attempt to match a class field declaration with or without initialization + const fieldMatch = trimmedLine.match(/^([a-zA-Z_$][0-9a-zA-Z_$]*)\s*(=|;|\n|$)/); + if (fieldMatch) { + fields.push(fieldMatch[1]); + } + } + + // If we encounter the constructor, stop the parsing as we're only interested in fields above it + if (trimmedLine.startsWith('constructor')) { + break; + } + } + + return fields; +} + +Registry.parseConstructor = function(classObject) { + let str = classObject.toString(); + const lines = str.split('\n'); + let modifiedLines = []; + let braceDepth = 0; + let constructorFound = false + let superCallFound = false; + let constructorEndFound = false; + + for (let i = 0; i < lines.length; i++) { + let line = lines[i]; + const trimmedLine = line.trim(); + + modifiedLines.push(line); + + braceDepth += (trimmedLine.match(/{/g) || []).length; + braceDepth -= (trimmedLine.match(/}/g) || []).length; + + if (trimmedLine.startsWith('constructor(')) { + constructorFound = true; + } + + if (constructorFound && trimmedLine.startsWith('super(') && !superCallFound) { + superCallFound = true; + modifiedLines.push(` window.Registry.construct(this);`); + } + + if (constructorFound && braceDepth === 1 && superCallFound && !constructorEndFound) { + modifiedLines.splice(modifiedLines.length - 1, 0, ' Object.preventExtensions(this);'); + modifiedLines.splice(modifiedLines.length - 1, 0, ' window.Registry.testInitialized(this);'); + constructorEndFound = true + } + } + + if(superCallFound) { + let modifiedStr = modifiedLines.join('\n'); + modifiedStr = '(' + modifiedStr + ')' + modifiedStr += `//# sourceURL=${classObject.prototype.constructor.name}.shadow` + return eval(modifiedStr); + } + + if(constructorFound) { + throw new Error("Quill: Constructor must have super()! " + lines[0]) + } else { + let constructorString = ` + constructor(...params) { + super(...params) + window.Registry.construct(this) + Object.preventExtensions(this); + window.Registry.testInitialized(this); + } + ` + let closingBracket = str.lastIndexOf("}"); + str = str.slice(0, closingBracket - 1) + constructorString + "\n}" + return eval('(' + str + `) //# sourceURL=${classObject.prototype.constructor.name}.shadow`); + } +} + +Registry.getRender = function(classObject) { + const classString = classObject.toString(); + + const regular = /render\s*\(\s*\)\s*\{/; + const arrow = /render\s*=\s*\(\s*\)\s*=>\s*\{/; + const matches = classString.match(regular) || classString.match(arrow); + + if(matches && matches.length === 1) { + return classString.substring(matches.index) + } else { + console.error("Quill: render funcion not defined properly!") + } +} + + +Registry.parseRender = function(classObject) { + let str = Registry.getRender(classObject.toString()).replace(/\s/g, ""); + console.log(str) + let functionStack = [] + let i = str.indexOf("{"); + + let firstEl = str.copyTo("(", i) + if(!firstEl) { + console.log("Empty render function") + return + } else { + i += firstEl.length + 1 + } + + if(firstEl.includes("Stack")) { + parseArrowFunction(str, i) + } + + return usage; +} + +function parseArrowFunction(str, i) { + i += str.copyTo("{", i).length + 1 + console.log(str[i]) + let firstEl = str.copyTo("(", i) + console.log(firstEl) +} + +function firstParam(str, i) { + console.log(str[i]) + switch(str[i]) { + case "(": + console.log("function") + break; + case "\"": + console.log("string") + break; + default: + if (!isNaN(input)) { + console.log("Number"); + } else { + console.log("Variable"); + } + } +} + +String.prototype.copyTo = function(char, i=0) { + let copied = "" + while(this[i]) { + if(this[i] === char) { + break; + } + copied += this[i] + + i++ + } + return copied +} + window.register = Registry.register -window.rendering = [] \ No newline at end of file +window.rendering = [] + + +// const usage = []; +// const lines = renderFunctionToClassEnd.split('\n'); + +// let currentFunction = null; +// let currentFunctionChain = []; // To keep track of nested function names + +// for (const line of lines) { +// const functionMatch = line.match(/^\s*([a-zA-Z_$][0-9a-zA-Z_$]*)\s*=\s*\(\s*\)\s*=>\s*{/); +// if (functionMatch) { +// currentFunction = functionMatch[1]; +// currentFunctionChain.push(currentFunction); +// } + +// if (line.includes('this')) { +// if (currentFunction) { +// const thisUsage = line.match(/this\.[a-zA-Z_$][0-9a-zA-Z_$]*(?:\.[a-zA-Z_$][0-9a-zA-Z_$]*)*/g); +// if (thisUsage) { +// for (const usageItem of thisUsage) { +// const propertyChain = usageItem.replace('this.', ''); +// const completeChain = [...currentFunctionChain, propertyChain]; +// usage.push(completeChain); +// } +// } +// } else { +// const thisUsage = line.match(/this\.[a-zA-Z_$][0-9a-zA-Z_$]*/g); +// if (thisUsage) { +// for (const usageItem of thisUsage) { +// const propertyChain = usageItem.replace('this.', ''); +// usage.push([propertyChain]); +// } +// } +// } +// } +// } \ No newline at end of file