Skip to content

Commit

Permalink
♻️ new year code care (#191)
Browse files Browse the repository at this point in the history
* ♻️ move fake name generator into it's own file

* ✨ normalise accented characters in link normalisation

* ♻️ describe toParentName function's purpose

* comment for safe front matter side effect

* ♻️ move common unique logic to core package
  • Loading branch information
ianhomer authored Jan 2, 2023
1 parent fe83810 commit ffc039e
Show file tree
Hide file tree
Showing 12 changed files with 80 additions and 35 deletions.
7 changes: 7 additions & 0 deletions packages/core/src/arrays.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import { unique } from "./arrays";

describe("arrays", () => {
it("should dedupe array", () => {
expect(["a", "a", "b"].filter(unique)).toStrictEqual(["a", "b"]);
});
});
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
// convenience function to filter out duplicates in an array
export const unique = (value: string, index: number, self: string[]) =>
self.indexOf(value) === index;
23 changes: 5 additions & 18 deletions packages/core/src/builder.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { LinkType, Meta, Things, ThingType } from "@garden/types";

import { toFakeName } from "./fake";
import { hash } from "./hash";

interface ChainedBuilder {
Expand All @@ -9,8 +10,8 @@ interface ChainedBuilder {
}

class MetaBuilder implements ChainedBuilder {
meta;
thingsBuilder;
private meta;
private thingsBuilder;

constructor(thingsBuilder: ThingsBuilder, meta: Meta) {
this.thingsBuilder = thingsBuilder;
Expand Down Expand Up @@ -42,22 +43,8 @@ class MetaBuilder implements ChainedBuilder {
}
}

const WORDS = ["foo", "bar", "baz", "qux", "fez", "tik", "mox"];
const RADIX = WORDS.length;

// numberToName that returns a deterministic name from a given number based on
// the array of available words.
const numberToName = (n: number) => {
return n
.toString(RADIX)
.split("")
.reverse()
.map((i) => WORDS[parseInt(i)])
.join("-");
};

class ThingsBuilder implements ChainedBuilder {
things: Things = {};
private things: Things = {};

name(name: string) {
const meta = {
Expand Down Expand Up @@ -91,7 +78,7 @@ class ThingsBuilder implements ChainedBuilder {
};
const lookup: string[] = [];
for (let i = 0; i < count; i++) {
const name = numberToName(i);
const name = toFakeName(i);
lookup.push(name);
}

Expand Down
20 changes: 20 additions & 0 deletions packages/core/src/fake.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
/**
* Returns a fake name. The same fake name is return each time called with given
* parameters. This is useful for generating a variety of test names for the
* garden
*
* @param index - number indicating which fake name to return
* @returns string fake name
*/
export const toFakeName = (
index: number,
words = ["foo", "bar", "baz", "qux", "fez", "tik", "mox"]
) => {
const radix = words.length;
return index
.toString(radix)
.split("")
.reverse()
.map((i) => words[parseInt(i)])
.join("-");
};
14 changes: 9 additions & 5 deletions packages/core/src/hash.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
import { linkResolver } from "./link";

// cheap checksum
/**
* Generate a cheap checksum from a string. This is used to append to duplicate
* named things in the garden to allow de-duplication.
*
* @param source - string to generate a hash from
* @returns checksum for the string
*/
export const hash = (source: string) => {
if (source.length === 0) {
return "0";
Expand All @@ -13,6 +17,6 @@ export const hash = (source: string) => {
// bitwise to 32 bit integer
value |= 0;
}
// redix with radix 36, i.e. characters 0-9a-z
return Math.abs(value).toString(36); // + linkResolver(source);
// redix with radix 36, i.e. use characters in the range 0-9 or a-z
return Math.abs(value).toString(36);
};
2 changes: 2 additions & 0 deletions packages/core/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { unique } from "./arrays";
import { builder } from "./builder";
import { hash } from "./hash";
import {
Expand All @@ -18,4 +19,5 @@ export {
linkResolver,
pageResolver,
toParentName,
unique,
};
15 changes: 10 additions & 5 deletions packages/core/src/link.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,16 @@ import {
} from ".";

describe("link", () => {
it("should render link in lowercase", () => {
expect(pageResolver("Page")).toStrictEqual(["page"]);
});
it("should render space as dash", () => {
expect(pageResolver("word 1")).toStrictEqual(["word-1"]);
describe("resolver", () => {
it("should render link in lowercase", () => {
expect(pageResolver("Page")).toStrictEqual(["page"]);
});
it("should render space as dash", () => {
expect(pageResolver("word 1")).toStrictEqual(["word-1"]);
});
it("should normalised accented characters", () => {
expect(pageResolver("áxâxÅxôxéxý")).toStrictEqual(["axaxaxoxexy"]);
});
});

it("should validate page name", () => {
Expand Down
19 changes: 19 additions & 0 deletions packages/core/src/link.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,20 @@
import { ItemLink, Nameable } from "@garden/types";

/**
* Generate the link name given for the text. This is a common normalisation for
* any text so that it can be referenced in a URL.
*
* @param name - text to normalise to a link name
* @returns normalised link name
*/
export const linkResolver = (name: string) =>
name
.replace(/[ \\/\\.]/g, "-")
.toLowerCase()
// normalize according to NFD - canonical decompisition - https://unicode.org/reports/tr15/
// NFD effectively removes accents and reduces variations on to single form
// more suitable for URLs
.normalize("NFD")
.replace(/[^a-z0-9-]/g, "");

// A page resolver plugin compatible with the remark-wiki-link pageResolver
Expand All @@ -17,6 +28,14 @@ export const isValidPageName = (name: string) =>

export const isNotValidPageName = (name: string) => !isValidPageName(name);

/**
* Get the parent name of an item based on the child name. A child name is
* composed of the parent name followed by the "#" character and then the
* relative child name, e.g. a-parent#a-child.
*
* @param name - child name
* @returns parent name
**/
export const toParentName = (name: string) => {
const index = name.indexOf("#");
return index > 0 ? name.slice(0, index) : undefined;
Expand Down
2 changes: 1 addition & 1 deletion packages/garden/src/base-garden-repository.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { GardenRepository, ItemReference } from "@garden/types";
import { BaseItem } from "./base-item";

export class BaseGardenRepository implements GardenRepository {
content;
private content;

constructor(content: { [key: string]: string } = {}) {
this.content = Object.fromEntries(
Expand Down
5 changes: 4 additions & 1 deletion packages/garden/src/base-item.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,10 @@ import { MarkdownMessage } from "./markdown-message";
const safeMatter = (content: string) => {
try {
// Note that the gray matter API caches the results if there are no options.
// Caching is not desired in this system so this side effect is appropriate.
// In this system, caching is undesirable since it masks potential errors
// and complicates reloading. Explicitly setting the language for the
// frontmatter, other than setting our desired front matter also has the
// desired side effect that caching is disabled.
return matter(content, { language: "yaml" });
} catch (error) {
const message =
Expand Down
4 changes: 1 addition & 3 deletions packages/garden/src/garden.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
import { hash, linkResolver } from "@garden/core";
import { hash, linkResolver, unique } from "@garden/core";
import {
GardenRepository,
Link,
LinkType,
Meta,
Thing,
Things,
ThingType,
Expand All @@ -13,7 +12,6 @@ import os from "os";
import { join } from "path";

import { BaseGardenRepository } from "./base-garden-repository";
import { unique } from "./common";
import { FileGardenRepository } from "./file-garden-repository";
import { justNaturalAliasLinks } from "./links";
import { logger } from "./logger";
Expand Down
3 changes: 1 addition & 2 deletions packages/garden/src/nlp.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
import { unique } from "@garden/core";
import { Link, LinkType } from "@garden/types";
import nlp from "compromise";
import Three from "compromise/types/view/three";

import { unique } from "./common";

interface Noun {
adjectives: string[];
root: string;
Expand Down

1 comment on commit ffc039e

@vercel
Copy link

@vercel vercel bot commented on ffc039e Jan 2, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please sign in to comment.