diff --git a/doc/architecture/rendering.md b/doc/architecture/rendering.md index 83ff05c6..fe2df172 100644 --- a/doc/architecture/rendering.md +++ b/doc/architecture/rendering.md @@ -13,7 +13,6 @@ A rendering occurs in two phases: - virtual rendering: this generates the virtual dom in memory, asynchronously - patch: applies a virtual tree to the screen (synchronously) - There are several classes involved in a rendering: - components @@ -21,9 +20,9 @@ There are several classes involved in a rendering: - fibers: small objects containing some metadata, associated with a rendering of a specific component - Components are organized in a dynamic component tree, visible in the user -interface. Whenever a rendering is initiated in a component `C`: +interface. Whenever a rendering is initiated in a component `C`: + - a fiber is created on `C` with the rendering props information - the virtual rendering phase starts on C (will asynchronously render all the child components) @@ -31,4 +30,3 @@ interface. Whenever a rendering is initiated in a component `C`: animation frame, if the fiber is done - once it is done, the scheduler will call the task callback, which will apply the patch (if it was not cancelled in the meantime). - diff --git a/doc/reference/store.md b/doc/reference/store.md index bb562edc..3be25d63 100644 --- a/doc/reference/store.md +++ b/doc/reference/store.md @@ -263,7 +263,7 @@ will perform a strict equality check and will update the component every time th check fails. Also, it may not be obvious, but it is crucial to remember that the selector -function should return an object or an array. The reason is that it needs to be +function should return an object or an array. The reason is that it needs to be observed, otherwise the component would not be able to react to changes. ### `useDispatch` diff --git a/tests/component/props_validation.test.ts b/tests/component/props_validation.test.ts index 4ea418be..15237b8a 100644 --- a/tests/component/props_validation.test.ts +++ b/tests/component/props_validation.test.ts @@ -354,7 +354,7 @@ describe("props validation", () => { async __updateProps() { try { await Component.prototype.__updateProps.apply(this, arguments); - } catch(e) { + } catch (e) { error = e; } } diff --git a/tests/doc_link_checker.test.ts b/tests/doc_link_checker.test.ts index bfdc5223..40fa3609 100644 --- a/tests/doc_link_checker.test.ts +++ b/tests/doc_link_checker.test.ts @@ -23,7 +23,7 @@ interface MarkDownSection { interface FileData { name: string; path: string[]; - fullName: string + fullName: string; links: MarkDownLink[]; sections: MarkDownSection[]; } @@ -31,30 +31,27 @@ interface FileData { const LINK_REGEXP = /\[([^\[]+)\]\(([^\)]+)\)/g; const HEADING_REGEXP = /\n(#+\s*)(.*)/g; - - export function addMardownData(fileData): void { - const sep = fileData.path.length > 0 ? '/' : ''; - const fullName = fileData.path.join('/') + sep + fileData.name; - const content = fs.readFileSync(fullName, { encoding: "utf8" }); - let m; - // get links info - do { - m = LINK_REGEXP.exec(content); - if (m) { - fileData.links.push({ name: m[0], link: m[2] }); - } - } while (m); - // get sections info - do { - m = HEADING_REGEXP.exec(content); - if (m) { - fileData.sections.push({ name: m[0], slug: slugify(m[2]) }); - } - } while (m); + const sep = fileData.path.length > 0 ? "/" : ""; + const fullName = fileData.path.join("/") + sep + fileData.name; + const content = fs.readFileSync(fullName, { encoding: "utf8" }); + let m; + // get links info + do { + m = LINK_REGEXP.exec(content); + if (m) { + fileData.links.push({ name: m[0], link: m[2] }); + } + } while (m); + // get sections info + do { + m = HEADING_REGEXP.exec(content); + if (m) { + fileData.sections.push({ name: m[0], slug: slugify(m[2]) }); + } + } while (m); } - /** * Returns a list of FileData corresponding to all files that need to be * validated. @@ -74,7 +71,7 @@ function getFiles(path: string[] = []): FileData[] { if (f.isDirectory()) { return getFiles(path.concat(f.name)); } - const fullName = path.join('/') + (path.length > 0 ? '/' : '') + f.name; + const fullName = path.join("/") + (path.length > 0 ? "/" : "") + f.name; return [ { name: f.name, @@ -88,62 +85,62 @@ function getFiles(path: string[] = []): FileData[] { return Array.prototype.concat(...files); } -const LOCAL_FILES = ['LICENSE']; +const LOCAL_FILES = ["LICENSE"]; export function isLinkValid(link: MarkDownLink, current: FileData, files: FileData[]): boolean { if (link.link.startsWith("http")) { // no check on external links return true; } - // Step 1: extract path, name, hash - // path = ['doc', 'architecture] - // name = 'rendering.md' - // hash = 'blabla' (or '' if no hash) + // Step 1: extract path, name, hash + // path = ['doc', 'architecture] + // name = 'rendering.md' + // hash = 'blabla' (or '' if no hash) - const parts = link.link.split('#'); - const hash = parts[1] || ''; - let name; - let path; - if (parts[0]) { - let temp = parts[0].split('/'); - name = temp[temp.length - 1]; - temp.splice(-1); - path = current.path.slice(); - for (let elem of temp) { - if (elem === '..') { - path.splice(-1); - } else if (elem !== '.') { - path.push(elem); - } - } - } else { - // there are no file name, so this is a relative link to the current file - name = current.name; - path = current.path; + const parts = link.link.split("#"); + const hash = parts[1] || ""; + let name; + let path; + if (parts[0]) { + let temp = parts[0].split("/"); + name = temp[temp.length - 1]; + temp.splice(-1); + path = current.path.slice(); + for (let elem of temp) { + if (elem === "..") { + path.splice(-1); + } else if (elem !== ".") { + path.push(elem); + } } + } else { + // there are no file name, so this is a relative link to the current file + name = current.name; + path = current.path; + } - // Step 2: build normalized link file name - const linkFullName = path.join('/') + (path.length > 0 ? '/' : '') + name; - - // Step 3: check link name against white list of local files - if (LOCAL_FILES.includes(linkFullName)) { - return true; - } - - // Step 4: check if there is a matching file - let target: FileData | undefined = files.find(f => f.fullName === linkFullName); - if (!target) { - return false; - } - - // Step 5: if necessary, check if there is a corresponding link inside the target - // link name - if (hash) { - if (!target.sections.find(s => s.slug === hash)) { - return false; - } - } + // Step 2: build normalized link file name + const linkFullName = path.join("/") + (path.length > 0 ? "/" : "") + name; + // Step 3: check link name against white list of local files + if (LOCAL_FILES.includes(linkFullName)) { return true; + } + + // Step 4: check if there is a matching file + let target: FileData | undefined = files.find(f => f.fullName === linkFullName); + if (!target) { + return false; + } + + // Step 5: if necessary, check if there is a corresponding link inside the target + // link name + if (hash) { + if (!target.sections.find(s => s.slug === hash)) { + return false; + } + } + + return true; } // adapted from https://medium.com/@mhagemann/the-ultimate-way-to-slugify-a-url-string-in-javascript-b8e4a0d849e1 @@ -164,25 +161,23 @@ function slugify(str) { .replace(/-+$/, ""); // Trim - from end of text } - - //-------------------------------------------------------------------------- // Test //-------------------------------------------------------------------------- test("All markdown links work", () => { - let linkNumber = 0; - let invalidLinkNumber = 0; - const data = getFiles(); - for (let file of data) { - for (let link of file.links) { - linkNumber++; - if (!isLinkValid(link, file, data)) { - console.warn(`Invalid Link: "${link.name}" in "${file.name}"`); - invalidLinkNumber++; - } + let linkNumber = 0; + let invalidLinkNumber = 0; + const data = getFiles(); + for (let file of data) { + for (let link of file.links) { + linkNumber++; + if (!isLinkValid(link, file, data)) { + console.warn(`Invalid Link: "${link.name}" in "${file.name}"`); + invalidLinkNumber++; + } } - } - expect(invalidLinkNumber).toBe(0); - expect(linkNumber).toBeGreaterThan(10); + } + expect(invalidLinkNumber).toBe(0); + expect(linkNumber).toBeGreaterThan(10); }); diff --git a/tests/router/router.test.ts b/tests/router/router.test.ts index 03256eb1..8a9213dc 100644 --- a/tests/router/router.test.ts +++ b/tests/router/router.test.ts @@ -54,13 +54,12 @@ describe("router miscellaneous", () => { }); test("navigate in hash mode preserve location", async () => { - router = new TestRouter(env, [{ name: "users", path: "/users/{{id}}" }], {mode: "hash"}); - window.history.pushState({}, "title", window.location.origin + '/test.html'); + router = new TestRouter(env, [{ name: "users", path: "/users/{{id}}" }], { mode: "hash" }); + window.history.pushState({}, "title", window.location.origin + "/test.html"); expect(window.location.href).toBe("http://localhost/test.html"); await router.navigate({ to: "users", params: { id: 3 } }); expect(window.location.href).toBe("http://localhost/test.html#/users/3"); }); - }); describe("routeToPath", () => {