diff --git a/.eslintrc.json b/.eslintrc.json index f8139e9..ce2a5ff 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -9,7 +9,15 @@ "project": ["./tsconfig.json"] }, "parser": "@typescript-eslint/parser", - "plugins": ["@typescript-eslint", "import", "simple-import-sort", "sort-exports", "typescript-sort-keys", "sort-keys", "prettier"], + "plugins": [ + "@typescript-eslint", + "import", + "simple-import-sort", + "sort-exports", + "typescript-sort-keys", + "sort-keys", + "prettier" + ], "extends": ["prettier"], "rules": { "curly": 2, @@ -28,19 +36,19 @@ "default": "generic" } ], - "@typescript-eslint/await-thenable": "error", + "@typescript-eslint/await-thenable": "off", "@typescript-eslint/consistent-type-definitions": [2, "type"], "@typescript-eslint/consistent-type-exports": "error", "@typescript-eslint/method-signature-style": "error", "@typescript-eslint/naming-convention": 0, - "@typescript-eslint/no-explicit-any": "error", + "@typescript-eslint/no-explicit-any": "off", "@typescript-eslint/no-for-in-array": "error", "@typescript-eslint/no-namespace": "error", - "@typescript-eslint/no-non-null-assertion": "error", + "@typescript-eslint/no-non-null-assertion": "off", "@typescript-eslint/no-require-imports": "error", "@typescript-eslint/no-this-alias": "error", "@typescript-eslint/no-unsafe-argument": "error", - "@typescript-eslint/no-unsafe-assignment": "error", + "@typescript-eslint/no-unsafe-assignment": "off", "@typescript-eslint/no-unsafe-member-access": "error", "@typescript-eslint/no-unsafe-return": "error", "@typescript-eslint/no-useless-empty-export": "error", @@ -64,18 +72,21 @@ ], "space-before-blocks": "off", "@typescript-eslint/space-before-blocks": ["error", "always"], - "@typescript-eslint/type-annotation-spacing": ["error", { "after": true }], + "@typescript-eslint/type-annotation-spacing": [ + "error", + { "after": true } + ], "import/first": "error", "import/newline-after-import": "error", "import/no-duplicates": "error", - "sort-exports/sort-exports": ["error", { "sortDir": "asc" }], + "sort-exports/sort-exports": ["off", { "sortDir": "asc" }], "typescript-sort-keys/interface": "error", "typescript-sort-keys/string-enum": "error", "sort-keys": 0, "sort-keys/sort-keys-fix": 2, "prettier/prettier": 2, "@typescript-eslint/no-unused-vars": "off", - "default-case": "error", + "default-case": "off", "default-case-last": "error" } } diff --git a/note.tree b/base.tree similarity index 100% rename from note.tree rename to base.tree diff --git a/code/make/note.tree b/code/make/base.tree similarity index 100% rename from code/make/note.tree rename to code/make/base.tree diff --git a/hack/code/base.ts b/hack/code/base.ts deleted file mode 100644 index f10bfc7..0000000 --- a/hack/code/base.ts +++ /dev/null @@ -1,13 +0,0 @@ -import Fill from './fill/hash.js' - -// base.ts -class Base { - fill: Fill - - card: Record - - task: Array - - // env vars - host: Record -} diff --git a/hack/code/card.ts b/hack/code/card.ts deleted file mode 100644 index 65c9d24..0000000 --- a/hack/code/card.ts +++ /dev/null @@ -1,3 +0,0 @@ -import * as card from './card/index.js' - -export default card diff --git a/hack/code/form.ts b/hack/code/form.ts deleted file mode 100644 index ca0bbfd..0000000 --- a/hack/code/form.ts +++ /dev/null @@ -1 +0,0 @@ -export * from './form/index.js' diff --git a/hack/code/form/base.ts b/hack/code/form/base.ts deleted file mode 100644 index d92f981..0000000 --- a/hack/code/form/base.ts +++ /dev/null @@ -1,22 +0,0 @@ -import { RiffDeck, SiteLookFormLink } from '~' - -export class Base { - // tasks to be run - task: Array<() => void> - - // observers - hook: Record> - - // env variables - host: Record - - // the file tree - deck: Record - - constructor() { - this.task = [] - this.hook = {} - this.host = {} - this.deck = {} - } -} diff --git a/hack/code/form/form.ts b/hack/code/form/form.ts deleted file mode 100644 index ef68c47..0000000 --- a/hack/code/form/form.ts +++ /dev/null @@ -1,40 +0,0 @@ -export enum Form { - Bear = 'bear', - Bind = 'bind', - Call = 'call', - Cite = 'cite', - CodeCard = 'code-card', - Comb = 'comb', - Deck = 'deck', - DeckCard = 'deck-card', - DeckFace = 'deck-face', - DeckLink = 'deck-link', - DeckLock = 'deck-lock', - Dock = 'dock', - Form = 'form', - FormHead = 'form-head', - Fuse = 'fuse', - HideBear = 'hide-bear', - Hold = 'hold', - Hook = 'hook', - Host = 'host', - Line = 'line', - Link = 'link', - List = 'list', - Load = 'load', - LoadFind = 'load-find', - LoadFindTake = 'load-find-take', - SideSize = 'side-size', - Size = 'size', - Suit = 'suit', - Take = 'take', - Task = 'task', - TermLink = 'term-link', - Test = 'test', - Text = 'text', - TextLink = 'text-link', - TextList = 'text-list', - Tree = 'tree', - Wave = 'wave', - Wear = 'wear', -} diff --git a/hack/code/form/index.ts b/hack/code/form/index.ts deleted file mode 100644 index 1f9301d..0000000 --- a/hack/code/form/index.ts +++ /dev/null @@ -1,4 +0,0 @@ -export * from './base.js' -export * from './mesh.js' -export * from './tree.js' -export * from './site.js' diff --git a/hack/code/form/mesh.ts b/hack/code/form/mesh.ts deleted file mode 100644 index 0b5a117..0000000 --- a/hack/code/form/mesh.ts +++ /dev/null @@ -1,11 +0,0 @@ -import { Base } from './base' -import { Tree, TreeCard } from './tree' -import { SiteFork } from './site' - -export type MeshLoad = { - base: Base - card: TreeCard - fork: SiteFork - // link: Link - riff: Tree -} diff --git a/hack/code/form/site.ts b/hack/code/form/site.ts deleted file mode 100644 index 614071b..0000000 --- a/hack/code/form/site.ts +++ /dev/null @@ -1,213 +0,0 @@ -/* eslint-disable @typescript-eslint/no-explicit-any */ -import { Base, FormMesh } from '@nerdbond/form' - -export class TreeBase { - link: Record - - hook: Record void> - - constructor() { - this.link = {} - this.hook = {} - } - - bind(name, form, hook) { - const list = (this.hook[name] ??= []) - const bind = {} - const nest = {} - for (const name in form) { - const bond = form[name] - if (isObject(bond)) { - nest[name] = bond - } else { - bind[name] = true - } - } - // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment - list.push({ bind, hook, nest }) - } -} - -export class TreeBind {} - -export class TreeFork { - constructor() { - this.link = {} - } - - bind(name, form, bond) {} - - form(name, form) {} - - save(name, bond) {} -} - -type MakeTreeBase = { - base: B - fork: TreeFork - form: FM -} - -// eslint-disable-next-line sort-exports/sort-exports -export class TreeSite< - B extends Base, - FM extends FormMesh, -> extends TreeBase { - base: B - - form: FM - - fork: TreeFork - - bond: any - - constructor({ base, form, fork }: MakeTreeBase) { - super() - this.base = base - this.form = form - this.fork = fork - } - - save( - name: string, - bond: TreeSite | string | number | boolean | null, - ) { - const link = this.form.link[name] - this.link[name] = bond - if (!testMesh(bond)) { - const bindList = this.bind[name] - if (bindList) { - for (const bind of bindList) { - bind.hook(this) - } - } - } - } - - bind1(hook: TreeHook) { - // self and all children are resolved - for (const name in form.link) { - const nestHook = () => { - this.needSize-- - this.needLink[name] = false - this.killBind2(name, nestHook) - if (this.needSize === 0) { - hook() - } - } - this.bind2(name, nestHook) - } - } - - bind2(name: string, hook: TreeHook) { - // all the children are resolved - const list = (this.bind[name] ??= []) - list.push({ hook }) - } - - bind3(name: string, test: TreeTest, hook: TreeHook) { - // subset of children are resolved - const list = (this.bind[name] ??= []) - const nest = makeTestNest(test, hook) - list.push({ hook, nest }) - - function makeTestNest(test, hook) { - const nest = [] - const site = this - let need = 0 - for (const name in test) { - need++ - const hookSelf = self => { - self.need-- - if (self.need === 0) { - hook(site) - } - } - nest.push({ hook: hookSelf, name, need }) - } - return nest - } - } -} - -type TreeTest = { - [name: string]: true | TreeTest -} - -type TreeHook = () => void - -type Matcher = { - [key: string]: true | Matcher -} - -type Callback = () => void - -abstract class TreeElement { - #parent?: TreeObject - - #listeners: Array<{ callback: Callback; matcher?: Matcher }> = [] - - constructor(parent?: TreeObject) { - this.#parent = parent - } - - watch(callback: Callback, matcher?: Matcher) { - if (this.isResolved(matcher)) { - callback.call(this) - } else { - this.#listeners.push({ callback, matcher }) - } - } - - notify() { - // empty(!) the listeners array and let the watch method deal with them - for (const { callback, matcher } of this.#listeners.splice(0)) { - this.watch(callback, matcher) - } - this.#parent?.notify() // bubble up - } - - abstract isResolved(matcher?: Matcher): boolean -} - -class TreeObject extends TreeElement { - #properties: Record = {} - - createObject(name: string) { - return (this.#properties[name] = new TreeObject(this)) - } - - createLiteral(name: string) { - return (this.#properties[name] = new TreeLiteral(this)) - } - - isResolved(matcher?: Matcher): boolean { - const keys = Object.keys(matcher ?? this.#properties) - return ( - keys.length > 0 && - keys.every(key => - this.#properties[key]?.isResolved( - !matcher || matcher?.[key] === true - ? undefined - : (matcher[key] as Matcher), - ), - ) - ) - } -} - -class TreeLiteral extends TreeElement { - #literalValue: any - - #isResolved = false - - set(value: any) { - this.#literalValue = value - this.#isResolved = true - this.notify() - } - - isResolved(): boolean { - return this.#isResolved - } -} diff --git a/hack/code/form/tree.ts b/hack/code/form/tree.ts deleted file mode 100644 index 5066707..0000000 --- a/hack/code/form/tree.ts +++ /dev/null @@ -1,500 +0,0 @@ -import { Form } from './form' - -export type Tree = - | TreeBear - | TreeBind - | TreeCall - | TreeLike - | TreeCodeCard - | TreeComb - | TreeDeck - | TreeDeckCard - | TreeDeckFace - | TreeDeckLock - | TreeDock - | TreeForm - | TreeFormHead - | TreeFuse - | TreeHideBear - | TreeHold - | TreeHook - | TreeHost - | TreeLine - | TreeLink - | TreeLoad - | TreeLoadFind - | TreeLoadFindTake - | TreeSideSize - | TreeSize - | TreeSuit - | TreeTake - | TreeTask - | TreeLine - | TreeTest - | TreeText - | TreeTextLink - | TreeTree - | TreeWave - | TreeWear - | TreeDeckLink - -export type TreeBase = { - // id - // code: string - // parent, so we can build paths - base?: Tree - // module associated with this, for easier error reporting - card?: TreeCard - // scope associated with this node. - fork: any - // unprocessed yet - needSize: number - // state of how complete the AST node is. - riseMark: TreeRiseMark - // list of children values which are dynamic unparsed terms - // list: Array - // how it is passed down. - slot: string - // the link tree (parsed text) associated with this - // tree: LinkTreeType - // runtime type - workForm?: TreeName - // whether or not the type form is accepted - workFormTake: boolean -} - -// export type TreeComb = TreeBase & { -// form: `tree-${Form.Comb}` -// type: Mesh.Decimal -// } -export type TreeBear = TreeBase & { - form: `tree-${Form.Bear}` - link: { - hide: TreeList - link?: TreeText - } -} - -export type TreeBind = TreeBase & { - form: `tree-${Form.Bind}` - link: { - bond?: TreeBond // or more - name?: TreeLine - } -} - -export type TreeBond = - | TreeText - | TreeSize - | TreeSideSize - | TreeComb - | TreeWave - -export type TreeCall = TreeBase & { - form: `tree-${Form.Call}` - link: { - bind: TreeList - line?: TreeLineForm - risk?: TreeWave - wait?: TreeWave - } -} - -export type TreeCard = TreeCodeCard | TreeDeckCard - -export type TreeCodeCard = TreeBase & { - form: `tree-${Form.CodeCard}` - link: { - bear: TreeList - dock: TreeList - form: TreeList - fuse: TreeList - hook: TreeList - host: TreeList - line: string - lineText: Array - linkTree: LinkTreeType - load: TreeList - suit: TreeList - task: TreeList - test: TreeList - text: string - tree: TreeList - } -} - -export type TreeComb = TreeBase & { - form: `tree-${Form.Comb}` - link: { - bond: number - } -} - -export type TreeDeck = TreeBase & { - form: `tree-${Form.Deck}` - link: { - bear?: TreeText - deck: TreeList - face: TreeList - host?: TreeText - mark?: TreeText - name?: TreeText - read?: TreeText - term: TreeList - test?: TreeText - } -} - -export type TreeDeckCard = TreeBase & { - form: `tree-${Form.DeckCard}` - link: { - deck?: TreeDeck - line: string - } -} - -export type TreeDeckFace = TreeBase & { - form: `tree-${Form.DeckFace}` - link: { - name?: TreeText - site?: TreeText - } -} - -export type TreeDeckLink = TreeBase & { - form: `tree-${Form.DeckLink}` - link: { - mark?: TreeText - name?: TreeText - } -} - -export type TreeDeckLock = TreeBase & { - form: `tree-${Form.DeckLock}` - link: {} -} - -export type TreeDock = TreeBase & { - form: `tree-${Form.Dock}` - link: {} -} - -// a placeholder unparsed yet. -export type TreeFoldList = TreeBase & { - link: {} -} - -export type TreeForm = TreeBase & { - form: `tree-${Form.Form}` - link: { - head: TreeList - hide?: TreeWave - hook: TreeList - link: TreeList - name?: TreeLine - task: TreeList - wear: TreeList - } -} - -export type TreeFormHead = TreeBase & { - form: `tree-${Form.FormHead}` - link: { - base?: TreeLike - name?: TreeLine - } -} - -export type TreeFuse = TreeBase & { - form: `tree-${Form.Fuse}` - link: { - bind: TreeList - name?: TreeLine - } -} - -export type TreeHash = { - bear: TreeBear - bind: TreeBind - call: TreeCall - cite: TreeLike - 'code-card': TreeCodeCard - comb: TreeComb - deck: TreeDeck - 'deck-card': TreeDeckCard - 'deck-face': TreeDeckFace - 'deck-link': TreeDeckLink - 'deck-lock': TreeDeckLock - dock: TreeDock - form: TreeForm - 'form-head': TreeFormHead - fuse: TreeFuse - 'hide-bear': TreeHideBear - hold: TreeHold - hook: TreeHook - host: TreeHost - line: TreeLine - link: TreeLink - load: TreeLoad - 'load-find': TreeLoadFind - 'load-find-take': TreeLoadFindTake - 'side-size': TreeSideSize - size: TreeSize - suit: TreeSuit - take: TreeTake - task: TreeTask - test: TreeTest - text: TreeText - tree: TreeTree - wave: TreeWave -} - -export type TreeHideBear = TreeBase & { - form: `tree-${Form.HideBear}` - link: { - hostName?: TreeLine - name?: TreeLine - } -} - -// assertion -export type TreeHold = TreeBase & { - form: `tree-${Form.Hold}` - link: {} -} - -export type TreeHook = TreeBase & { - form: `tree-${Form.Hook}` - link: { - call: TreeList - name?: TreeLine - take: TreeList - task: TreeList - } -} - -export type TreeHost = TreeBase & { - form: `tree-${Form.Host}` - link: { - bond?: TreeBond | TreeList - hide?: TreeWave - name?: TreeLine - } -} - -export type TreeLike = TreeBase & { - form: `tree-${Form.Cite}` - link: { - bind: TreeList - name?: TreeLine - } -} - -export type TreeLine = TreeBase & { - form: `tree-${Form.Line}` - link: { - // bond: LinkPathType - } -} - -export type TreeLineForm = TreeLine | TreeLine - -export type TreeLink = TreeBase & { - form: `tree-${Form.Link}` - link: { - bond: TreeWave - // dereference - cite: TreeWave - // mutable - flex: TreeWave - // owner - have: TreeWave - line: TreeLineForm - // reference - time?: string - } -} - -export type TreeList
= { - bond: Array - form: `tree-${Form.List}` - headSize: number - leadSize: number -} - -export type TreeLoad = TreeBase & { - form: `tree-${Form.Load}` - link: { - find: TreeList - link?: TreeText - } -} - -export type TreeLoadFind = TreeBase & { - form: `tree-${Form.LoadFind}` - link: { - forkName?: TreeLine - name?: TreeLine - take?: TreeLoadFindTake - } -} - -export type TreeLoadFindTake = TreeBase & { - form: `tree-${Form.LoadFindTake}` - link: {} -} - -export enum TreeName { - Bear = 'riff-bear', - Bind = 'riff-bind', - Call = 'riff-call', - Cite = 'riff-cite', - CodeCard = 'riff-code-card', - Comb = 'riff-comb', - Deck = 'riff-deck', - DeckCard = 'riff-deck-card', - DeckFace = 'riff-deck-face', - DeckLock = 'riff-deck-lock', - Dock = 'riff-dock', - Form = 'riff-form', - FormHead = 'riff-form-head', - Fuse = 'riff-fuse', - HideBear = 'riff-hide-bear', - Hold = 'riff-hold', - Hook = 'riff-hook', - Host = 'riff-host', - Line = 'riff-line', - Link = 'riff-link', - Load = 'riff-load', - LoadFind = 'riff-load-find', - LoadFindTake = 'riff-load-find-take', - SideSize = 'riff-side-size', - Size = 'riff-size', - Suit = 'riff-suit', - Take = 'riff-take', - Task = 'riff-task', - Test = 'riff-test', - Text = 'riff-text', - TextLink = 'riff-text-link', - TextList = 'riff-text-list', - Tree = 'riff-tree', - Wave = 'riff-wave', - Wear = 'riff-wear', -} - -export enum TreeNote { - CollectionGathered = 'collection-gathered', - Initialized = 'initialized', - RuntimeComplete = 'runtime-complete', - StaticComplete = 'static-complete', -} - -export enum TreeRiseMark { - CollectionGathered = 'collection-gathered', - Initialized = 'initialized', - RuntimeComplete = 'runtime-complete', - StaticComplete = 'static-complete', -} - -export type TreeSideSize = TreeBase & { - form: `tree-${Form.SideSize}` - link: { - bond: number - } -} - -export type TreeSize = TreeBase & { - form: `tree-${Form.Size}` - link: { - bond: number - } -} - -export type TreeSuit = TreeBase & { - form: `tree-${Form.Suit}` - link: { - bind?: TreeList - head: TreeList - hide?: TreeWave - link: TreeList - name?: TreeLine - task: TreeList - } -} - -export type TreeTake = TreeBase & { - form: `tree-${Form.Take}` - link: { - name?: TreeText - } -} - -export type TreeTask = TreeBase & { - form: `tree-${Form.Task}` - link: { - base?: TreeTask - call: TreeList - head: TreeList - hide?: TreeWave - like?: TreeLike - name?: TreeLine - risk?: TreeWave - take: TreeList - task: TreeList - wait?: TreeWave - } -} - -export type TreeTest = TreeBase & { - form: `tree-${Form.Test}` - link: {} -} - -export type TreeText = TreeBase & { - form: `tree-${Form.Text}` - link: { - bond: string - } -} - -export type TreeTextLink = TreeBase & { - form: `tree-${Form.TextLink}` - link: { - // bond: LinkTextType - } -} - -export type TreeTree = TreeBase & { - form: `tree-${Form.Tree}` - link: { - hide?: TreeWave - hook: TreeList - name?: TreeLine - take: TreeList - } -} - -export type TreeWave = TreeBase & { - form: `tree-${Form.Wave}` - link: { - bond: boolean - } -} - -export type TreeWear = TreeBase & { - form: `tree-${Form.Wear}` - link: {} -} - -// eslint-disable-next-line sort-exports/sort-exports -export const SITE_OBSERVER_STATE = [ - TreeNote.Initialized, - TreeNote.StaticComplete, - TreeNote.RuntimeComplete, -] - -// eslint-disable-next-line sort-exports/sort-exports -export const SITE_OBSERVER_COMPLETE_STATE = [ - TreeNote.StaticComplete, - TreeNote.RuntimeComplete, -] diff --git a/hack/code/index.ts b/hack/code/index.ts deleted file mode 100644 index b8886e3..0000000 --- a/hack/code/index.ts +++ /dev/null @@ -1,22 +0,0 @@ -import { load_deckCard } from './mesh/deck/index.js' -import { - callTask, - findLink, - createBase, - setEnvironmentVariable, -} from './tool/index.js' - -export default async function build(host: string) { - const link = findLink(host) - assertString(link) - const base = createBase() - setEnvironmentVariable(base, 'dock', 'javascript') - setEnvironmentVariable(base, 'site', 'test') - load_deckCard(base, link) - while (base.tasks.length) { - callTask(base) - } - // exportNodeJS(base) -} - -export default class Code {} diff --git a/hack/code/load/index.ts b/hack/code/load/index.ts deleted file mode 100644 index d7472f5..0000000 --- a/hack/code/load/index.ts +++ /dev/null @@ -1,40 +0,0 @@ -import { minimatch } from 'minimatch' -import { Base } from '../form.js' -import tool from '../tool.js' - -export * from './deck/index.js' -export * from './mint/index.js' - -export function loadCard(base: Base, link: string): void { - if (tool.testHaveCard(base, link)) { - return - } - - const deck = card.loadDeckFile(link) - const mint = card.loadMintFile(deck) - - walk: for (const have of mint.mint) { - if (minimatch(link, have.link)) { - switch (have.name) { - case 'deck': - return card.load_deckCard(base, link) - case 'code': - return card.load_codeCard(base, link) - case 'mint': - return card.load_mintCard(base, link) - case 'call': // api urls - return card.load_callCard(base, link) - case 'line': // cli hooks - return card.load_lineCard(base, link) - case 'note': // a note type is a scratch type which isn't validated - return card.load_noteCard(base, link) - case 'book': - return card.load_bookCard(base, link) - default: - throw card.haltMissMintName() - } - } - } - - throw card.haltCardMiss() -} diff --git a/hack/code/load/mill/index.ts b/hack/code/load/mill/index.ts deleted file mode 100644 index b1c6ea4..0000000 --- a/hack/code/load/mill/index.ts +++ /dev/null @@ -1 +0,0 @@ -export default {} diff --git a/hack/code/load/mill/mine/index.ts b/hack/code/load/mill/mine/index.ts deleted file mode 100644 index e69de29..0000000 diff --git a/hack/code/load/mill/mint/mint.ts b/hack/code/load/mill/mint/mint.ts deleted file mode 100644 index e69de29..0000000 diff --git a/hack/code/look/bind/code.ts b/hack/code/look/bind/code.ts deleted file mode 100644 index 1eab236..0000000 --- a/hack/code/look/bind/code.ts +++ /dev/null @@ -1,5 +0,0 @@ -let CODE = 1 - -export default function make() { - return String(CODE++) -} diff --git a/hack/code/look/bind/hash.ts b/hack/code/look/bind/hash.ts deleted file mode 100644 index b22beb5..0000000 --- a/hack/code/look/bind/hash.ts +++ /dev/null @@ -1,12 +0,0 @@ -import Emitter from 'events' -import makeCode from './code' - -export default class BindHash extends Emitter { - code: string - - constructor() { - super() - - this.code = makeCode() - } -} diff --git a/hack/code/look/bind/index.ts b/hack/code/look/bind/index.ts deleted file mode 100644 index a96b740..0000000 --- a/hack/code/look/bind/index.ts +++ /dev/null @@ -1,6 +0,0 @@ -import BindHash from './hash.js' -import BindList from './list.js' -import BindSink from './sink.js' -import BindSite from './site.js' - -export type Bind = BindHash | BindList | BindSite | BindSink diff --git a/hack/code/look/bind/list.ts b/hack/code/look/bind/list.ts deleted file mode 100644 index 2e4d400..0000000 --- a/hack/code/look/bind/list.ts +++ /dev/null @@ -1,31 +0,0 @@ -/* eslint-disable @typescript-eslint/no-explicit-any */ -import Emitter from 'events' -import { Bind } from '.' -import makeCode from './code' - -export default class BindList extends Emitter { - dock: Array - - vibeSeal: boolean - - code: string - - constructor() { - super() - this.dock = [] - this.vibeSeal = false - this.code = makeCode() - } - - saveHead(bond: Bind) { - this.dock.push(bond) - this.emit('save', bond) - } - - seal() { - if (!this.vibeSeal) { - this.vibeSeal = true - this.emit('seal') - } - } -} diff --git a/hack/code/look/bind/sink.ts b/hack/code/look/bind/sink.ts deleted file mode 100644 index 916e119..0000000 --- a/hack/code/look/bind/sink.ts +++ /dev/null @@ -1,25 +0,0 @@ -import Emitter from 'events' -import makeCode from './code' - -export default class BindSink extends Emitter { - code: string - - bond: unknown - - constructor(bond: unknown) { - super() - - this.code = makeCode() - - this.save(bond) - } - - save(bond: unknown) { - this.bond = bond - this.emit('save') - } - - read() { - return this.bond - } -} diff --git a/hack/code/look/bind/site.ts b/hack/code/look/bind/site.ts deleted file mode 100644 index d61b5df..0000000 --- a/hack/code/look/bind/site.ts +++ /dev/null @@ -1,30 +0,0 @@ -/* eslint-disable @typescript-eslint/no-explicit-any */ -import Emitter from 'events' -import { Bind } from '.' -import makeCode from './code' - -export default class BindSite extends Emitter { - dock: Record - - code: string - - constructor() { - super() - - this.dock = {} - this.code = makeCode() - } - - save(name: string, bond: Bind) { - this.dock[name] = bond - this.emit('save', { bond, name }) - } - - read(name: string) { - return this.dock[name] - } - - have(name: string) { - return this.dock.hasOwnProperty(name) - } -} diff --git a/hack/code/look/fill.ts b/hack/code/look/fill.ts deleted file mode 100644 index a0f304e..0000000 --- a/hack/code/look/fill.ts +++ /dev/null @@ -1,336 +0,0 @@ -/* eslint-disable @typescript-eslint/no-explicit-any */ -import Emitter from 'events' -import { Bind } from './bind/index.js' -import BindList from './bind/list.js' -import BindSite from './bind/site.js' -import BindHash from './bind/hash.js' -import Look from './index.js' -import BindSink from './bind/sink.js' - -type SaveHook = { - bond: Bind - name: string -} - -type FillLoad = { - base?: Fill - look: Look - name: string -} - -export default class Fill extends Emitter { - // how many things we've bound - seekSize: number - - // how many things we've resolved - haveSize: number - - takeVibe: boolean - - fill: Record> - - takeFill: Record - - // parent - base?: Fill - - bindTest: Record - - sealVibe: boolean - - look: Look - - name: string - - sort?: string - - constructor({ look, base, name }: FillLoad) { - super() - this.name = name - this.look = look - this.base = base - this.fill = {} - this.seekSize = 0 - this.haveSize = 0 - this.takeVibe = false - this.takeFill = {} - this.bindTest = {} - this.sealVibe = false - this.seekRise() - } - - hold(bond: Bind) { - this.bind(bond) - this.load(bond) - } - - protected bind(bond: Bind) { - if (bond instanceof BindSite && !this.bindTest[bond.code]) { - this.bindSite(bond) - - return - } - - if (bond instanceof BindList && !this.bindTest[bond.code]) { - this.bindList(bond) - - return - } - - if (bond instanceof BindSink && !this.bindTest[bond.code]) { - this.bindSink(bond) - - return - } - - if (bond instanceof BindHash && !this.bindTest[bond.code]) { - this.bindHash(bond) - - return - } - } - - protected load(bond: Bind) { - if (bond instanceof BindSite) { - this.loadSite(bond) - } - - if (bond instanceof BindList) { - this.loadList(bond) - } - - if (bond instanceof BindSink) { - this.loadSink(bond) - } - } - - protected take() { - if (this.takeVibe) { - return - } - - // console.log('take') - // console.log(' ', this.readLink()) - // console.log(' ', 'have:', this.haveSize, 'seek:', this.seekSize) - if (this.haveSize === this.seekSize) { - this.takeVibe = true - this.emit('take') - } - } - - protected bindSite(bond: BindSite) { - this.bindTest[bond.code] = true - - this.sort = 'site' - - bond.on(`save`, ({ name, bond: nestBond }: SaveHook) => { - this.holdLink(bond.code, name, nestBond) - }) - - for (const name in this.look.link) { - this.bindSiteLink(name, bond) - } - - // for (const name in this.look.link) { - // if (bond.have(name)) { - // const link = bond.read(name) - // if (link != null) { - // this.holdLink(bond.code, name, link) - // } - // } - // } - } - - protected bindSiteLink(name: string, bond: BindSite) { - const look = this.look.link[name] - const fillHash = (this.fill[name] ??= {}) - - if (look) { - fillHash[bond.code] ??= new Fill({ - base: this, - look, - name, - }) - // this.seekRise() - } - } - - readLink() { - const link: Array = [] - // eslint-disable-next-line @typescript-eslint/no-this-alias - let seed: Fill | undefined = this - while (seed) { - link.push(seed.name) - seed = seed.base - } - return link.reverse().join('/') - } - - protected bindList(bond: BindList) { - this.seekRise() // for the seal on the list - - this.sort = 'list' - - this.bindTest[bond.code] = true - - bond.on(`save`, (bond: Bind) => { - this.hold(bond) - }) - - bond.on(`seal`, () => { - this.haveRise() - // this.haveRise() - }) - - bond.dock.forEach(bond => { - this.hold(bond) - }) - } - - protected bindSink(bond: BindSink) { - this.bindTest[bond.code] = true - - this.sort = 'sink' - - bond.on(`save`, () => { - this.haveRise() - }) - } - - protected bindHash(bond: BindHash) { - this.bindTest[bond.code] = true - - this.sort = 'hash' - - bond.on(`save`, () => { - this.haveRise() - }) - } - - protected loadSite(bond: BindSite) { - for (const name in this.fill) { - if (bond.have(name)) { - const link = bond.read(name) - if (link != null) { - this.loadLink(bond.code, name, link) - } - } - } - } - - testMeet() { - return this.haveSize === this.seekSize - 1 - } - - protected loadList(bond: BindList) { - if (bond.vibeSeal) { - this.haveRise() - } - bond.dock.forEach(bond => { - this.hold(bond) - }) - } - - protected loadSink(bond: BindSink) { - // console.log( - // 'load sink', - // this.readLink(), - // this.haveSize, - // this.seekSize, - // ) - this.haveRise() - } - - protected loadLink(code: string, name: string, bond: Bind) { - const look = this.look.link[name] - if (!look) { - return - } - - const fillHash = this.fill[name] - - if (!fillHash) { - return - } - - const fill = fillHash[code] - - if (!fill) { - return - } - - fill.hold(bond) - } - - protected holdLink(code: string, name: string, bond: Bind) { - const look = this.look.link[name] - if (!look) { - return - } - - const fillHash = this.fill[name] - - if (!fillHash) { - return - } - - const fill = fillHash[code] - - if (!fill) { - return - } - - fill.hold(bond) - } - - protected seekRise() { - this.seekSize++ - console.log( - 'seekRise ', - this.haveSize, - this.seekSize, - this.readLink(), - ) - // console.log('seekRise') - // console.log(' ', this.readLink()) - // console.log(' ', 'have:', this.haveSize, 'seek:', this.seekSize) - this.base?.seekRise() - } - - protected haveRise() { - // console.log( - // // new Error().stack, - // 'haveRise2', - // this.haveSize, - // this.seekSize, - // this.readLink(), - // this.takeVibe, - // ) - if (this.takeVibe) { - return - } - - this.haveSize++ - - console.log( - // new Error().stack, - 'haveRise', - this.haveSize, - this.seekSize, - this.readLink(), - ) - - this.take() - this.base?.haveRise() - - if (this.haveSize === this.seekSize - 1) { - this.haveRise() - return - } - - // if (this.sort === 'list' && this.haveSize === this.seekSize - 1) { - // console.log('ere') - // this.haveRise() - // } - } -} diff --git a/hack/code/look/index.ts b/hack/code/look/index.ts deleted file mode 100644 index 3d2764d..0000000 --- a/hack/code/look/index.ts +++ /dev/null @@ -1,22 +0,0 @@ -/* eslint-disable @typescript-eslint/no-explicit-any */ - -export default class Look { - link: Record - - testLeaf: boolean - - constructor() { - this.link = {} - this.testLeaf = false - } - - seek(name: string) { - const look = (this.link[name] ??= new Look()) - return look - } - - leaf() { - this.testLeaf = true - return this - } -} diff --git a/hack/code/look/readme.md b/hack/code/look/readme.md deleted file mode 100644 index aa94904..0000000 --- a/hack/code/look/readme.md +++ /dev/null @@ -1,113 +0,0 @@ -```ts -const card = new BindSite() -const fill = new FillCard() - -fill.bind(card) - -const fork = fill.fork() - -fork.waitList('form').wait('name') - -const fork2 = fill.fork() - -fork2.waitList('form').wait('name', 'user') -fork2.hook(() => { - console.log('resolved fork2') -}) - -const userForm = new BindSite({ - name: 'user', -}) - -const formList = new BindList([userForm]) - -card.save('form', formList) -``` - -At first you are working with the card fill. Then once it it is ready, -you take the built card out of it and use that. - -```ts -fork2.waitList('form').wait('name') -fork2.hook(() => { - console.log('resolved fork2') -}) -``` - -At first you don't know how large the list is going to be. The list has -potential items, and then it is called `take` on the bind. It's a -bounded list. Or call it `seal`, to close the list from any more -additions. - -```ts -fork2.wait('form').wait('name') -fork2.take(() => { - console.log('resolved fork2') -}) - -const formList = new BindList([userForm]) - -formList.seal() // say it's ready -``` - -```ts -fork.on('seal', () => { - // do whatever you need to to build the AST further. -}) -``` - -When the objects are ready, then you call `seal` on them to freeze them -from being changed. - -So if you call `.seal()` on a list before all items have been sealed, -then it will wait for all items to be sealed. - -```ts -saveHead // push - -function seal() { - if (this.seedSealSize === this.length) { - this.emit('seal') - } else { - this.vibeSeal = true - } -} -``` - -Or perhaps you don't need that. - -So we have Bind and Fill. The fill is just a tree of watchers, which -watches the bind objects. The bind objects are what we set values on. - -If the bind object is a `BindList`, then we wait for the `seal` event -before saying it's ready. If the bind object is a `BindSite` (an -object), then we wait until we get the `save` event for each field. When -we get the save event, we increment the `takeSize`. Once that equals the -`bindSize`, then we trigger `take` on the `Fill`. Once we get `take` on -the `Fill`, we have all our properties ready to be evaluated. This could -mean adding another fill fork, since we can have interpolated -interpolated properties, etc.. - -We then have a FillBase, which monitors the whole set of packages, the -FillDeck, which monitors the cards, and Fill is the card. - -The BindHash is a hash table. It is what the base and deck use. - ---- - -```ts -const look = new Look() -look.seek('form').seek('name') - -const fill = new Fill(look) - -const hash = new BindSite() -fill.load(hash) - -const formList = new BindList() -const form = new BindSite() -const name = new BindSink('user') -form.save('name', name) -formList.saveHead(form) -hash.save('form', formList) -``` diff --git a/hack/code/look/test.ts b/hack/code/look/test.ts deleted file mode 100644 index f961cfe..0000000 --- a/hack/code/look/test.ts +++ /dev/null @@ -1,66 +0,0 @@ -import Look from './index.js' -import Fill from './fill.js' -import BindSite from './bind/site.js' -import BindList from './bind/list.js' -import BindSink from './bind/sink.js' - -const look = new Look() -const fill = new Fill({ look, name: 'start' }) - -fill.on('take', () => { - console.log('resolved') -}) - -const site = new BindSite() - -look.seek('a').seek('b').seek('c1') -look.seek('a').seek('b').seek('c2') -look.seek('a').seek('b').seek('d').seek('c3') -look.seek('a').seek('x').seek('y') - -fill.hold(site) - -const a = new BindSite() -const b = new BindList() -const b_a = new BindSite() -const b_a_c1 = new BindSink('b_a_c1') -const b_a_c2 = new BindSink('b_a_c2') -const b_a_c3 = new BindSink('b_a_c3') -const b_b = new BindSite() -const b_b_c1 = new BindSink('b_b_c1') -const b_b_c2 = new BindSink('b_b_c2') -const b_b_c3 = new BindSink('b_b_c3') -const b_c = new BindSite() -const b_c_c1 = new BindSink('b_c_c1') -const b_c_c2 = new BindSink('b_c_c2') -const b_c_c3 = new BindSink('b_c_c3') -const x = new BindSite() -const y = new BindSink('y') -const d = new BindList() -const d_a = new BindSite() -const d_a_c3 = new BindSink('d_a_c3') -b_a.save('c1', b_a_c1) -b_a.save('c2', b_a_c2) -// b_a.save('c3', b_a_c3) -b_b.save('c1', b_b_c1) -b_b.save('c2', b_b_c2) -// b_b.save('c3', b_b_c3) -b_c.save('c1', b_c_c1) -b_c.save('c2', b_c_c2) -// b_c.save('c3', b_c_c3) -b.saveHead(b_a) -// b.saveHead(b_b) -// b.saveHead(b_c) -x.save('y', y) -a.save('b', b) -a.save('x', x) -d_a.save('c3', d_a_c3) -d.saveHead(d_a) -d.seal() -b_a.save('d', d) - -site.save('a', a) - -b.seal() - -console.log('done') diff --git a/hack/code/make/index.ts b/hack/code/make/index.ts deleted file mode 100644 index 715d817..0000000 --- a/hack/code/make/index.ts +++ /dev/null @@ -1 +0,0 @@ -// compile down to mesh form diff --git a/hack/code/readme.md b/hack/code/readme.md deleted file mode 100644 index eeeab9d..0000000 --- a/hack/code/readme.md +++ /dev/null @@ -1,456 +0,0 @@ -# Platform Integration - -- declarative data model queries -- declarative database schema formation -- declarative infrastructure provisioning -- declarative ui components -- declarative parsing -- declarative text generation -- declarative apis -- declarative clis -- declarative beats - -The only other portion is writing the actual imperative logic to -implement some actions. How much further can it be taken? - -## Inspiration - -- [fog](https://github.com/fog/fog) -- [terraform](https://github.com/hashicorp/terraform) -- [pundit](https://github.com/varvet/pundit) -- [atlas](https://github.com/ariga/atlas) - - https://github.com/ariga/atlas/blob/master/sql/mysql/diff.go#L36 - -## Vercel Integration - -Building on top of Vercel is one option. - -``` -hook /login, task login - bind edge, term true - -hook /logout, task logout - bind edge, term false -``` - -``` -# host/base.tree - -host platform, term vercel -host database, term postgres -``` - -``` -# host/hide.tree -# environment secrets - -host wikidata-client-key, 123123 -``` - -## Google Cloud Integration - -Building on top of Google Cloud is another option. - -``` -host platform, term google-cloud -host file-storage, term google-cloud-storage -``` - -- https://github.com/fog/fog-google/tree/master/lib/fog -- https://getbetterdevops.io/google-cloud-functions-with-terraform/ - -A `link` or `tell` is a variable which can be set from the outside. - -``` -link mesh - link storage-sizes, like mesh - bind usd5, <1xCPU-1GB> - bind usd10, <1xCPU-2GB> - note - -save mesh/plan, <20USD> -``` - -``` -seed server1, like upcloud-server - bind hostname, loan plan -``` - -It gets saved into a terraform "state" file. - -```json -{ - "version": 4, - "terraform_version": "1.2.3", - "serial": 1, - "lineage": "86545604-7463-4aa5-e9e8-a2a221de98d2", - "outputs": {}, - "resources": [ - { - "mode": "managed", - "type": "aws_instance", - "name": "example", - "provider": "provider[\"registry.terraform.io/...\"]", - "instances": [ - { - "schema_version": 1, - "attributes": { - "ami": "ami-0fb653ca2d3203ac1", - "availability_zone": "us-east-2b", - "id": "i-0bc4bbe5b84387543", - "instance_state": "running", - "instance_type": "t2.micro", - "(...)": "(truncated)" - } - } - ] - } - ] -} -``` - -- https://stackoverflow.com/questions/38486335/should-i-commit-tfstate-files-to-git -- https://github.com/mdb/terraform-example/blob/master/terraform/terraform.tfstate -- [Example Terraform State Files](https://gist.github.com/lancejpollard/1fbf133fdfd2bfcf96a29705ffd2e385) - -Saved locally to `bind.tree`. - -For sites, you have: - -``` -/back -/face -/hook -/line -/task -``` - -## Beats - -``` -beat x5-4 - tick x - tick o - tick o - tick x -``` - -## Errors - -``` -kink undefined-form - code 12 - take form - note - hint -``` - -```rs -fn does_things() -> Result { - let res1 = match can_fail() { - Ok(v) => v, - Err(e) => return Err(e) - }; - - let res2 = match can_fail() { - Ok(v) => v, - Err(e) => return Err(e) - }; - - return Ok(res1 + res2); -} - -fn does_things() -> Result { - let res1 = try!(canFail()) - let res2 = try!(canFail()) - return Ok(res1 + res2); -} -``` - -``` -task does-things - like result - like u32 - like io-error - - save res1, call can-fail - save ok1 - stem case - call read-form - loan res1 - case ok - loan res1/value - case kink - back res1 - - save ok, fuse try, call can-fail -``` - -``` -tree try - take result - - hook fuse - stem case - call read-form - loan result - case ok - loan result/value - case kink - back result -``` - -``` -bind.tree # Platform Bindings -bolt.tree # Standard Library -loom.tree # Compiler Framework / TypeChecking / etc. -fish.tree # Linting/Printing Framework (Language Server) - note - /code - /text - /:text - /rule - /:rule - /task -tree.tree # Content Grammars and Parsing - /code - /content - /pdf - /task -star.tree # Third-party library like with GitHub and Vercel -snow.tree # Modeling Framework / Querying -moon.tree # Resource Provisioning -crow.tree # UI Framework like React -nest.tree # Site Framework (last remaining folders) -seed.tree # Math Framework -wolf.tree # CLI/REPL Framework -base.tree # Package Framework -door.tree # Security/User/Rate Limiting Framework -``` - -Compiler needs to know about: - -- link folder for decks and dependencies -- make folder for compiling to target -- bind folder for configuration -- book folder for readme -- deck file for parsing decks -- flow folder for logs -- test folder for tests - -All that's left is the "code" part of the app. - -The dock (view) is part of the code file type, so that is known by the -compiler. - -The compiler would know about the framework?!! The compiler is the -framework basically. - -The compiler is aware of: - -- platform bindings -- standard library - -## Comments - -Comments can be in many ways as `mark`. - - host note-name - text markdown, < - Shortens the vector, keeping the first `len` elements and dropping - the rest. - - If `len` is greater than the vector's current length, this has no - effect. - - The [`drain`] method can emulate `truncate`, but causes the excess - elements to be returned instead of dropped. - - Note that this method has no effect on the allocated capacity - of the vector. - - # Examples - - Truncating a five element vector to two elements: - - ``` - let mut vec = vec![1, 2, 3, 4, 5]; - vec.truncate(2); - assert_eq!(vec, [1, 2]); - ``` - - No truncation occurs when `len` is greater than the vector's current - length: - - ``` - let mut vec = vec![1, 2, 3]; - vec.truncate(8); - assert_eq!(vec, [1, 2, 3]); - ``` - - Truncating when `len == 0` is equivalent to calling the [`clear`] - method. - - ``` - let mut vec = vec![1, 2, 3]; - vec.truncate(0); - assert_eq!(vec, []); - ``` - > - -Can do inline `text` format. - - mark - head 2, - text - like md - -Or even: - - mark md - - -Can mark/flag tasks and such that are: - -- deprecated: `mark toss` -- experimental: `mark test` - -Can have a `read/hint` folder with all the abstracted notes on the tasks -and forms and such. - - load ./foo - find task create-something - find task do-another - - task create-something - note - task do-another - note - -Similar to how you isolate tests from source code. - -Or, import the notes into your source code. - - host create-something - text - - # then in the file - load ./read/task/stuff - find note create-something - - task create-something - note create-something - ---- - - call {{name}} - - form: 'call', - name: LinkKnit | MeshLink (path) | MeshTerm - - {{call}} name - -The non-leaf nodes need to be resolved by compile time. - -As these non-leaf nodes are being interpolated, they spawn tasks to -resolve them when they are complete, and add them to the data model. - - mesh.tree => links to link tree - -Wait on it to resolve. Watches a module for a specific path. If the path -is an array, then it waits until the `done` trigger on the array -children, so it knows it has received all the array elements. - - card.bindingSet() - .waitFor('a') - .waitFor('b') - .waitFor('someArray/*/link/*') - .waitForArray('someArray') - .waitFor('link/name') - .then(() => { - handle() - removeFromBaseById() - }) - card.set('a', 'foo') - card.set('someArray', [{ link: { name: 'bar' } }]) - card.finish('someArray') - -All objects in the AST need to be bindable / emit events. - - // BindingEnvironment - class FillBase { - - } - - class FillDeck { - - } - - class FillFile { - - } - - class FillHook { - - } - - class FillList { - - } - - class FillSite { - - } - -@termsurf/fill-mesh.js - -A Bindable Fulfillment Library for Compiler AST Generation - -So then in mesh.tree, it will create a new -FillModule.hook().bind('foo/bar').bindList('form') - -Then it will notify everything that gets attached in the future if it is -complete. - -- if bindings already exist, and we set something and it fulfills the - binding, then trigger. -- if bindings don't exist until after it's been fulfilled, then trigger - immediately - -Then in mesh.tree - - // base.ts - class Base { - fill: FillBase - card: Record - task: Array - // env vars - host: Record - } - -base.fill.save('link', cardFill) - -- marked as completely bound (bindHook: true) - - all wired up with required watchers -- list items are is completely added (bindSeed: true) -- mark as completely resolved (bindTake: true) - - watchers are all resolved - -So they have basically a shell. - -So they have basically a shell. The shell is what we are watching for, -and it is filled with Bind objects. So we have the Fill tree and the -Bind tree. - - card.save('deep', deeplyNestedObject) - - fillCard.bind(card) // card is a site - - fillCard.wait('deep').wait('foo') - - deeplyNestedObject.save('foo', 'bar') - -When you save the deeply nested object, it triggers the fill card which -is bound to it, and it marks it off. diff --git a/hack/code/tool.ts b/hack/code/tool.ts deleted file mode 100644 index 8e4c957..0000000 --- a/hack/code/tool.ts +++ /dev/null @@ -1,3 +0,0 @@ -import * as tool from './tool/index.js' - -export default tool diff --git a/hack/code/tool/dependency.ts b/hack/code/tool/dependency.ts deleted file mode 100644 index fd7645e..0000000 --- a/hack/code/tool/dependency.ts +++ /dev/null @@ -1,307 +0,0 @@ -import { MeshLoad } from '../form' - -export function addDependencyTreeObserver( - load: MeshLoad, - list: Array, -): void { - // list.forEach() -} - -export function canResolveDependencyTree( - load: MeshLoad, - list: Array, -): boolean { - if (list.length === 0) { - return true - } - - const stack = list.concat() - - while (stack.length) { - const observer = stack.shift() - code.assertRecord(observer) - - // we made it back to the base - if (!observer.parent) { - return true - } - - const name = observer.path[0] - code.assertString(name) - - if (code.hasEnvironmentVariable(load.environment, name)) { - if (observer.parent) { - observer.parent.remaining-- - if (observer.parent.remaining === 0) { - stack - } - } - } - } - - return false -} - -export function connectDependency( - parent: SiteDependencyObserverType, - binding: SiteDependencyObserverParentType, - child: SiteDependencyObserverType, -): void { - child.parent = binding - binding.remaining++ - parent.children.push(child) -} - -export function getLeafDependencyList( - tree: SiteDependencyObserverType, - array: Array = [], -): Array { - tree.children.forEach(child => { - if (typeof child === 'object') { - if (!child.children.length) { - array.push(child) - } else { - getLeafDependencyList(child, array) - } - } - }) - return array -} - -export function resolveDynamicPathDependencyTree( - load: MeshLoad, -): SiteDependencyObserverType { - const path = code.assumeLink(load, Link.Path) - - const observer = { - children: [], - node: path, - path: [], - } - - const binding = { - observer, - remaining: 0, - } - - path.segment.forEach((seg, i) => { - if (seg.type === Link.Index) { - code.throwError(code.generateCompilerTodoError()) - } else { - code.connectDependency( - observer, - binding, - resolveTermDependencyTree(code.withLink(load, seg, i)), - ) - } - }) - - return observer -} - -export function resolveDynamicTermDependencyTree( - load: MeshLoad, -): SiteDependencyObserverType { - const term = code.assumeLink(load, Link.Term) - - const observer: SiteDependencyObserverType = { - children: [], - node: term, - path: [], - } - - const binding = { - observer, - remaining: 0, - } - - term.segment.forEach((seg, i) => { - if (seg.type === Link.String) { - observer.children.push(seg.value) - } else { - code.connectDependency( - observer, - binding, - code.resolvePluginDependencyTree(code.withLink(load, seg, i)), - ) - } - }) - - return observer -} - -export function resolvePathDependencyTree( - load: MeshLoad, -): SiteDependencyObserverType { - const type = code.getLinkHint(load) - - switch (type) { - case LinkHint.StaticPath: { - return code.resolveStaticPathDependencyTree(load) - } - case LinkHint.DynamicPath: { - return code.resolveDynamicPathDependencyTree(load) - } - default: - code.throwError(code.generateInvalidCompilerStateError()) - throw new CompilerError() - } -} - -export function resolvePluginDependencyTree( - load: MeshLoad, -): SiteDependencyObserverType { - const nest = load.link.element - - const observer = { - children: [], - node: nest, - path: [], - } - - const binding = { - observer, - remaining: 0, - } - - switch (nest.type) { - case Link.Term: { - code.connectDependency( - observer, - binding, - code.resolveTermDependencyTree(load), - ) - break - } - case Link.Path: { - code.connectDependency( - observer, - binding, - code.resolvePathDependencyTree(load), - ) - break - } - case Link.Tree: { - code.throwError(code.generateCompilerTodoError()) - break - } - default: - code.throwError(code.generateInvalidCompilerStateError()) - } - - return observer -} - -export function resolveStaticPathDependencyTree( - load: MeshLoad, -): SiteDependencyObserverType { - const path = code.assumeLink(load, Link.Path) - - const observer = { - children: [], - node: path, - path: [], - } - - const binding = { - observer, - remaining: 0, - } - - path.segment.forEach((seg, i) => { - if (seg.type === Link.Index) { - code.throwError(code.generateCompilerTodoError()) - } else { - code.connectDependency( - observer, - binding, - resolveTermDependencyTree(code.withLink(load, seg, i)), - ) - } - }) - - return observer -} - -export function resolveStaticTermDependencyTree( - load: MeshLoad, -): SiteDependencyObserverType { - const term = code.assumeLink(load, Link.Term) - const string: Array = [] - - const observer: SiteDependencyObserverType = { - children: [], - node: term, - path: [], - } - - term.segment.forEach((seg, i) => { - if (seg.type === Link.String) { - string.push(seg.value) - } else { - code.throwError(code.generateInvalidCompilerStateError()) - } - }) - - observer.path.push(string.join('')) - - return observer -} - -export function resolveTermDependencyTree( - load: MeshLoad, -): SiteDependencyObserverType { - const type = code.getLinkHint(load) - - switch (type) { - case LinkHint.StaticTerm: { - return code.resolveStaticTermDependencyTree(load) - } - case LinkHint.DynamicTerm: { - return code.resolveDynamicTermDependencyTree(load) - } - default: - code.throwError(code.generateInvalidCompilerStateError()) - throw new CompilerError() - } -} - -export function resolveTextDependencyTree( - load: MeshLoad, -): SiteDependencyObserverType { - const nest = code.assumeLink(load, Link.Text) - - const observer: SiteDependencyObserverType = { - children: [], - node: nest, - path: [], - } - - const binding = { - observer, - remaining: 0, - } - - nest.segment.forEach(seg => { - switch (seg.type) { - case Link.String: - observer.children.push(seg.value) - break - case Link.Plugin: - const childNest = seg.nest[0] - code.assertGenericLink(childNest) - code.connectDependency( - observer, - binding, - code.resolvePluginDependencyTree( - code.withLink(load, childNest, 0), - ), - ) - break - default: - code.throwError(code.generateInvalidCompilerStateError()) - } - }) - - return observer -} diff --git a/hack/code/tool/environment.ts b/hack/code/tool/environment.ts deleted file mode 100644 index e59048d..0000000 --- a/hack/code/tool/environment.ts +++ /dev/null @@ -1,119 +0,0 @@ -import type { SiteEnvironmentType } from '~' -import { Base } from '../form/base.js' - -export function assertEnvironment( - object: unknown, -): asserts object is SiteEnvironmentType { - if (!code.isEnvironment(object)) { - code.throwError( - code.generateObjectNotTypeError(object, ['environment']), - ) - } -} - -export function createBase(): Base { - return new Base() -} - -export function createEnvironment( - bindings: Record, - parent?: SiteEnvironmentType, -): SiteEnvironmentType { - return { - bindings, - isEnv: true, - parent, - } -} - -export function getEnvironmentProperty( - environment: SiteEnvironmentType, - name: string | number | symbol, -): unknown { - let source: SiteEnvironmentType = environment - - while (source) { - if (name in source.bindings) { - return ( - source.bindings as Record - )[name] - } else if (source.parent) { - source = source.parent - } else { - return - } - } -} - -export function getEnvironmentVariable( - base: Base, - key: string, -): unknown { - return base.env[key] -} - -export function hasEnvironmentVariable( - environment: SiteEnvironmentType, - name: string | number | symbol, -): boolean { - let source: SiteEnvironmentType = environment - - while (source) { - if (name in source.bindings) { - return true - } else if (source.parent) { - source = source.parent - } else { - return false - } - } - - return false -} -export function isEnvironment( - object: unknown, -): object is SiteEnvironmentType { - return (object as SiteEnvironmentType).isEnv === true -} - -export function setCachedFile( - base: Base, - path: string, - content: string, -): void { - base.textMap[path] = content -} - -export function setEnvironmentProperty( - scope: SiteEnvironmentType, - property: string, - value: unknown, -): void { - if (property in scope.bindings) { - scope.bindings[property] = value - } else if (scope.parent) { - code.setEnvironmentProperty(scope.parent, property, value) - } else { - code.throwError( - code.generateEnvironmentMissingPropertyError(property), - ) - } -} - -export function setEnvironmentVariable( - base: Base, - key: string, - value: unknown, -): void { - base.env[key] = value -} - -export function withEnvironment( - load: MeshLoad, - bindings: Record, -): SiteProcessInputType { - return { - ...load, - environment: code.createEnvironment(bindings, load.environment), - } -} diff --git a/hack/code/tool/file.ts b/hack/code/tool/file.ts deleted file mode 100644 index 0c1aa15..0000000 --- a/hack/code/tool/file.ts +++ /dev/null @@ -1,66 +0,0 @@ -import fs from 'fs' -import glob from 'glob' -import pathResolver from 'path' -import smc from 'source-map' -import { fileURLToPath } from 'url' - -export const SOURCE_MAP_MESH: Record = {} - -const __filename = fileURLToPath(import.meta.url) - -export const __dirname = pathResolver.dirname(__filename) - -export async function findFilePathsRecursively( - pattern: string, -): Promise> { - return glob.sync(pattern) -} - -export function loadLink(load: MeshLoad, loadPath: string): string { - const card = load.module - const path = code.findPath(loadPath, card.directory) - if (!path) { - code.throwError(code.generateUnresolvedPathError(load, loadPath)) - } - code.assertString(path, 'path') - return path -} - -export function readLinkHost(link: string): string { - return pathResolver.dirname(link) -} - -export function readTextFile(base: Base, link: string): string { - return base.textMap[link] ?? fs.readFileSync(link, 'utf-8') -} - -export function resolveDirectoryPath(path: string): string { - return pathResolver.dirname(path) -} - -export function resolveModulePath( - load: MeshLoad, - text: string, -): string { - const { module } = load - const path = code.findPath(text, module.directory) - - if (!path) { - code.throwError(code.generateUnresolvedPathError(load, text)) - } - - code.assertString(path) - - return path -} - -export function resolveNativePath( - path: string, - context: string, -): string { - const relative = pathResolver.relative( - process.cwd(), - pathResolver.resolve(context, path), - ) - return relative.startsWith('.') ? relative : `./${relative}` -} diff --git a/hack/code/tool/halt.ts b/hack/code/tool/halt.ts deleted file mode 100644 index 42803ff..0000000 --- a/hack/code/tool/halt.ts +++ /dev/null @@ -1,1052 +0,0 @@ -import chalk from 'chalk' -import { diffChars } from 'diff' - -import { - ERROR, - LINK_HINT_TEXT, - Link, - LinkHint, - LinkNodeType, - SOURCE_MAP_MESH, - Text, - code, - prettifyJSON, -} from '~' -import type { - FoldStateInputType, - SiteProcessInputType, - TextSplitInputType, - TextTokenType, -} from '~' - -export class BaseNoteError extends Error { - data: SiteErrorType - - constructor(message: string, data: SiteErrorType) { - super(message) - - this.data = data - } -} - -export class CompilerError extends Error {} - -export type CursorLinePositionType = { - character: number - line: number -} - -export type CursorRangeType = { - end: CursorLinePositionType - start: CursorLinePositionType -} - -export enum ErrorTerm { - CompilationError = 'compilation-error', - CompilerError = 'compiler-error', - SyntaxError = 'syntax-error', - SystemError = 'system-error', -} - -export type SiteErrorConfigType = { - code: string - hint?: string - note: (props: Record) => string - text?: string -} - -const consumers = {} - -export type SiteErrorInputType = Record - -export type SiteErrorType = { - code: string - file?: string - hint?: string - note: string - term?: Array - text?: string -} - -export type SiteStackTraceType = { - character?: number - file: string - function?: string - line?: number -} - -export class TypescriptError extends Error {} - -export function assertError( - error: unknown, -): asserts error is SiteErrorConfigType { - if (!code.isError(error)) { - throw new Error('Error handler undefined') - } -} - -export function buildErrorMessage(data: SiteErrorType): Array { - const text: Array = [] - - text.push(``) - text.push( - chalk.gray(` note <`) + - chalk.whiteBright(`${data.note}`) + - chalk.gray('>'), - ) - - if (data.hint) { - text.push( - chalk.gray(` hint <`) + - chalk.whiteBright(`${data.hint}`) + - chalk.gray('>'), - ) - } - - data.term?.forEach(term => { - text.push(chalk.gray(` term `) + chalk.white(`${term}`)) - }) - - text.push(chalk.gray(` code `) + chalk.white(`#${data.code}`)) - - if (data.file) { - if (data.text) { - text.push( - chalk.gray(` file <`) + - chalk.whiteBright(`${data.file}`) + - chalk.gray(`>, <`), - ) - data.text.split('\n').forEach(line => { - text.push(` ${line}`) - }) - text.push(chalk.gray(` >`)) - } else { - text.push( - chalk.gray(` file <`) + - chalk.whiteBright(`${data.file}`) + - chalk.gray(`>`), - ) - } - } else if (data.text) { - text.push(chalk.gray(` text <`)) - data.text.split('\n').forEach(line => { - text.push(` ${line}`) - }) - text.push(chalk.gray(' >')) - } - - return text -} - -export function createDefaultRange(): CursorRangeType { - return { - end: { - character: 0, - line: 0, - }, - start: { - character: 0, - line: 0, - }, - } -} - -export function generateChangeVariableTypeError( - load: MeshLoad, -): SiteErrorType { - return { - code: '0031', - note: `Attempt to change a variable's type.`, - } -} - -export function generateCompilerTodoError( - hint?: string, -): SiteErrorType { - return { - code: `0029`, - hint: [ - `This part of the compiler is unfinished, see the stack trace for where to modify code.`, - hint, - ] - .filter(x => x) - .join(' '), - note: `Compiler TODO`, - term: [ErrorTerm.CompilerError], - } -} - -export function generateEnvironmentMissingPropertyError( - property: string, -): SiteErrorType { - return { - code: '0019', - note: `Environment is missing property ${property}.`, - } -} - -export function generateForkMissingPropertyError( - property: string, -): SiteErrorType { - return { - code: `0010`, - note: `Scope is missing property '${property}'.`, - } -} - -export function generateHighlightedError( - textByLine: Array, - highlight: CursorRangeType, -): string { - const endLine = Math.min( - highlight.start.line + 2, - textByLine.length - 1, - ) - const endLineString = textByLine[endLine] - code.assertString(endLineString) - const endCharacter = endLineString.length - 1 - const boundedRange: CursorRangeType = { - end: { - character: endCharacter, - line: endLine, - }, - start: { - character: 0, - line: Math.max(0, highlight.start.line - 2), - }, - } - - const text = highlightTextRangeForError( - boundedRange, - textByLine, - highlight, - ) - - return text -} - -export function generateHighlightedErrorForLinkTree( - load: MeshLoad, -): string { - const highlightedRange = code.getCursorRangeForTree(load) - return code.generateHighlightedError( - load.module.textByLine, - highlightedRange, - ) -} - -export function generateHighlightedErrorForText( - load: MeshLoad, -): string { - const highlightedRange = code.getCursorRangeForText(load) - return code.generateHighlightedError( - load.module.textByLine, - highlightedRange, - ) -} - -export function generateIncorrectlyTypedVariable( - type: string | Array, - name?: string, - path?: string, -): SiteErrorType { - type = Array.isArray(type) ? type : [type] - const words = - type.length > 1 - ? type - .slice(-1) - .map(x => `\`${x}\``) - .join(', ') + ` or \`${type[type.length - 1]}\`` - : `\`${type[0]}\`` - const text = name ? ` \`${name}\`` : '' - return { - code: `0027`, - file: path, - note: `Variable${text} is not typed as a ${words}.`, - } -} - -export function generateInvalidCompilerStateError( - hint?: string, - path?: string, -): SiteErrorType { - return { - code: `0028`, - file: path, - hint: [ - hint, - `This is some bug with the budding compiler. Check the stack trace to see where the error occurred.`, - ] - .filter(x => x) - .join(' '), - note: `Invalid compiler state`, - } -} - -export function generateInvalidDeckLink( - load: MeshLoad, - link: string, -): SiteErrorType { - return { - code: `0008`, - note: `Invalid deck link '${link}'.`, - } -} - -export function generateInvalidNestCaseError( - load: MeshLoad, - type: LinkHint, -): SiteErrorType { - let scope - try { - scope = code.resolveTermString(load) - } catch (e) {} - const text = code.generateHighlightedErrorForLinkTree(load) - return { - code: `0032`, - file: `${load.module.path}`, - note: `The "${LINK_HINT_TEXT[type]}" elements are invalid in this context.`, - text, - } -} - -export function generateInvalidNestChildrenLengthError( - load: MeshLoad, - length: number, -): SiteErrorType { - return { - code: `0009`, - note: `Term doesn't have ${length} children.`, - } -} - -// export function generateInvalidPatternError( -// load: MeshLoad, -// pattern: unknown, -// ): SiteErrorType { -// const { module } = load -// const nest = code.assumeLink(load) -// const text = code.generateHighlightedErrorForText(load) -// return { -// code: `0012`, -// file: `${module.path}`, -// note: `Text does not match pattern ${pattern}.`, -// text: text, -// } -// } - -export function generateInvalidWhitespaceError( - load: FoldStateInputType, -): SiteErrorType { - const token = load.tokenList[load.state.index] - code.assertTextGenericType(token) - const highlightedRange = code.getCursorRangeForTextWhitespaceToken( - token, - load, - ) - const text = code.generateHighlightedError( - load.textByLine, - highlightedRange, - ) - - return { - code: '0027', - file: load.path, - note: `Invalid whitespace`, - text, - } -} - -export function generateModuleUnresolvableError( - load: MeshLoad, -): SiteErrorType { - return { - code: '0020', - file: `${load.module.path}`, - note: `Module has unresolvable references`, - } -} - -export function generateObjectNotTypeError( - object: unknown, - type: Array, -): SiteErrorType { - const words = - type.length > 1 - ? type - .slice(-1) - .map(x => `\`${x}\``) - .join(', ') + ` or \`${type[-1]}\`` - : `\`${type[0]}\`` - return { - code: `0007`, - note: `Object isn't type ${words}.`, - text: object == null ? String(object) : prettifyJSON(object), - } -} - -export function generateStringMismatchError( - load: TextSplitInputType, - a: string, - b: string, -): SiteErrorType { - return { - code: '0030', - file: load.path, - note: 'String mismatch error', - text: code.renderDiffText(a, b), - } -} - -export function generateSyntaxTokenError( - load: TextSplitInputType, - lastToken?: TextTokenType, -): SiteErrorType { - const highlight: CursorRangeType = { - end: { - character: 0, - line: 0, - }, - start: { - character: 0, - line: 0, - }, - } - - if (lastToken) { - highlight.start.line = lastToken.range.line.start - highlight.end.line = lastToken.range.line.end - highlight.start.character = lastToken.range.character.start - highlight.end.character = lastToken.range.character.end - } - - const text = code.generateHighlightedError(load.textByLine, highlight) - - return { - code: `0021`, - note: `Error in the structure of the text tree.`, - text, - } -} - -export function generateTermMissingChildError(): void {} - -export function generateTermMissingError( - load: MeshLoad, - type: string, - object: string, -): SiteErrorType { - const { module } = load - return { - code: `0018`, - file: `${module.path}`, - note: `Term ${type} is missing on ${object}.`, - text: '', - } -} - -export function generateUnhandledNestCaseBaseError( - load: MeshLoad, -): SiteErrorType { - const { module } = load - const text = code.generateHighlightedErrorForLinkTree(load) - return { - code: `0005`, - file: `${module.path}`, - note: `We haven't implemented handling this type of nest yet.`, - text, - } -} - -export function generateUnhandledNestCaseError( - load: MeshLoad, - type: LinkHint, -): SiteErrorType { - let scope - try { - // scope = code.resolveTermString(load, 1) - scope = code.resolveTermString(load) - } catch (e) {} - const text = code.generateHighlightedErrorForLinkTree(load) - return { - code: `0004`, - file: `${load.module.path}`, - note: `We haven't implemented handling "${ - LINK_HINT_TEXT[type] - }s" yet${scope ? ` on \`${scope}\`` : ''}.`, - text, - } -} - -export function generateUnhandledTermCaseError( - load: MeshLoad, -): SiteErrorType { - let scope - try { - // scope = code.resolveTermString(load, 1) - scope = code.resolveTermString(load) - } catch (e) {} - const name = code.resolveTermString(load) - code.assertString(name) - const handle = ERROR['0002'] - code.assertError(handle) - const text = code.generateHighlightedErrorForLinkTree(load) - return { - code: `0002`, - file: `${load.module.path}`, - note: handle.note({ name, scope }), - term: [ErrorTerm.CompilerError], - text, - } -} - -export function generateUnhandledTermInterpolationError( - load: MeshLoad, -): SiteErrorType { - return { - code: `0001`, - file: `${load.module.path}`, - note: `We haven't implemented handling term interpolation yet.`, - text: '', - } -} - -export function generateUnknownTermError( - load: MeshLoad, -): SiteErrorType { - const { module } = load - const name = code.resolveTermString(load) - const text = code.generateHighlightedErrorForLinkTree(load) - // const insideName = code.resolveTermString(load, 1) - const insideName = code.resolveTermString(load) - return { - code: `0003`, - file: `${module.path}`, - note: `Unknown term \`${name}\`${ - insideName ? ` inside \`${insideName}\`` : '' - }.`, - text: text, - } -} - -export function generateUnresolvedPathError( - load: MeshLoad, - path: string, -): SiteErrorType { - const { module } = load - return { - code: `0013`, - file: module.path, - note: `File not found ${path}.`, - } -} - -export function generatedNotImplementedYetError( - name?: string, - path?: string, -): SiteErrorType { - return { - code: '0024', - file: path, - note: `We have not yet implemented ${ - name ? `${name}` : 'something you referenced' - }.`, - term: [ErrorTerm.CompilerError], - } -} - -export function getCursorRangeForPath(load: MeshLoad): CursorRangeType { - const path = code.assumeLink(load, Link.Path) - const firstSegment = path.segment[0] as LinkNodeType - const lastSegment = path.segment[ - path.segment.length - 1 - ] as LinkNodeType - const start = getCursorRangeForTerm(code.withLink(load, firstSegment)) - const end = getCursorRangeForTerm(code.withLink(load, lastSegment)) - const range: CursorRangeType = { - end: { - character: end.end.character, - line: end.end.line, - }, - start: { - character: start.start.character, - line: start.start.line, - }, - } - return range -} - -export function getCursorRangeForPlugin( - load: MeshLoad, -): CursorRangeType { - const nest = code.assumeLink(load, Link.Plugin) - const child = nest.nest[0] - - switch (child?.type) { - case Link.Term: { - return code.getCursorRangeForTerm(code.withLink(load, nest)) - } - case Link.Path: { - return code.getCursorRangeForPath(code.withLink(load, nest)) - } - case Link.Tree: { - return code.getCursorRangeForTree(code.withLink(load, nest)) - } - default: - code.throwError(code.generateInvalidCompilerStateError()) - throw new CompilerError() - } -} - -export function getCursorRangeForString( - load: MeshLoad, -): CursorRangeType { - const string = code.assumeLink(load, Link.String) - - return { - end: { - character: string.range.character.end, - line: string.range.line.end, - }, - start: { - character: string.range.character.start, - line: string.range.line.start, - }, - } -} - -export function getCursorRangeForTerm(load: MeshLoad): CursorRangeType { - const term = code.assumeLink(load, Link.Term) - const range: CursorRangeType = createDefaultRange() - - const start = term.segment[0] - const end = term.segment[term.segment.length - 1] - - if (!start || start.type !== Link.String) { - return range - } - - if (!end || end.type !== Link.String) { - return range - } - - range.end.character = end.range.character.end - range.end.line = end.range.line.end - - range.start.character = start.range.character.start - range.start.line = start.range.line.start - - return range -} - -export function getCursorRangeForText(load: MeshLoad): CursorRangeType { - const nest = code.assumeLink(load, Link.Text) - - const range: CursorRangeType = { - end: { - character: 0, - line: 0, - }, - start: { - character: 0, - line: 0, - }, - } - - const first = nest.segment[0] - const last = nest.segment[nest.segment.length - 1] - - code.assertGenericLink(first) - code.assertGenericLink(last) - - let firstRange: CursorRangeType - - if (first.type === Link.String) { - firstRange = code.getCursorRangeForString( - code.withLink(load, first), - ) - } else if (first.type === Link.Plugin) { - firstRange = code.getCursorRangeForPlugin( - code.withLink(load, first), - ) - } else { - code.throwError(code.generateInvalidCompilerStateError()) - throw new CompilerError() - } - - if (firstRange) { - range.start.line = firstRange.start.line - range.start.character = firstRange.start.character - range.end.line = firstRange.end.line - range.end.character = firstRange.end.character - } - - let lastRange: CursorRangeType - - if (last.type === Link.String) { - lastRange = code.getCursorRangeForString(code.withLink(load, last)) - } else if (last.type === Link.Plugin) { - lastRange = code.getCursorRangeForPlugin(code.withLink(load, last)) - } else { - code.throwError(code.generateInvalidCompilerStateError()) - throw new CompilerError() - } - - if (lastRange) { - range.end.line = lastRange.end.line - range.end.character = lastRange.end.character - } - - return range -} - -export function getCursorRangeForTextWhitespaceToken( - token: TextTokenType, - load: FoldStateInputType, -): CursorRangeType { - let tokens: Array> = [] - let i = load.state.index - - loop: while (i < load.tokenList.length) { - let t = load.tokenList[i] - code.assertTextGenericType(t) - switch (t.type) { - case Text.OpenIndentation: - case Text.OpenNesting: - tokens.push(t) - break - default: - break loop - } - i++ - } - - const start = tokens[0] - const end = tokens[tokens.length - 1] - - code.assertTextGenericType(start) - code.assertTextGenericType(end) - - return { - end: { - character: end.range.character.end, - line: end.range.line.end, - }, - start: { - character: start.range.character.start, - line: start.range.line.start, - }, - } -} - -export function getCursorRangeForTree(load: MeshLoad): CursorRangeType { - // console.log(load) - const nest = load.link.element - - switch (nest.type) { - case Link.Tree: { - const term = nest.head - if (!term) { - code.throwError(code.generateInvalidCompilerStateError()) - throw new CompilerError() - } - - return getCursorRangeForTerm(code.withLink(load, term)) - } - case Link.Path: { - return getCursorRangeForPath(load) - } - case Link.Term: { - return getCursorRangeForTerm(load) - } - default: - code.throwError(code.generateInvalidCompilerStateError()) - throw new CompilerError() - } -} - -export function getSourceMappedFile( - path: string, - line: number, - character: number, -): [string, number | undefined, number | undefined] { - const map = SOURCE_MAP_MESH[path] - - const trace = { - column: character, - filename: path, - line: line, - } - - if (map) { - const token = map.originalPositionFor(trace) - if (token.source) { - return [ - code.resolveNativePath( - token.source, - code.resolveDirectoryPath(path.replace(/^file:\/\//, '')), - ), - token.line == null ? undefined : token.line, - token.column == null ? undefined : token.column, - ] - } else { - return [path, line, character] - } - } else { - return [path, line, character] - } -} - -export function highlightTextRangeForError( - bound: CursorRangeType, - textByLine: Array, - highlight: CursorRangeType, -): string { - const lines: Array = [] - let i = bound.start.line - let n = bound.end.line - let pad = String(n + 1).length - const defaultIndent = new Array(pad + 1).join(' ') - lines.push(chalk.white(`${defaultIndent} |`)) - while (i <= n) { - const lineText = textByLine[i] - const x = i + 1 - let z = - i < textByLine.length - ? x.toString().padStart(pad, ' ') - : defaultIndent - if (highlight.start.line === i) { - lines.push(chalk.whiteBright(`${z} | ${lineText}`)) - const indentA = new Array(z.length + 1).join(' ') - const indentB = new Array(highlight.start.character + 1).join(' ') - const squiggly = new Array( - highlight.end.character - highlight.start.character + 1, - ).join('~') - lines.push( - chalk.white(`${indentA} | ${indentB}`) + - chalk.red(`${squiggly}`), - ) - } else { - lines.push(chalk.white(`${z} | ${lineText}`)) - } - i++ - } - - lines.push(chalk.white(`${defaultIndent} |`)) - - return lines.join('\n') -} - -export function isError(error: unknown): error is SiteErrorConfigType { - return ( - code.isRecord(error) && Boolean((error as SiteErrorConfigType).code) - ) -} - -export function parseStackLine(text: string) { - const [a, b] = text.trim().split(/\s+/) - code.assertString(a) - if (!b) { - return parseStackLineFileOnly(a) - } else { - return { - ...parseStackLineFileOnly(b), - function: a, - } - } -} - -export function parseStackLineFileOnly( - text: string, -): SiteStackTraceType { - const parts = text.replace(/[\(\)]/g, '').split(':') - const character = parts.pop() - let characterN = character ? parseInt(character, 10) : undefined - const line = parts.pop() - let lineN = line ? parseInt(line, 10) : undefined - let file = parts.join(':') - if (code.isNumber(lineN) && code.isNumber(characterN)) { - ;[file, lineN, characterN] = getSourceMappedFile( - file, - lineN, - characterN, - ) - } - return { - character: characterN, - file, - line: lineN, - } -} - -export function parseTapStackTrace( - stack: string, -): Array { - return stack - .trim() - .split(/\n+/) - .map(line => { - const [a, b] = line.trim().split(/\s+/) - code.assertString(a) - if (!b) { - return parseStackLineFileOnly(a) - } else { - return { - ...parseStackLineFileOnly(b), - function: a, - } - } - }) -} - -export function renderDiffText(a: string, b: string): string { - const text: Array = [] - const diff = diffChars(a, b) - - diff.forEach(part => { - const value = part.value.replace(/ /g, '◌') - if (part.added) { - text.push(chalk.green(value)) - } else if (part.removed) { - text.push(chalk.red(value)) - } else { - text.push(chalk.gray(value)) - } - }) - - return text.join('') -} - -export function renderError(stackTrace: string): Array { - const messageLine: Array = [] - const stack: Array = [] - const parts = stackTrace.trim().split(/\n+/) - - let intoMessage = false - let i = parts.length - 1 - while (i >= 0) { - const line = parts[i--] - if (!intoMessage && line?.startsWith(' at ')) { - stack.push(code.parseStackLine(line.slice(' at '.length))) - } else if (line) { - intoMessage = true - messageLine.push(line) - } - } - - const errorText = code.buildErrorMessage({ - code: '0031', - note: messageLine.reverse().join('\n'), - term: [ErrorTerm.SystemError], - }) - - code.renderStackTrace(stack.reverse()).forEach(line => { - errorText.push(` ${line}`) - }) - - errorText.push('') - - return errorText -} - -export function renderStackTrace( - stack: Array, -): Array { - const g = chalk.gray - const w = chalk.white - const bw = chalk.whiteBright - const text: Array = [] - stack.forEach(node => { - let suffix = [] - if (node.line) { - suffix.push(node.line) - } - if (node.character) { - suffix.push(node.character) - } - - const end = suffix.length ? ':' + suffix.join(':') : '' - text.push( - `${g(`site ${g('<')}`)}${bw(`${node.file}${end}`)}${g('>')}`, - ) - if (node.function) { - text.push(`${g(` call ${g('<')}${w(node.function)}${g('>')}`)}`) - } - }) - return text -} - -export function throwError(data: SiteErrorType): void { - const text = code.buildErrorMessage(data) - text.push(``) - - // Error.stackTraceLimit = Infinity - - const prepareStackTrace = Error.prepareStackTrace - - Error.prepareStackTrace = function prepareStackTrace( - error: Error, - stack: Array, - ): string { - return ( - error.message + - chalk.gray(' list base\n') + - stack - .slice(1) - .map((site: NodeJS.CallSite) => { - let x = site.getFileName() - let a: number | null | undefined = site.getLineNumber() - let b: number | null | undefined = site.getColumnNumber() - - if ( - x && - code.isNumber(a) && - code.isNumber(b) && - code.isString(x) - ) { - ;[x, a, b] = getSourceMappedFile(x, a, b) - } - let m = site.getMethodName()?.trim() - let f = site.getFunctionName()?.trim() - let t = site.getTypeName()?.trim() - let label = m - ? [t, m].join('.') - : t - ? [t, f].join('.') - : f || '[anonymous]' - label = label ? label : '' - const lastLines: Array = [] - if (x) { - lastLines.push( - chalk.gray(' site <') + - chalk.whiteBright([x, a, b].filter(x => x).join(':')) + - chalk.gray('>'), - ) - } else { - lastLines.push(chalk.gray(' site ')) - } - - lastLines.push( - chalk.gray(' call <') + - chalk.white(label) + - chalk.gray('>'), - ) - - return lastLines.join('\n') - }) - .join('\n') + - '\n' - ) - } - - const error = new BaseNoteError(text.join('\n'), data) - error.name = '' - - Error.captureStackTrace(error) - - error.stack - - Error.prepareStackTrace = prepareStackTrace - - throw error -} diff --git a/hack/code/tool/index.ts b/hack/code/tool/index.ts deleted file mode 100644 index 6f25a84..0000000 --- a/hack/code/tool/index.ts +++ /dev/null @@ -1,9 +0,0 @@ -export * from './dependency.js' -export * from './environment.js' -export * from './file.js' -export * from './halt.js' -export * from './module.js' -export * from './nest.js' -export * from './observer.js' -export * from './task.js' -export * from './text.js' diff --git a/hack/code/tool/load/error-handler.ts b/hack/code/tool/load/error-handler.ts deleted file mode 100644 index 0dbaf0d..0000000 --- a/hack/code/tool/load/error-handler.ts +++ /dev/null @@ -1,25 +0,0 @@ -export function watchUnhandledErrors(): void { - process.on('unhandledRejection', (reason: unknown) => { - if (reason instanceof BaseNoteError) { - console.log(reason.stack) - } else if ( - reason instanceof Error && - 'stack' in reason && - code.isString(reason.stack) - ) { - const text = code.renderError(reason.stack) - console.log(text.join('\n')) - } else { - console.log(reason) - } - }) - - process.on('uncaughtException', (error: Error) => { - if (code.isString(error.stack)) { - const text = code.renderError(error.stack) - console.log(text.join('\n')) - } else { - console.log(error.message ?? error) - } - }) -} diff --git a/hack/code/tool/load/index.ts b/hack/code/tool/load/index.ts deleted file mode 100644 index f5e597c..0000000 --- a/hack/code/tool/load/index.ts +++ /dev/null @@ -1,5 +0,0 @@ -import { watchUnhandledErrors } from './error-handler.js' - -export * from './error-handler.js' - -watchUnhandledErrors() diff --git a/hack/code/tool/module.ts b/hack/code/tool/module.ts deleted file mode 100644 index 211fe35..0000000 --- a/hack/code/tool/module.ts +++ /dev/null @@ -1,38 +0,0 @@ -import { - Base, - BaseCard, - SiteModuleBaseType, - SiteModuleType, - SiteCardCode, - code, -} from '~' - -export function assertModule( - object: unknown, -): asserts object is SiteModuleType { - if (!code.isModule(object)) { - code.throwError(code.generateObjectNotTypeError(object, ['module'])) - } -} - -export function hasModuleInitialized(module: BaseCard): boolean { - return Object.keys(module.seed).length > 0 -} - -export function isModule(object: unknown): object is SiteModuleType { - return (object as SiteModuleType).isModule === true -} - -export function loadLinkModule(base: Base, path: string): SiteCardCode { - const text = code.readTextFile(base, path) - const data = code.parseLinkText({ path, text }) - const directory = code.getLinkHost(path) - return { - directory, - ...data, - } -} - -export function testHaveCard(base: Base, path: string): boolean { - return path in base.cardsByPath -} diff --git a/hack/code/tool/nest.ts b/hack/code/tool/nest.ts deleted file mode 100644 index 1550fab..0000000 --- a/hack/code/tool/nest.ts +++ /dev/null @@ -1,103 +0,0 @@ -import type { SiteProcessInputType } from '~' - -export function assumeLinkIndex(load: MeshLoad): number { - const index = load.link.index - code.assertNumber(index) - return index -} - -export function getLinkHint(load: MeshLoad): LinkHint { - if (code.nestIsTerm(load)) { - if (code.termIsInterpolated(load)) { - return LinkHint.DynamicTerm - } else { - return LinkHint.StaticTerm - } - } else if (code.nestIsPath(load)) { - if (code.pathIsInterpolated(load)) { - return LinkHint.DynamicPath - } else { - return LinkHint.StaticPath - } - } else if (code.nestIsText(load)) { - if (code.textIsInterpolated(load)) { - return LinkHint.DynamicText - } else { - return LinkHint.StaticText - } - } else if (code.nestIsUnsignedInteger(load)) { - return LinkHint.Mark - } else if (code.nestIsHashtag(load)) { - return LinkHint.Code - } else { - code.throwError(code.generateUnhandledNestCaseBaseError(load)) - } - - return LinkHint.Empty -} - -export function nestIsHashtag(load: MeshLoad): boolean { - const nest = load.link.element - - return nest.type === Link.Hashtag -} - -export function nestIsPath(load: MeshLoad): boolean { - const nest = load.link.element - - return nest.type === Link.Path -} - -export function nestIsTerm(load: MeshLoad): boolean { - const nest = load.link.element - - if (nest.type === Link.Term) { - return true - } - - if (nest.type !== Link.Tree) { - return false - } - - const child = nest.head - if (!child) { - return false - } - - if (child.type !== Link.Term) { - return false - } - - return true -} - -export function nestIsText(load: MeshLoad): boolean { - const nest = load.link.element - - return nest.type === Link.Text -} - -export function nestIsUnsignedInteger(load: MeshLoad): boolean { - const nest = load.link.element - - return nest.type === Link.UnsignedInteger -} - -export function pathIsInterpolated(load: MeshLoad): boolean { - const nest = load.link.element - - if (nest.type !== Link.Path) { - return false - } - - for (const seg of nest.segment) { - if (seg.type === Link.Index) { - return true - } - if (code.termIsInterpolatedImpl(seg)) { - return true - } - } - - return false -} diff --git a/hack/code/tool/observer.ts b/hack/code/tool/observer.ts deleted file mode 100644 index ff7f5bb..0000000 --- a/hack/code/tool/observer.ts +++ /dev/null @@ -1,470 +0,0 @@ -import { - BlueMapType, - BlueNodeType, - BluePossibleType, - BlueType, - Mesh, - SITE_OBSERVER_COMPLETE_STATE, - SITE_OBSERVER_STATE, - SiteModuleBindingInputType, - SiteObjectWatcherHandleType, - SiteObjectWatcherPropertiesType, - SiteObjectWatcherPropertyType, - SiteObjectWatcherSchemaPropertyType, - SiteObjectWatcherSchemaType, - SiteObjectWatcherType, - SiteObserverState, - code, -} from '~' -import type { SiteProcessInputType } from '~' - -export function bindSchema( - load: SiteModuleBindingInputType, - schema: SiteObjectWatcherSchemaType, -): void { - const watcher = code.registerSchema(load, schema) - code.updateAllThroughWatcher(load, watcher) -} - -export function createCodeModuleObjectNameObserverSchema( - property: string, - handle: SiteObjectWatcherHandleType, -): SiteObjectWatcherSchemaType { - return { - properties: { - definitions: { - properties: { - public: { - properties: { - [property]: { - properties: { - ['*']: { - handle, - properties: { - name: { - state: [SiteObserverState.RuntimeComplete], - }, - }, - state: SITE_OBSERVER_STATE, - }, - }, - state: SITE_OBSERVER_STATE, - }, - }, - state: SITE_OBSERVER_STATE, - }, - }, - state: SITE_OBSERVER_STATE, - }, - }, - } -} - -export function createCodeModulePublicCollectionObserverSchema( - property: string, - handle: SiteObjectWatcherHandleType, -): SiteObjectWatcherSchemaType { - return { - properties: { - definitions: { - properties: { - public: { - properties: { - [property]: { - handle, - state: [SiteObserverState.CollectionGathered], - }, - }, - state: SITE_OBSERVER_STATE, - }, - }, - state: SITE_OBSERVER_STATE, - }, - }, - } -} - -export function createWatcherFromSchema( - schema: SiteObjectWatcherSchemaType, -): SiteObjectWatcherType { - const watcher: SiteObjectWatcherType = { - properties: {}, - } - - Object.keys(schema.properties).forEach(name => { - const property = schema.properties[ - name - ] as SiteObjectWatcherPropertyType - - watcher.properties[name] = code.createWatcherFromSchemaProperty( - property, - name, - ) - }) - - return watcher -} - -export function createWatcherFromSchemaProperty( - property: SiteObjectWatcherSchemaPropertyType, - name: string, - parent?: SiteObjectWatcherPropertyType, - pending = 1, -): SiteObjectWatcherPropertyType { - const watcher: SiteObjectWatcherPropertyType = { - counted: true, - handle: property.handle, - matched: false, - name, - pending, - state: property.state, - } - - const isDynamic = name === '*' - - Object.defineProperty(watcher, 'parent', { - enumerable: false, - value: parent, - }) - - Object.defineProperty(watcher, 'node', { - enumerable: false, - value: undefined, - writable: true, - }) - - let higher = parent - while (higher) { - higher.pending += pending - higher = higher.parent - } - - const propertyProperties = property.properties - - if (propertyProperties) { - const nestedProperties: SiteObjectWatcherPropertiesType = {} - - Object.keys(propertyProperties).forEach(name => { - const child = propertyProperties[ - name - ] as SiteObjectWatcherPropertyType - - const isChildDynamic = name === '*' - - nestedProperties[name] = createWatcherFromSchemaProperty( - child, - name, - isDynamic ? undefined : watcher, - isDynamic ? 0 : 1, - ) - }) - - if (isDynamic) { - watcher.dynamicProperties = nestedProperties - watcher.properties = {} - } else { - watcher.properties = nestedProperties - } - } - - return watcher -} - -export function extendDynamicPropertyWatcher( - load: MeshLoad, - watcher: SiteObjectWatcherPropertyType, - name: string, -): SiteObjectWatcherPropertyType { - const { dynamicProperties } = watcher - code.assertRecord(dynamicProperties) - - const childWatcher: SiteObjectWatcherPropertyType = { - counted: false, - matched: false, - name, - parent: watcher, - pending: 0, - state: [], - } - - const nestedProperties: Record< - string, - SiteObjectWatcherPropertyType - > = {} - - Object.keys(dynamicProperties).forEach(name => { - const child = dynamicProperties[ - name - ] as SiteObjectWatcherPropertyType - - nestedProperties[name] = createWatcherFromSchemaProperty( - child, - name, - childWatcher, - ) - }) - - childWatcher.properties = nestedProperties - - const { properties } = watcher - - code.assertRecord(properties) - - properties[name] = childWatcher - - return childWatcher -} - -export function isObserverStateAccepted( - load: SiteObserverState, - potential: Array, -): boolean { - if (potential.includes(SiteObserverState.CollectionGathered)) { - return load === SiteObserverState.CollectionGathered - } - - if (potential.includes(SiteObserverState.Initialized)) { - return SITE_OBSERVER_STATE.includes(load) - } - - if (potential.includes(SiteObserverState.StaticComplete)) { - return SITE_OBSERVER_COMPLETE_STATE.includes(load) - } - - if (potential.includes(SiteObserverState.RuntimeComplete)) { - return load === SiteObserverState.RuntimeComplete - } - - return false -} - -export function propagatePendingUpwards( - property: SiteObjectWatcherPropertyType, - amount: number, -): void { - let higher: SiteObjectWatcherPropertyType | undefined = property - - while (higher) { - higher.pending += amount - higher = higher.parent - } -} - -export function queuePropertyUpdateHandle( - load: MeshLoad, - handle: SiteObjectWatcherHandleType, - node: BlueNodeType, -): void { - code.addTask(load.base, () => handle(node)) -} - -export function registerSchema( - load: SiteModuleBindingInputType, - schema: SiteObjectWatcherSchemaType, -): SiteObjectWatcherType { - let list = load.base.watchers[load.moduleId] - - if (!list) { - list = load.base.watchers[load.moduleId] = [] - } - - const watcher = code.createWatcherFromSchema(schema) - - list.push(watcher) - - return watcher -} - -export function resolveBluePath( - blue: BlueNodeType, -): Array> { - let node: BlueNodeType | undefined = blue - const array: Array> = [] - while (node) { - array.push(node) - node = node.parent - } - return array.reverse() -} - -export function triggerObjectBindingUpdate( - load: MeshLoad, - node: BlueNodeType, -): void { - const watchers = load.base.watchers[load.module.id] - - if (!watchers) { - return - } - - const path = code.resolveBluePath(node) - watchers.forEach(watcher => { - code.updateWatcherForPath(load, watcher, path) - }) -} - -export function updateAllThroughWatcher( - load: SiteModuleBindingInputType, - watcher: SiteObjectWatcherType, -): void { - let node = load.module.blue.node as BlueMapType< - Record - > - - for (const name in watcher.properties) { - const property = watcher.properties[ - name - ] as SiteObjectWatcherPropertyType - - let child = node.value[name] as BlueType - - code.updateAllThroughWatcherProperty(load, property, child) - } - - // console.log(JSON.stringify(watcher, null, 2)) -} - -export function updateAllThroughWatcherProperty( - load: SiteModuleBindingInputType, - property: SiteObjectWatcherPropertyType, - node: Record, -): void { - code.assertGenericBlue(node) - - if (code.isObserverStateAccepted(node.state, property.state)) { - property.matched = true - code.propagatePendingUpwards(property, -1) - } - - property.node = node - - const { properties } = property - - if (properties) { - Object.keys(properties).forEach(name => { - const childProperty = properties[ - name - ] as SiteObjectWatcherPropertyType - - if (childProperty.dynamicProperties) { - switch (node.type) { - case Mesh.Array: { - const potentialChildren = node.value as Array - potentialChildren.forEach((childValue, i) => { - const elementProperty = code.extendDynamicPropertyWatcher( - load, - property, - String(i), - ) - - code.updateAllThroughWatcherProperty( - load, - elementProperty, - childValue, - ) - }) - break - } - case Mesh.Map: { - const potentialMap = node.value as Record - for (const key in potentialMap) { - const childValue = potentialMap[key] as BlueType - const elementProperty = code.extendDynamicPropertyWatcher( - load, - property, - key, - ) - - code.updateAllThroughWatcherProperty( - load, - elementProperty, - childValue, - ) - } - break - } - default: - code.throwError(code.generateInvalidCompilerStateError()) - } - } else { - switch (node.type) { - case Mesh.Map: { - node = node.value as Record - } - default: - break - } - - const childValue = node[name] as BlueType - - code.updateAllThroughWatcherProperty( - load, - childProperty, - childValue, - ) - } - }) - } -} - -export function updateWatcherForPath( - load: MeshLoad, - watcher: SiteObjectWatcherType, - path: Array>, -): void { - let properties: SiteObjectWatcherPropertiesType | undefined = - watcher.properties - - let i = 0 - - while (i < path.length) { - const node = path[i++] as BlueNodeType - code.assertString(node.attachedAs) - - let property: SiteObjectWatcherPropertyType | undefined = - properties[node.attachedAs] - - if (!property) { - return - } - - property.node = node - - if (i === path.length) { - if (property.matched) { - return - } - - property.matched = property.state.includes(node.state) - - if (property.matched) { - while (property) { - property.pending-- - if (property.pending === 0 && property.handle) { - code.assertRecord(property.node) - - const parent = property.parent - if (parent?.properties) { - delete parent.properties[property.name] - } - - code.queuePropertyUpdateHandle( - load, - property.handle, - property.node, - ) - } - property = property.parent - } - } - - return - } - - properties = property.properties - - if (!properties) { - return - } - } -} diff --git a/hack/code/tool/task.ts b/hack/code/tool/task.ts deleted file mode 100644 index 8006e00..0000000 --- a/hack/code/tool/task.ts +++ /dev/null @@ -1,12 +0,0 @@ -import { Base } from '../form/base.js' - -export function callTask(base: Base): void { - const task = base.task.shift() - if (task) { - task() - } -} - -export function hostTask(base: Base, hook: SiteCallbackType): void { - base.task.push(hook) -} diff --git a/hack/code/tool/text.ts b/hack/code/tool/text.ts deleted file mode 100644 index 7d2b9e0..0000000 --- a/hack/code/tool/text.ts +++ /dev/null @@ -1,37 +0,0 @@ -import { MeshLoad } from '../form.js' -import card from '../card.js' -import tool from '../tool.js' - -export function bindText(load: MeshLoad, hook: (text: string) => void) { - const hint = tool.readLinkHint(load) - switch (hint) { - case LinkHint.Text: { - const string = tool.loadText(load) - hook(string) - break - } - case LinkHint.NickText: { - const string = tool.loadNickText(load) - - if (string) { - hook(string) - } else { - tool.waitText(load, () => { - const string = tool.loadNickText(load) - if (!string) { - tool.throwError(`Received null for string`, load) - } else { - hook(string) - } - }) - } - } - default: - tool.throwError(tool.generateUnhandledNestCaseError(load, hint)) - } -} - -// https://github.com/nerdbond/base.link/blob/make/make/tool/dependency.ts#L277 -export function loadNickText(load: MeshLoad) {} - -export function loadText(load: MeshLoad) {} diff --git a/hack/code/typecheck/readme.md b/hack/code/typecheck/readme.md deleted file mode 100644 index fefafec..0000000 --- a/hack/code/typecheck/readme.md +++ /dev/null @@ -1,214 +0,0 @@ -# TypeChecking and Type Inference - -This section does all the typechecking and inference and borrow checking -and lifetime checking and whatnot. - -Still have a long ways to go to figuring this out. - -- [Type Inference in Rust Compiler](https://rustc-dev-guide.rust-lang.org/type-inference.html) -- https://sdleffler.github.io/RustTypeSystemTuringComplete/ -- http://sinelaw.github.io/infernu.org/s/posts/type-system.html -- https://jaked.org/blog/2021-09-07-Reconstructing-TypeScript-part-0 - -Example: - - function checkFunctionCall(call, fork) { - // check the inputs match the task type - // check the right number of inputs exist - // check the bindings on the call are defined in the fork - } - - function check(ast: Expression, type: Type) { - if (AST.isObjectExpression(ast) && Type.isObject(type)) - return checkObject(ast, type); - - const synthType = synth(ast); - if (!Type.isSubtype(synthType, type)) - err(`expected ${Type.toString(type)}, got ${Type.toString(synthType)}`, ast); - } - -So we need to create a type from the AST nodes. So we have the Mesh -nodes, and the Form nodes (types). Each mesh has a form node. - - make (infer) => construct a form - test (check) => compare mesh to form - take (if it was accepted) - - riff.form (its ast type) - riff.note.take (if it is accepted) - riff.note.form (its runtime type) - riff.note.link (link tree nodes, so we can get back to error handling) - riff.link (properties) - -The riff is the AST node. - -fork (the environment) - -Step through the AST (iterate through the calls), and construct a fork -for each step. Then test that the riff matches the form, or infer it and -then check. - - function testFormForm() { - - } - - function testForm(riff, form) { - for (const name in riff.link) { - - } - } - -Can mark the literals with the final type instantly. - - if (riff.workFormTake && riff.workForm !== form) { - throw halt('invalid_type') - } - -The compile target is just an AST, it's not the actual executable. The -executable is the finally generated code. The AST is a tree structure, -not a graph, so there won't be a problem rendering it. - - riff.base //=> calculate path to notify watchers - - base.hook[line].push(hook) - -Actually we want to add a tree of watchers, so they look up by property -key. - -The interpolated references are used to generate more of the AST? - ---- - -So we have the AST as used by the documentation tool. It goes: - -- link text tree (CST) -- mesh tree (AST), which is a wrapper around link tree - -mesh.text // link tree mesh.link // properties - -The mesh tree is generated from the data. It is modified (modifying the -link text nodes) to change the layout of the code. As we modify the CST, -the meaning of the ranks (position of the code in text) goes away, since -now we have added dynamic elements to it. - -The property `form-code` gives a number for the type, and has `unknown` -type if it is unknown. You can't access the AST for the types at -runtime. The form code is the hash of the module name + form name. - -How to access the form AST then at runtime? - -https://web.mit.edu/rust-lang_v1.25/arch/amd64_ubuntu1404/share/doc/rust/html/book/first-edition/procedural-macros.html - -derive(Insertable) - -You need to - - hook mesh - - user.form.link.forEach - - mesh user - - mesh any # include ast of all types - - form user - mesh true - - save user/email, - -calls - - call user/save, 'email', - -And runs validations based on type. - -No, do the validation elsewhere. - - form user - fuse insertable - - # like a tree/template, except it gives you the captured final AST as well. - mesh insertable - take mesh, like mesh - - hook fuse - task insert - walk mesh/link - - tree insertable - mesh true - - hook fuse - task insert - take mesh, like mesh - take self, like self - walk mesh/link - -Gives you the mesh/AST for each task, after it is complete. - - form user - task insert - take self - mesh true - - walk self/form/link - ... - -If you want the AST for a specific task: - - task insert - mesh true - -If you want the AST for a whole module, just add it at the top level: - - mesh true - -If you want the AST for everything, you can do this in a role file: - - file ./**/*.link - mesh true - - suit insertable - mesh true - - task insert - -The mesh is the _final_ compiled target, which links to the link CST. - -If you want the full AST with the CST, you need to simply parse the file -again at runtime. Or perhaps there is a special `code true` term? - -The code is accessible in mesh, you just read the file with mesh and get -the AST, then match it to the form id. Or do whatever to generate -documentation, or use in the linter. - -So it's like, we call: - - mesh/make-tree - -That gives us the final compiled tree, without typechecking or any of -that. - - mesh/mold-tree - -That does typechecking and type inference. - - mesh/save-js - mesh/save-link - -These take an AST and write the output file. - -That way, the documentation can just call `make-tree` to get an AST -ready for documentation generation. The linter can take the result of -`make-tree` and rewrite some of the AST, to then call `save-link` and -replace some of the file. Or if we want to generate the final js, we can -call `mold-tree` and then `save-js`. - -The `mold-tree` will then do the typechecking. The typechecking is -basically doing symbolic evaluation. - -A test generator can take the typed ast and generate tests based on -constraints somehow. - -The make of the tree uses the mill grammars for the tree, to generate -the structures. diff --git a/hack/form/base.ts b/hack/form/base.ts deleted file mode 100644 index f10bfc7..0000000 --- a/hack/form/base.ts +++ /dev/null @@ -1,13 +0,0 @@ -import Fill from './fill/hash.js' - -// base.ts -class Base { - fill: Fill - - card: Record - - task: Array - - // env vars - host: Record -} diff --git a/hack/form/card.ts b/hack/form/card.ts deleted file mode 100644 index 65c9d24..0000000 --- a/hack/form/card.ts +++ /dev/null @@ -1,3 +0,0 @@ -import * as card from './card/index.js' - -export default card diff --git a/hack/form/deck/find.ts b/hack/form/deck/find.ts deleted file mode 100644 index e62a572..0000000 --- a/hack/form/deck/find.ts +++ /dev/null @@ -1,112 +0,0 @@ -import fs from 'fs' -import pathResolver from 'path' - -export function findHostLink( - link: string, - base: string, -): string | void { - const linkBase = pathResolver.join(base, `./link/hook/${link}`) - if (testFileBase(linkBase)) { - const linkBaseBond = readLink(linkBase) - - if (testFile(linkBaseBond)) { - return readLink(linkBaseBond) - } else if (testFileBase(linkBaseBond)) { - const deckLink = `${base}/deck.link` - if (testFile(deckLink)) { - const deck = loadDeck(deckLink) - if (deck && deck.head) { - const deckHeadLink = pathResolver.relative(deck.head, base) - if (testFile(deckHeadLink)) { - return readLink(deckHeadLink) - } - } - } - const BaseNote = `${base}/base.link` - if (testFile(BaseNote)) { - return readLink(BaseNote) - } - } - } - - if (base != '/') { - const riseLink = pathResolver.join(base, '..') - return findHostLink(link, riseLink) - } -} - -export function findLeadLink(linkBase: string): string | void { - if (testFileBase(linkBase)) { - const linkBaseBond = readLink(linkBase) - // it doesn't need to check the package.json, that is what the installer does. - // so by this point it is the actual structure. - if (testFile(linkBaseBond)) { - return readLink(linkBaseBond) - } else if (testFileBase(linkBaseBond)) { - const deckLink = `${linkBaseBond}/deck.link` - if (testFile(deckLink)) { - const deck = loadDeck(deckLink) - if (deck.head) { - const deckHeadLink = pathResolver.relative( - deck.head, - linkBaseBond, - ) - if (testFile(deckHeadLink)) { - return readLink(deckHeadLink) - } - } - } - const BaseNote = `${linkBaseBond}/base.link` - if (testFile(BaseNote)) { - return readLink(BaseNote) - } - } - } -} - -export function findLink(link: string, base: string) { - if (link.startsWith('@')) { - return findHostLink(link.slice(1), process.cwd()) - } else { - return findLeadLink(pathResolver.relative(link, base)) - } -} - -export const readLink = - process.platform !== 'win32' && - fs.realpathSync && - typeof fs.realpathSync.native === 'function' - ? fs.realpathSync.native - : fs.realpathSync - -export function testFile(dir: string) { - try { - const stat = fs.statSync(dir, { throwIfNoEntry: false }) - return !!stat && (stat.isFile() || stat.isFIFO()) - } catch (halt) { - if (testFileReadHalt(halt)) { - return false - } - throw halt - } -} - -export function testFileBase(file: string) { - try { - const stat = fs.statSync(file, { throwIfNoEntry: false }) - return !!stat && stat.isDirectory() - } catch (halt) { - if (testFileReadHalt(halt)) { - return false - } - throw halt - } -} - -function testFileReadHalt(halt: unknown) { - return ( - halt instanceof Error && - 'code' in halt && - (halt.code === 'ENOENT' || halt.code === 'ENOTDIR') - ) -} diff --git a/hack/form/deck/install.ts b/hack/form/deck/install.ts deleted file mode 100644 index e69de29..0000000 diff --git a/hack/form/deck/run.ts b/hack/form/deck/run.ts deleted file mode 100644 index e69de29..0000000 diff --git a/hack/form/deck/test.ts b/hack/form/deck/test.ts deleted file mode 100644 index e69de29..0000000 diff --git a/hack/form/form.ts b/hack/form/form.ts deleted file mode 100644 index ca0bbfd..0000000 --- a/hack/form/form.ts +++ /dev/null @@ -1 +0,0 @@ -export * from './form/index.js' diff --git a/hack/form/form/base.ts b/hack/form/form/base.ts deleted file mode 100644 index d92f981..0000000 --- a/hack/form/form/base.ts +++ /dev/null @@ -1,22 +0,0 @@ -import { RiffDeck, SiteLookFormLink } from '~' - -export class Base { - // tasks to be run - task: Array<() => void> - - // observers - hook: Record> - - // env variables - host: Record - - // the file tree - deck: Record - - constructor() { - this.task = [] - this.hook = {} - this.host = {} - this.deck = {} - } -} diff --git a/hack/form/form/form.ts b/hack/form/form/form.ts deleted file mode 100644 index ef68c47..0000000 --- a/hack/form/form/form.ts +++ /dev/null @@ -1,40 +0,0 @@ -export enum Form { - Bear = 'bear', - Bind = 'bind', - Call = 'call', - Cite = 'cite', - CodeCard = 'code-card', - Comb = 'comb', - Deck = 'deck', - DeckCard = 'deck-card', - DeckFace = 'deck-face', - DeckLink = 'deck-link', - DeckLock = 'deck-lock', - Dock = 'dock', - Form = 'form', - FormHead = 'form-head', - Fuse = 'fuse', - HideBear = 'hide-bear', - Hold = 'hold', - Hook = 'hook', - Host = 'host', - Line = 'line', - Link = 'link', - List = 'list', - Load = 'load', - LoadFind = 'load-find', - LoadFindTake = 'load-find-take', - SideSize = 'side-size', - Size = 'size', - Suit = 'suit', - Take = 'take', - Task = 'task', - TermLink = 'term-link', - Test = 'test', - Text = 'text', - TextLink = 'text-link', - TextList = 'text-list', - Tree = 'tree', - Wave = 'wave', - Wear = 'wear', -} diff --git a/hack/form/form/index.ts b/hack/form/form/index.ts deleted file mode 100644 index 1f9301d..0000000 --- a/hack/form/form/index.ts +++ /dev/null @@ -1,4 +0,0 @@ -export * from './base.js' -export * from './mesh.js' -export * from './tree.js' -export * from './site.js' diff --git a/hack/form/form/mesh.ts b/hack/form/form/mesh.ts deleted file mode 100644 index 0b5a117..0000000 --- a/hack/form/form/mesh.ts +++ /dev/null @@ -1,11 +0,0 @@ -import { Base } from './base' -import { Tree, TreeCard } from './tree' -import { SiteFork } from './site' - -export type MeshLoad = { - base: Base - card: TreeCard - fork: SiteFork - // link: Link - riff: Tree -} diff --git a/hack/form/form/site.ts b/hack/form/form/site.ts deleted file mode 100644 index 614071b..0000000 --- a/hack/form/form/site.ts +++ /dev/null @@ -1,213 +0,0 @@ -/* eslint-disable @typescript-eslint/no-explicit-any */ -import { Base, FormMesh } from '@nerdbond/form' - -export class TreeBase { - link: Record - - hook: Record void> - - constructor() { - this.link = {} - this.hook = {} - } - - bind(name, form, hook) { - const list = (this.hook[name] ??= []) - const bind = {} - const nest = {} - for (const name in form) { - const bond = form[name] - if (isObject(bond)) { - nest[name] = bond - } else { - bind[name] = true - } - } - // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment - list.push({ bind, hook, nest }) - } -} - -export class TreeBind {} - -export class TreeFork { - constructor() { - this.link = {} - } - - bind(name, form, bond) {} - - form(name, form) {} - - save(name, bond) {} -} - -type MakeTreeBase = { - base: B - fork: TreeFork - form: FM -} - -// eslint-disable-next-line sort-exports/sort-exports -export class TreeSite< - B extends Base, - FM extends FormMesh, -> extends TreeBase { - base: B - - form: FM - - fork: TreeFork - - bond: any - - constructor({ base, form, fork }: MakeTreeBase) { - super() - this.base = base - this.form = form - this.fork = fork - } - - save( - name: string, - bond: TreeSite | string | number | boolean | null, - ) { - const link = this.form.link[name] - this.link[name] = bond - if (!testMesh(bond)) { - const bindList = this.bind[name] - if (bindList) { - for (const bind of bindList) { - bind.hook(this) - } - } - } - } - - bind1(hook: TreeHook) { - // self and all children are resolved - for (const name in form.link) { - const nestHook = () => { - this.needSize-- - this.needLink[name] = false - this.killBind2(name, nestHook) - if (this.needSize === 0) { - hook() - } - } - this.bind2(name, nestHook) - } - } - - bind2(name: string, hook: TreeHook) { - // all the children are resolved - const list = (this.bind[name] ??= []) - list.push({ hook }) - } - - bind3(name: string, test: TreeTest, hook: TreeHook) { - // subset of children are resolved - const list = (this.bind[name] ??= []) - const nest = makeTestNest(test, hook) - list.push({ hook, nest }) - - function makeTestNest(test, hook) { - const nest = [] - const site = this - let need = 0 - for (const name in test) { - need++ - const hookSelf = self => { - self.need-- - if (self.need === 0) { - hook(site) - } - } - nest.push({ hook: hookSelf, name, need }) - } - return nest - } - } -} - -type TreeTest = { - [name: string]: true | TreeTest -} - -type TreeHook = () => void - -type Matcher = { - [key: string]: true | Matcher -} - -type Callback = () => void - -abstract class TreeElement { - #parent?: TreeObject - - #listeners: Array<{ callback: Callback; matcher?: Matcher }> = [] - - constructor(parent?: TreeObject) { - this.#parent = parent - } - - watch(callback: Callback, matcher?: Matcher) { - if (this.isResolved(matcher)) { - callback.call(this) - } else { - this.#listeners.push({ callback, matcher }) - } - } - - notify() { - // empty(!) the listeners array and let the watch method deal with them - for (const { callback, matcher } of this.#listeners.splice(0)) { - this.watch(callback, matcher) - } - this.#parent?.notify() // bubble up - } - - abstract isResolved(matcher?: Matcher): boolean -} - -class TreeObject extends TreeElement { - #properties: Record = {} - - createObject(name: string) { - return (this.#properties[name] = new TreeObject(this)) - } - - createLiteral(name: string) { - return (this.#properties[name] = new TreeLiteral(this)) - } - - isResolved(matcher?: Matcher): boolean { - const keys = Object.keys(matcher ?? this.#properties) - return ( - keys.length > 0 && - keys.every(key => - this.#properties[key]?.isResolved( - !matcher || matcher?.[key] === true - ? undefined - : (matcher[key] as Matcher), - ), - ) - ) - } -} - -class TreeLiteral extends TreeElement { - #literalValue: any - - #isResolved = false - - set(value: any) { - this.#literalValue = value - this.#isResolved = true - this.notify() - } - - isResolved(): boolean { - return this.#isResolved - } -} diff --git a/hack/form/form/tree.ts b/hack/form/form/tree.ts deleted file mode 100644 index 5066707..0000000 --- a/hack/form/form/tree.ts +++ /dev/null @@ -1,500 +0,0 @@ -import { Form } from './form' - -export type Tree = - | TreeBear - | TreeBind - | TreeCall - | TreeLike - | TreeCodeCard - | TreeComb - | TreeDeck - | TreeDeckCard - | TreeDeckFace - | TreeDeckLock - | TreeDock - | TreeForm - | TreeFormHead - | TreeFuse - | TreeHideBear - | TreeHold - | TreeHook - | TreeHost - | TreeLine - | TreeLink - | TreeLoad - | TreeLoadFind - | TreeLoadFindTake - | TreeSideSize - | TreeSize - | TreeSuit - | TreeTake - | TreeTask - | TreeLine - | TreeTest - | TreeText - | TreeTextLink - | TreeTree - | TreeWave - | TreeWear - | TreeDeckLink - -export type TreeBase = { - // id - // code: string - // parent, so we can build paths - base?: Tree - // module associated with this, for easier error reporting - card?: TreeCard - // scope associated with this node. - fork: any - // unprocessed yet - needSize: number - // state of how complete the AST node is. - riseMark: TreeRiseMark - // list of children values which are dynamic unparsed terms - // list: Array - // how it is passed down. - slot: string - // the link tree (parsed text) associated with this - // tree: LinkTreeType - // runtime type - workForm?: TreeName - // whether or not the type form is accepted - workFormTake: boolean -} - -// export type TreeComb = TreeBase & { -// form: `tree-${Form.Comb}` -// type: Mesh.Decimal -// } -export type TreeBear = TreeBase & { - form: `tree-${Form.Bear}` - link: { - hide: TreeList - link?: TreeText - } -} - -export type TreeBind = TreeBase & { - form: `tree-${Form.Bind}` - link: { - bond?: TreeBond // or more - name?: TreeLine - } -} - -export type TreeBond = - | TreeText - | TreeSize - | TreeSideSize - | TreeComb - | TreeWave - -export type TreeCall = TreeBase & { - form: `tree-${Form.Call}` - link: { - bind: TreeList - line?: TreeLineForm - risk?: TreeWave - wait?: TreeWave - } -} - -export type TreeCard = TreeCodeCard | TreeDeckCard - -export type TreeCodeCard = TreeBase & { - form: `tree-${Form.CodeCard}` - link: { - bear: TreeList - dock: TreeList - form: TreeList - fuse: TreeList - hook: TreeList - host: TreeList - line: string - lineText: Array - linkTree: LinkTreeType - load: TreeList - suit: TreeList - task: TreeList - test: TreeList - text: string - tree: TreeList - } -} - -export type TreeComb = TreeBase & { - form: `tree-${Form.Comb}` - link: { - bond: number - } -} - -export type TreeDeck = TreeBase & { - form: `tree-${Form.Deck}` - link: { - bear?: TreeText - deck: TreeList - face: TreeList - host?: TreeText - mark?: TreeText - name?: TreeText - read?: TreeText - term: TreeList - test?: TreeText - } -} - -export type TreeDeckCard = TreeBase & { - form: `tree-${Form.DeckCard}` - link: { - deck?: TreeDeck - line: string - } -} - -export type TreeDeckFace = TreeBase & { - form: `tree-${Form.DeckFace}` - link: { - name?: TreeText - site?: TreeText - } -} - -export type TreeDeckLink = TreeBase & { - form: `tree-${Form.DeckLink}` - link: { - mark?: TreeText - name?: TreeText - } -} - -export type TreeDeckLock = TreeBase & { - form: `tree-${Form.DeckLock}` - link: {} -} - -export type TreeDock = TreeBase & { - form: `tree-${Form.Dock}` - link: {} -} - -// a placeholder unparsed yet. -export type TreeFoldList = TreeBase & { - link: {} -} - -export type TreeForm = TreeBase & { - form: `tree-${Form.Form}` - link: { - head: TreeList - hide?: TreeWave - hook: TreeList - link: TreeList - name?: TreeLine - task: TreeList - wear: TreeList - } -} - -export type TreeFormHead = TreeBase & { - form: `tree-${Form.FormHead}` - link: { - base?: TreeLike - name?: TreeLine - } -} - -export type TreeFuse = TreeBase & { - form: `tree-${Form.Fuse}` - link: { - bind: TreeList - name?: TreeLine - } -} - -export type TreeHash = { - bear: TreeBear - bind: TreeBind - call: TreeCall - cite: TreeLike - 'code-card': TreeCodeCard - comb: TreeComb - deck: TreeDeck - 'deck-card': TreeDeckCard - 'deck-face': TreeDeckFace - 'deck-link': TreeDeckLink - 'deck-lock': TreeDeckLock - dock: TreeDock - form: TreeForm - 'form-head': TreeFormHead - fuse: TreeFuse - 'hide-bear': TreeHideBear - hold: TreeHold - hook: TreeHook - host: TreeHost - line: TreeLine - link: TreeLink - load: TreeLoad - 'load-find': TreeLoadFind - 'load-find-take': TreeLoadFindTake - 'side-size': TreeSideSize - size: TreeSize - suit: TreeSuit - take: TreeTake - task: TreeTask - test: TreeTest - text: TreeText - tree: TreeTree - wave: TreeWave -} - -export type TreeHideBear = TreeBase & { - form: `tree-${Form.HideBear}` - link: { - hostName?: TreeLine - name?: TreeLine - } -} - -// assertion -export type TreeHold = TreeBase & { - form: `tree-${Form.Hold}` - link: {} -} - -export type TreeHook = TreeBase & { - form: `tree-${Form.Hook}` - link: { - call: TreeList - name?: TreeLine - take: TreeList - task: TreeList - } -} - -export type TreeHost = TreeBase & { - form: `tree-${Form.Host}` - link: { - bond?: TreeBond | TreeList - hide?: TreeWave - name?: TreeLine - } -} - -export type TreeLike = TreeBase & { - form: `tree-${Form.Cite}` - link: { - bind: TreeList - name?: TreeLine - } -} - -export type TreeLine = TreeBase & { - form: `tree-${Form.Line}` - link: { - // bond: LinkPathType - } -} - -export type TreeLineForm = TreeLine | TreeLine - -export type TreeLink = TreeBase & { - form: `tree-${Form.Link}` - link: { - bond: TreeWave - // dereference - cite: TreeWave - // mutable - flex: TreeWave - // owner - have: TreeWave - line: TreeLineForm - // reference - time?: string - } -} - -export type TreeList = { - bond: Array - form: `tree-${Form.List}` - headSize: number - leadSize: number -} - -export type TreeLoad = TreeBase & { - form: `tree-${Form.Load}` - link: { - find: TreeList - link?: TreeText - } -} - -export type TreeLoadFind = TreeBase & { - form: `tree-${Form.LoadFind}` - link: { - forkName?: TreeLine - name?: TreeLine - take?: TreeLoadFindTake - } -} - -export type TreeLoadFindTake = TreeBase & { - form: `tree-${Form.LoadFindTake}` - link: {} -} - -export enum TreeName { - Bear = 'riff-bear', - Bind = 'riff-bind', - Call = 'riff-call', - Cite = 'riff-cite', - CodeCard = 'riff-code-card', - Comb = 'riff-comb', - Deck = 'riff-deck', - DeckCard = 'riff-deck-card', - DeckFace = 'riff-deck-face', - DeckLock = 'riff-deck-lock', - Dock = 'riff-dock', - Form = 'riff-form', - FormHead = 'riff-form-head', - Fuse = 'riff-fuse', - HideBear = 'riff-hide-bear', - Hold = 'riff-hold', - Hook = 'riff-hook', - Host = 'riff-host', - Line = 'riff-line', - Link = 'riff-link', - Load = 'riff-load', - LoadFind = 'riff-load-find', - LoadFindTake = 'riff-load-find-take', - SideSize = 'riff-side-size', - Size = 'riff-size', - Suit = 'riff-suit', - Take = 'riff-take', - Task = 'riff-task', - Test = 'riff-test', - Text = 'riff-text', - TextLink = 'riff-text-link', - TextList = 'riff-text-list', - Tree = 'riff-tree', - Wave = 'riff-wave', - Wear = 'riff-wear', -} - -export enum TreeNote { - CollectionGathered = 'collection-gathered', - Initialized = 'initialized', - RuntimeComplete = 'runtime-complete', - StaticComplete = 'static-complete', -} - -export enum TreeRiseMark { - CollectionGathered = 'collection-gathered', - Initialized = 'initialized', - RuntimeComplete = 'runtime-complete', - StaticComplete = 'static-complete', -} - -export type TreeSideSize = TreeBase & { - form: `tree-${Form.SideSize}` - link: { - bond: number - } -} - -export type TreeSize = TreeBase & { - form: `tree-${Form.Size}` - link: { - bond: number - } -} - -export type TreeSuit = TreeBase & { - form: `tree-${Form.Suit}` - link: { - bind?: TreeList - head: TreeList - hide?: TreeWave - link: TreeList - name?: TreeLine - task: TreeList - } -} - -export type TreeTake = TreeBase & { - form: `tree-${Form.Take}` - link: { - name?: TreeText - } -} - -export type TreeTask = TreeBase & { - form: `tree-${Form.Task}` - link: { - base?: TreeTask - call: TreeList - head: TreeList - hide?: TreeWave - like?: TreeLike - name?: TreeLine - risk?: TreeWave - take: TreeList - task: TreeList - wait?: TreeWave - } -} - -export type TreeTest = TreeBase & { - form: `tree-${Form.Test}` - link: {} -} - -export type TreeText = TreeBase & { - form: `tree-${Form.Text}` - link: { - bond: string - } -} - -export type TreeTextLink = TreeBase & { - form: `tree-${Form.TextLink}` - link: { - // bond: LinkTextType - } -} - -export type TreeTree = TreeBase & { - form: `tree-${Form.Tree}` - link: { - hide?: TreeWave - hook: TreeList - name?: TreeLine - take: TreeList - } -} - -export type TreeWave = TreeBase & { - form: `tree-${Form.Wave}` - link: { - bond: boolean - } -} - -export type TreeWear = TreeBase & { - form: `tree-${Form.Wear}` - link: {} -} - -// eslint-disable-next-line sort-exports/sort-exports -export const SITE_OBSERVER_STATE = [ - TreeNote.Initialized, - TreeNote.StaticComplete, - TreeNote.RuntimeComplete, -] - -// eslint-disable-next-line sort-exports/sort-exports -export const SITE_OBSERVER_COMPLETE_STATE = [ - TreeNote.StaticComplete, - TreeNote.RuntimeComplete, -] diff --git a/hack/form/index.ts b/hack/form/index.ts deleted file mode 100644 index ef474a4..0000000 --- a/hack/form/index.ts +++ /dev/null @@ -1,20 +0,0 @@ -import { load_deckCard } from './mesh/deck/index.js' -import { - callTask, - findLink, - createBase, - setEnvironmentVariable, -} from './tool/index.js' - -export default async function build(host: string) { - const link = findLink(host) - assertString(link) - const base = createBase() - setEnvironmentVariable(base, 'dock', 'javascript') - setEnvironmentVariable(base, 'site', 'test') - load_deckCard(base, link) - while (base.tasks.length) { - callTask(base) - } - // exportNodeJS(base) -} diff --git a/hack/form/load/index.ts b/hack/form/load/index.ts deleted file mode 100644 index d7472f5..0000000 --- a/hack/form/load/index.ts +++ /dev/null @@ -1,40 +0,0 @@ -import { minimatch } from 'minimatch' -import { Base } from '../form.js' -import tool from '../tool.js' - -export * from './deck/index.js' -export * from './mint/index.js' - -export function loadCard(base: Base, link: string): void { - if (tool.testHaveCard(base, link)) { - return - } - - const deck = card.loadDeckFile(link) - const mint = card.loadMintFile(deck) - - walk: for (const have of mint.mint) { - if (minimatch(link, have.link)) { - switch (have.name) { - case 'deck': - return card.load_deckCard(base, link) - case 'code': - return card.load_codeCard(base, link) - case 'mint': - return card.load_mintCard(base, link) - case 'call': // api urls - return card.load_callCard(base, link) - case 'line': // cli hooks - return card.load_lineCard(base, link) - case 'note': // a note type is a scratch type which isn't validated - return card.load_noteCard(base, link) - case 'book': - return card.load_bookCard(base, link) - default: - throw card.haltMissMintName() - } - } - } - - throw card.haltCardMiss() -} diff --git a/hack/form/load/mill/index.ts b/hack/form/load/mill/index.ts deleted file mode 100644 index b1c6ea4..0000000 --- a/hack/form/load/mill/index.ts +++ /dev/null @@ -1 +0,0 @@ -export default {} diff --git a/hack/form/load/mill/mine/index.ts b/hack/form/load/mill/mine/index.ts deleted file mode 100644 index e69de29..0000000 diff --git a/hack/form/load/mill/mint/mint.ts b/hack/form/load/mill/mint/mint.ts deleted file mode 100644 index e69de29..0000000 diff --git a/hack/form/look/bind/code.ts b/hack/form/look/bind/code.ts deleted file mode 100644 index 1eab236..0000000 --- a/hack/form/look/bind/code.ts +++ /dev/null @@ -1,5 +0,0 @@ -let CODE = 1 - -export default function make() { - return String(CODE++) -} diff --git a/hack/form/look/bind/hash.ts b/hack/form/look/bind/hash.ts deleted file mode 100644 index b22beb5..0000000 --- a/hack/form/look/bind/hash.ts +++ /dev/null @@ -1,12 +0,0 @@ -import Emitter from 'events' -import makeCode from './code' - -export default class BindHash extends Emitter { - code: string - - constructor() { - super() - - this.code = makeCode() - } -} diff --git a/hack/form/look/bind/index.ts b/hack/form/look/bind/index.ts deleted file mode 100644 index a96b740..0000000 --- a/hack/form/look/bind/index.ts +++ /dev/null @@ -1,6 +0,0 @@ -import BindHash from './hash.js' -import BindList from './list.js' -import BindSink from './sink.js' -import BindSite from './site.js' - -export type Bind = BindHash | BindList | BindSite | BindSink diff --git a/hack/form/look/bind/list.ts b/hack/form/look/bind/list.ts deleted file mode 100644 index 2e4d400..0000000 --- a/hack/form/look/bind/list.ts +++ /dev/null @@ -1,31 +0,0 @@ -/* eslint-disable @typescript-eslint/no-explicit-any */ -import Emitter from 'events' -import { Bind } from '.' -import makeCode from './code' - -export default class BindList extends Emitter { - dock: Array - - vibeSeal: boolean - - code: string - - constructor() { - super() - this.dock = [] - this.vibeSeal = false - this.code = makeCode() - } - - saveHead(bond: Bind) { - this.dock.push(bond) - this.emit('save', bond) - } - - seal() { - if (!this.vibeSeal) { - this.vibeSeal = true - this.emit('seal') - } - } -} diff --git a/hack/form/look/bind/sink.ts b/hack/form/look/bind/sink.ts deleted file mode 100644 index 916e119..0000000 --- a/hack/form/look/bind/sink.ts +++ /dev/null @@ -1,25 +0,0 @@ -import Emitter from 'events' -import makeCode from './code' - -export default class BindSink extends Emitter { - code: string - - bond: unknown - - constructor(bond: unknown) { - super() - - this.code = makeCode() - - this.save(bond) - } - - save(bond: unknown) { - this.bond = bond - this.emit('save') - } - - read() { - return this.bond - } -} diff --git a/hack/form/look/bind/site.ts b/hack/form/look/bind/site.ts deleted file mode 100644 index d61b5df..0000000 --- a/hack/form/look/bind/site.ts +++ /dev/null @@ -1,30 +0,0 @@ -/* eslint-disable @typescript-eslint/no-explicit-any */ -import Emitter from 'events' -import { Bind } from '.' -import makeCode from './code' - -export default class BindSite extends Emitter { - dock: Record - - code: string - - constructor() { - super() - - this.dock = {} - this.code = makeCode() - } - - save(name: string, bond: Bind) { - this.dock[name] = bond - this.emit('save', { bond, name }) - } - - read(name: string) { - return this.dock[name] - } - - have(name: string) { - return this.dock.hasOwnProperty(name) - } -} diff --git a/hack/form/look/fill.ts b/hack/form/look/fill.ts deleted file mode 100644 index a0f304e..0000000 --- a/hack/form/look/fill.ts +++ /dev/null @@ -1,336 +0,0 @@ -/* eslint-disable @typescript-eslint/no-explicit-any */ -import Emitter from 'events' -import { Bind } from './bind/index.js' -import BindList from './bind/list.js' -import BindSite from './bind/site.js' -import BindHash from './bind/hash.js' -import Look from './index.js' -import BindSink from './bind/sink.js' - -type SaveHook = { - bond: Bind - name: string -} - -type FillLoad = { - base?: Fill - look: Look - name: string -} - -export default class Fill extends Emitter { - // how many things we've bound - seekSize: number - - // how many things we've resolved - haveSize: number - - takeVibe: boolean - - fill: Record> - - takeFill: Record - - // parent - base?: Fill - - bindTest: Record - - sealVibe: boolean - - look: Look - - name: string - - sort?: string - - constructor({ look, base, name }: FillLoad) { - super() - this.name = name - this.look = look - this.base = base - this.fill = {} - this.seekSize = 0 - this.haveSize = 0 - this.takeVibe = false - this.takeFill = {} - this.bindTest = {} - this.sealVibe = false - this.seekRise() - } - - hold(bond: Bind) { - this.bind(bond) - this.load(bond) - } - - protected bind(bond: Bind) { - if (bond instanceof BindSite && !this.bindTest[bond.code]) { - this.bindSite(bond) - - return - } - - if (bond instanceof BindList && !this.bindTest[bond.code]) { - this.bindList(bond) - - return - } - - if (bond instanceof BindSink && !this.bindTest[bond.code]) { - this.bindSink(bond) - - return - } - - if (bond instanceof BindHash && !this.bindTest[bond.code]) { - this.bindHash(bond) - - return - } - } - - protected load(bond: Bind) { - if (bond instanceof BindSite) { - this.loadSite(bond) - } - - if (bond instanceof BindList) { - this.loadList(bond) - } - - if (bond instanceof BindSink) { - this.loadSink(bond) - } - } - - protected take() { - if (this.takeVibe) { - return - } - - // console.log('take') - // console.log(' ', this.readLink()) - // console.log(' ', 'have:', this.haveSize, 'seek:', this.seekSize) - if (this.haveSize === this.seekSize) { - this.takeVibe = true - this.emit('take') - } - } - - protected bindSite(bond: BindSite) { - this.bindTest[bond.code] = true - - this.sort = 'site' - - bond.on(`save`, ({ name, bond: nestBond }: SaveHook) => { - this.holdLink(bond.code, name, nestBond) - }) - - for (const name in this.look.link) { - this.bindSiteLink(name, bond) - } - - // for (const name in this.look.link) { - // if (bond.have(name)) { - // const link = bond.read(name) - // if (link != null) { - // this.holdLink(bond.code, name, link) - // } - // } - // } - } - - protected bindSiteLink(name: string, bond: BindSite) { - const look = this.look.link[name] - const fillHash = (this.fill[name] ??= {}) - - if (look) { - fillHash[bond.code] ??= new Fill({ - base: this, - look, - name, - }) - // this.seekRise() - } - } - - readLink() { - const link: Array = [] - // eslint-disable-next-line @typescript-eslint/no-this-alias - let seed: Fill | undefined = this - while (seed) { - link.push(seed.name) - seed = seed.base - } - return link.reverse().join('/') - } - - protected bindList(bond: BindList) { - this.seekRise() // for the seal on the list - - this.sort = 'list' - - this.bindTest[bond.code] = true - - bond.on(`save`, (bond: Bind) => { - this.hold(bond) - }) - - bond.on(`seal`, () => { - this.haveRise() - // this.haveRise() - }) - - bond.dock.forEach(bond => { - this.hold(bond) - }) - } - - protected bindSink(bond: BindSink) { - this.bindTest[bond.code] = true - - this.sort = 'sink' - - bond.on(`save`, () => { - this.haveRise() - }) - } - - protected bindHash(bond: BindHash) { - this.bindTest[bond.code] = true - - this.sort = 'hash' - - bond.on(`save`, () => { - this.haveRise() - }) - } - - protected loadSite(bond: BindSite) { - for (const name in this.fill) { - if (bond.have(name)) { - const link = bond.read(name) - if (link != null) { - this.loadLink(bond.code, name, link) - } - } - } - } - - testMeet() { - return this.haveSize === this.seekSize - 1 - } - - protected loadList(bond: BindList) { - if (bond.vibeSeal) { - this.haveRise() - } - bond.dock.forEach(bond => { - this.hold(bond) - }) - } - - protected loadSink(bond: BindSink) { - // console.log( - // 'load sink', - // this.readLink(), - // this.haveSize, - // this.seekSize, - // ) - this.haveRise() - } - - protected loadLink(code: string, name: string, bond: Bind) { - const look = this.look.link[name] - if (!look) { - return - } - - const fillHash = this.fill[name] - - if (!fillHash) { - return - } - - const fill = fillHash[code] - - if (!fill) { - return - } - - fill.hold(bond) - } - - protected holdLink(code: string, name: string, bond: Bind) { - const look = this.look.link[name] - if (!look) { - return - } - - const fillHash = this.fill[name] - - if (!fillHash) { - return - } - - const fill = fillHash[code] - - if (!fill) { - return - } - - fill.hold(bond) - } - - protected seekRise() { - this.seekSize++ - console.log( - 'seekRise ', - this.haveSize, - this.seekSize, - this.readLink(), - ) - // console.log('seekRise') - // console.log(' ', this.readLink()) - // console.log(' ', 'have:', this.haveSize, 'seek:', this.seekSize) - this.base?.seekRise() - } - - protected haveRise() { - // console.log( - // // new Error().stack, - // 'haveRise2', - // this.haveSize, - // this.seekSize, - // this.readLink(), - // this.takeVibe, - // ) - if (this.takeVibe) { - return - } - - this.haveSize++ - - console.log( - // new Error().stack, - 'haveRise', - this.haveSize, - this.seekSize, - this.readLink(), - ) - - this.take() - this.base?.haveRise() - - if (this.haveSize === this.seekSize - 1) { - this.haveRise() - return - } - - // if (this.sort === 'list' && this.haveSize === this.seekSize - 1) { - // console.log('ere') - // this.haveRise() - // } - } -} diff --git a/hack/form/look/index.ts b/hack/form/look/index.ts deleted file mode 100644 index 3d2764d..0000000 --- a/hack/form/look/index.ts +++ /dev/null @@ -1,22 +0,0 @@ -/* eslint-disable @typescript-eslint/no-explicit-any */ - -export default class Look { - link: Record - - testLeaf: boolean - - constructor() { - this.link = {} - this.testLeaf = false - } - - seek(name: string) { - const look = (this.link[name] ??= new Look()) - return look - } - - leaf() { - this.testLeaf = true - return this - } -} diff --git a/hack/form/look/readme.md b/hack/form/look/readme.md deleted file mode 100644 index aa94904..0000000 --- a/hack/form/look/readme.md +++ /dev/null @@ -1,113 +0,0 @@ -```ts -const card = new BindSite() -const fill = new FillCard() - -fill.bind(card) - -const fork = fill.fork() - -fork.waitList('form').wait('name') - -const fork2 = fill.fork() - -fork2.waitList('form').wait('name', 'user') -fork2.hook(() => { - console.log('resolved fork2') -}) - -const userForm = new BindSite({ - name: 'user', -}) - -const formList = new BindList([userForm]) - -card.save('form', formList) -``` - -At first you are working with the card fill. Then once it it is ready, -you take the built card out of it and use that. - -```ts -fork2.waitList('form').wait('name') -fork2.hook(() => { - console.log('resolved fork2') -}) -``` - -At first you don't know how large the list is going to be. The list has -potential items, and then it is called `take` on the bind. It's a -bounded list. Or call it `seal`, to close the list from any more -additions. - -```ts -fork2.wait('form').wait('name') -fork2.take(() => { - console.log('resolved fork2') -}) - -const formList = new BindList([userForm]) - -formList.seal() // say it's ready -``` - -```ts -fork.on('seal', () => { - // do whatever you need to to build the AST further. -}) -``` - -When the objects are ready, then you call `seal` on them to freeze them -from being changed. - -So if you call `.seal()` on a list before all items have been sealed, -then it will wait for all items to be sealed. - -```ts -saveHead // push - -function seal() { - if (this.seedSealSize === this.length) { - this.emit('seal') - } else { - this.vibeSeal = true - } -} -``` - -Or perhaps you don't need that. - -So we have Bind and Fill. The fill is just a tree of watchers, which -watches the bind objects. The bind objects are what we set values on. - -If the bind object is a `BindList`, then we wait for the `seal` event -before saying it's ready. If the bind object is a `BindSite` (an -object), then we wait until we get the `save` event for each field. When -we get the save event, we increment the `takeSize`. Once that equals the -`bindSize`, then we trigger `take` on the `Fill`. Once we get `take` on -the `Fill`, we have all our properties ready to be evaluated. This could -mean adding another fill fork, since we can have interpolated -interpolated properties, etc.. - -We then have a FillBase, which monitors the whole set of packages, the -FillDeck, which monitors the cards, and Fill is the card. - -The BindHash is a hash table. It is what the base and deck use. - ---- - -```ts -const look = new Look() -look.seek('form').seek('name') - -const fill = new Fill(look) - -const hash = new BindSite() -fill.load(hash) - -const formList = new BindList() -const form = new BindSite() -const name = new BindSink('user') -form.save('name', name) -formList.saveHead(form) -hash.save('form', formList) -``` diff --git a/hack/form/look/test.ts b/hack/form/look/test.ts deleted file mode 100644 index f961cfe..0000000 --- a/hack/form/look/test.ts +++ /dev/null @@ -1,66 +0,0 @@ -import Look from './index.js' -import Fill from './fill.js' -import BindSite from './bind/site.js' -import BindList from './bind/list.js' -import BindSink from './bind/sink.js' - -const look = new Look() -const fill = new Fill({ look, name: 'start' }) - -fill.on('take', () => { - console.log('resolved') -}) - -const site = new BindSite() - -look.seek('a').seek('b').seek('c1') -look.seek('a').seek('b').seek('c2') -look.seek('a').seek('b').seek('d').seek('c3') -look.seek('a').seek('x').seek('y') - -fill.hold(site) - -const a = new BindSite() -const b = new BindList() -const b_a = new BindSite() -const b_a_c1 = new BindSink('b_a_c1') -const b_a_c2 = new BindSink('b_a_c2') -const b_a_c3 = new BindSink('b_a_c3') -const b_b = new BindSite() -const b_b_c1 = new BindSink('b_b_c1') -const b_b_c2 = new BindSink('b_b_c2') -const b_b_c3 = new BindSink('b_b_c3') -const b_c = new BindSite() -const b_c_c1 = new BindSink('b_c_c1') -const b_c_c2 = new BindSink('b_c_c2') -const b_c_c3 = new BindSink('b_c_c3') -const x = new BindSite() -const y = new BindSink('y') -const d = new BindList() -const d_a = new BindSite() -const d_a_c3 = new BindSink('d_a_c3') -b_a.save('c1', b_a_c1) -b_a.save('c2', b_a_c2) -// b_a.save('c3', b_a_c3) -b_b.save('c1', b_b_c1) -b_b.save('c2', b_b_c2) -// b_b.save('c3', b_b_c3) -b_c.save('c1', b_c_c1) -b_c.save('c2', b_c_c2) -// b_c.save('c3', b_c_c3) -b.saveHead(b_a) -// b.saveHead(b_b) -// b.saveHead(b_c) -x.save('y', y) -a.save('b', b) -a.save('x', x) -d_a.save('c3', d_a_c3) -d.saveHead(d_a) -d.seal() -b_a.save('d', d) - -site.save('a', a) - -b.seal() - -console.log('done') diff --git a/hack/form/make/index.ts b/hack/form/make/index.ts deleted file mode 100644 index 182a1c1..0000000 --- a/hack/form/make/index.ts +++ /dev/null @@ -1,2 +0,0 @@ - -// compile down to mesh form diff --git a/hack/form/readme.md b/hack/form/readme.md deleted file mode 100644 index 36f3bf4..0000000 --- a/hack/form/readme.md +++ /dev/null @@ -1,203 +0,0 @@ -## Comments - -Comments can be in many ways as `mark`. - - host note-name - text markdown, < - Shortens the vector, keeping the first `len` elements and dropping - the rest. - - If `len` is greater than the vector's current length, this has no - effect. - - The [`drain`] method can emulate `truncate`, but causes the excess - elements to be returned instead of dropped. - - Note that this method has no effect on the allocated capacity - of the vector. - - # Examples - - Truncating a five element vector to two elements: - - ``` - let mut vec = vec![1, 2, 3, 4, 5]; - vec.truncate(2); - assert_eq!(vec, [1, 2]); - ``` - - No truncation occurs when `len` is greater than the vector's current - length: - - ``` - let mut vec = vec![1, 2, 3]; - vec.truncate(8); - assert_eq!(vec, [1, 2, 3]); - ``` - - Truncating when `len == 0` is equivalent to calling the [`clear`] - method. - - ``` - let mut vec = vec![1, 2, 3]; - vec.truncate(0); - assert_eq!(vec, []); - ``` - > - -Can do inline `text` format. - - mark - head 2, - text - like md - -Or even: - - mark md - - -Can mark/flag tasks and such that are: - -- deprecated: `mark toss` -- experimental: `mark test` - -Can have a `read/hint` folder with all the abstracted notes on the tasks -and forms and such. - - load ./foo - find task create-something - find task do-another - - task create-something - note - task do-another - note - -Similar to how you isolate tests from source code. - -Or, import the notes into your source code. - - host create-something - text - - # then in the file - load ./read/task/stuff - find note create-something - - task create-something - note create-something - ---- - - call {{name}} - - form: 'call', - name: LinkKnit | MeshLink (path) | MeshTerm - - {{call}} name - -The non-leaf nodes need to be resolved by compile time. - -As these non-leaf nodes are being interpolated, they spawn tasks to -resolve them when they are complete, and add them to the data model. - - mesh.tree => links to link tree - -Wait on it to resolve. Watches a module for a specific path. If the path -is an array, then it waits until the `done` trigger on the array -children, so it knows it has received all the array elements. - - card.bindingSet() - .waitFor('a') - .waitFor('b') - .waitFor('someArray/*/link/*') - .waitForArray('someArray') - .waitFor('link/name') - .then(() => { - handle() - removeFromBaseById() - }) - card.set('a', 'foo') - card.set('someArray', [{ link: { name: 'bar' } }]) - card.finish('someArray') - -All objects in the AST need to be bindable / emit events. - - // BindingEnvironment - class FillBase { - - } - - class FillDeck { - - } - - class FillFile { - - } - - class FillHook { - - } - - class FillList { - - } - - class FillSite { - - } - -@termsurf/fill-mesh.js - -A Bindable Fulfillment Library for Compiler AST Generation - -So then in mesh.link, it will create a new -FillModule.hook().bind('foo/bar').bindList('form') - -Then it will notify everything that gets attached in the future if it is -complete. - -- if bindings already exist, and we set something and it fulfills the - binding, then trigger. -- if bindings don't exist until after it's been fulfilled, then trigger - immediately - -Then in mesh.link - - // base.ts - class Base { - fill: FillBase - card: Record - task: Array - // env vars - host: Record - } - -base.fill.save('link', cardFill) - -- marked as completely bound (bindHook: true) - - all wired up with required watchers -- list items are is completely added (bindSeed: true) -- mark as completely resolved (bindTake: true) - - watchers are all resolved - -So they have basically a shell. - -So they have basically a shell. The shell is what we are watching for, -and it is filled with Bind objects. So we have the Fill tree and the -Bind tree. - - card.save('deep', deeplyNestedObject) - - fillCard.bind(card) // card is a site - - fillCard.wait('deep').wait('foo') - - deeplyNestedObject.save('foo', 'bar') - -When you save the deeply nested object, it triggers the fill card which -is bound to it, and it marks it off. diff --git a/hack/form/sort/readme.md b/hack/form/sort/readme.md deleted file mode 100644 index fefafec..0000000 --- a/hack/form/sort/readme.md +++ /dev/null @@ -1,214 +0,0 @@ -# TypeChecking and Type Inference - -This section does all the typechecking and inference and borrow checking -and lifetime checking and whatnot. - -Still have a long ways to go to figuring this out. - -- [Type Inference in Rust Compiler](https://rustc-dev-guide.rust-lang.org/type-inference.html) -- https://sdleffler.github.io/RustTypeSystemTuringComplete/ -- http://sinelaw.github.io/infernu.org/s/posts/type-system.html -- https://jaked.org/blog/2021-09-07-Reconstructing-TypeScript-part-0 - -Example: - - function checkFunctionCall(call, fork) { - // check the inputs match the task type - // check the right number of inputs exist - // check the bindings on the call are defined in the fork - } - - function check(ast: Expression, type: Type) { - if (AST.isObjectExpression(ast) && Type.isObject(type)) - return checkObject(ast, type); - - const synthType = synth(ast); - if (!Type.isSubtype(synthType, type)) - err(`expected ${Type.toString(type)}, got ${Type.toString(synthType)}`, ast); - } - -So we need to create a type from the AST nodes. So we have the Mesh -nodes, and the Form nodes (types). Each mesh has a form node. - - make (infer) => construct a form - test (check) => compare mesh to form - take (if it was accepted) - - riff.form (its ast type) - riff.note.take (if it is accepted) - riff.note.form (its runtime type) - riff.note.link (link tree nodes, so we can get back to error handling) - riff.link (properties) - -The riff is the AST node. - -fork (the environment) - -Step through the AST (iterate through the calls), and construct a fork -for each step. Then test that the riff matches the form, or infer it and -then check. - - function testFormForm() { - - } - - function testForm(riff, form) { - for (const name in riff.link) { - - } - } - -Can mark the literals with the final type instantly. - - if (riff.workFormTake && riff.workForm !== form) { - throw halt('invalid_type') - } - -The compile target is just an AST, it's not the actual executable. The -executable is the finally generated code. The AST is a tree structure, -not a graph, so there won't be a problem rendering it. - - riff.base //=> calculate path to notify watchers - - base.hook[line].push(hook) - -Actually we want to add a tree of watchers, so they look up by property -key. - -The interpolated references are used to generate more of the AST? - ---- - -So we have the AST as used by the documentation tool. It goes: - -- link text tree (CST) -- mesh tree (AST), which is a wrapper around link tree - -mesh.text // link tree mesh.link // properties - -The mesh tree is generated from the data. It is modified (modifying the -link text nodes) to change the layout of the code. As we modify the CST, -the meaning of the ranks (position of the code in text) goes away, since -now we have added dynamic elements to it. - -The property `form-code` gives a number for the type, and has `unknown` -type if it is unknown. You can't access the AST for the types at -runtime. The form code is the hash of the module name + form name. - -How to access the form AST then at runtime? - -https://web.mit.edu/rust-lang_v1.25/arch/amd64_ubuntu1404/share/doc/rust/html/book/first-edition/procedural-macros.html - -derive(Insertable) - -You need to - - hook mesh - - user.form.link.forEach - - mesh user - - mesh any # include ast of all types - - form user - mesh true - - save user/email, - -calls - - call user/save, 'email', - -And runs validations based on type. - -No, do the validation elsewhere. - - form user - fuse insertable - - # like a tree/template, except it gives you the captured final AST as well. - mesh insertable - take mesh, like mesh - - hook fuse - task insert - walk mesh/link - - tree insertable - mesh true - - hook fuse - task insert - take mesh, like mesh - take self, like self - walk mesh/link - -Gives you the mesh/AST for each task, after it is complete. - - form user - task insert - take self - mesh true - - walk self/form/link - ... - -If you want the AST for a specific task: - - task insert - mesh true - -If you want the AST for a whole module, just add it at the top level: - - mesh true - -If you want the AST for everything, you can do this in a role file: - - file ./**/*.link - mesh true - - suit insertable - mesh true - - task insert - -The mesh is the _final_ compiled target, which links to the link CST. - -If you want the full AST with the CST, you need to simply parse the file -again at runtime. Or perhaps there is a special `code true` term? - -The code is accessible in mesh, you just read the file with mesh and get -the AST, then match it to the form id. Or do whatever to generate -documentation, or use in the linter. - -So it's like, we call: - - mesh/make-tree - -That gives us the final compiled tree, without typechecking or any of -that. - - mesh/mold-tree - -That does typechecking and type inference. - - mesh/save-js - mesh/save-link - -These take an AST and write the output file. - -That way, the documentation can just call `make-tree` to get an AST -ready for documentation generation. The linter can take the result of -`make-tree` and rewrite some of the AST, to then call `save-link` and -replace some of the file. Or if we want to generate the final js, we can -call `mold-tree` and then `save-js`. - -The `mold-tree` will then do the typechecking. The typechecking is -basically doing symbolic evaluation. - -A test generator can take the typed ast and generate tests based on -constraints somehow. - -The make of the tree uses the mill grammars for the tree, to generate -the structures. diff --git a/hack/form/tool.ts b/hack/form/tool.ts deleted file mode 100644 index 8e4c957..0000000 --- a/hack/form/tool.ts +++ /dev/null @@ -1,3 +0,0 @@ -import * as tool from './tool/index.js' - -export default tool diff --git a/hack/form/tool/dependency.ts b/hack/form/tool/dependency.ts deleted file mode 100644 index fd7645e..0000000 --- a/hack/form/tool/dependency.ts +++ /dev/null @@ -1,307 +0,0 @@ -import { MeshLoad } from '../form' - -export function addDependencyTreeObserver( - load: MeshLoad, - list: Array, -): void { - // list.forEach() -} - -export function canResolveDependencyTree( - load: MeshLoad, - list: Array, -): boolean { - if (list.length === 0) { - return true - } - - const stack = list.concat() - - while (stack.length) { - const observer = stack.shift() - code.assertRecord(observer) - - // we made it back to the base - if (!observer.parent) { - return true - } - - const name = observer.path[0] - code.assertString(name) - - if (code.hasEnvironmentVariable(load.environment, name)) { - if (observer.parent) { - observer.parent.remaining-- - if (observer.parent.remaining === 0) { - stack - } - } - } - } - - return false -} - -export function connectDependency( - parent: SiteDependencyObserverType, - binding: SiteDependencyObserverParentType, - child: SiteDependencyObserverType, -): void { - child.parent = binding - binding.remaining++ - parent.children.push(child) -} - -export function getLeafDependencyList( - tree: SiteDependencyObserverType, - array: Array = [], -): Array { - tree.children.forEach(child => { - if (typeof child === 'object') { - if (!child.children.length) { - array.push(child) - } else { - getLeafDependencyList(child, array) - } - } - }) - return array -} - -export function resolveDynamicPathDependencyTree( - load: MeshLoad, -): SiteDependencyObserverType { - const path = code.assumeLink(load, Link.Path) - - const observer = { - children: [], - node: path, - path: [], - } - - const binding = { - observer, - remaining: 0, - } - - path.segment.forEach((seg, i) => { - if (seg.type === Link.Index) { - code.throwError(code.generateCompilerTodoError()) - } else { - code.connectDependency( - observer, - binding, - resolveTermDependencyTree(code.withLink(load, seg, i)), - ) - } - }) - - return observer -} - -export function resolveDynamicTermDependencyTree( - load: MeshLoad, -): SiteDependencyObserverType { - const term = code.assumeLink(load, Link.Term) - - const observer: SiteDependencyObserverType = { - children: [], - node: term, - path: [], - } - - const binding = { - observer, - remaining: 0, - } - - term.segment.forEach((seg, i) => { - if (seg.type === Link.String) { - observer.children.push(seg.value) - } else { - code.connectDependency( - observer, - binding, - code.resolvePluginDependencyTree(code.withLink(load, seg, i)), - ) - } - }) - - return observer -} - -export function resolvePathDependencyTree( - load: MeshLoad, -): SiteDependencyObserverType { - const type = code.getLinkHint(load) - - switch (type) { - case LinkHint.StaticPath: { - return code.resolveStaticPathDependencyTree(load) - } - case LinkHint.DynamicPath: { - return code.resolveDynamicPathDependencyTree(load) - } - default: - code.throwError(code.generateInvalidCompilerStateError()) - throw new CompilerError() - } -} - -export function resolvePluginDependencyTree( - load: MeshLoad, -): SiteDependencyObserverType { - const nest = load.link.element - - const observer = { - children: [], - node: nest, - path: [], - } - - const binding = { - observer, - remaining: 0, - } - - switch (nest.type) { - case Link.Term: { - code.connectDependency( - observer, - binding, - code.resolveTermDependencyTree(load), - ) - break - } - case Link.Path: { - code.connectDependency( - observer, - binding, - code.resolvePathDependencyTree(load), - ) - break - } - case Link.Tree: { - code.throwError(code.generateCompilerTodoError()) - break - } - default: - code.throwError(code.generateInvalidCompilerStateError()) - } - - return observer -} - -export function resolveStaticPathDependencyTree( - load: MeshLoad, -): SiteDependencyObserverType { - const path = code.assumeLink(load, Link.Path) - - const observer = { - children: [], - node: path, - path: [], - } - - const binding = { - observer, - remaining: 0, - } - - path.segment.forEach((seg, i) => { - if (seg.type === Link.Index) { - code.throwError(code.generateCompilerTodoError()) - } else { - code.connectDependency( - observer, - binding, - resolveTermDependencyTree(code.withLink(load, seg, i)), - ) - } - }) - - return observer -} - -export function resolveStaticTermDependencyTree( - load: MeshLoad, -): SiteDependencyObserverType { - const term = code.assumeLink(load, Link.Term) - const string: Array = [] - - const observer: SiteDependencyObserverType = { - children: [], - node: term, - path: [], - } - - term.segment.forEach((seg, i) => { - if (seg.type === Link.String) { - string.push(seg.value) - } else { - code.throwError(code.generateInvalidCompilerStateError()) - } - }) - - observer.path.push(string.join('')) - - return observer -} - -export function resolveTermDependencyTree( - load: MeshLoad, -): SiteDependencyObserverType { - const type = code.getLinkHint(load) - - switch (type) { - case LinkHint.StaticTerm: { - return code.resolveStaticTermDependencyTree(load) - } - case LinkHint.DynamicTerm: { - return code.resolveDynamicTermDependencyTree(load) - } - default: - code.throwError(code.generateInvalidCompilerStateError()) - throw new CompilerError() - } -} - -export function resolveTextDependencyTree( - load: MeshLoad, -): SiteDependencyObserverType { - const nest = code.assumeLink(load, Link.Text) - - const observer: SiteDependencyObserverType = { - children: [], - node: nest, - path: [], - } - - const binding = { - observer, - remaining: 0, - } - - nest.segment.forEach(seg => { - switch (seg.type) { - case Link.String: - observer.children.push(seg.value) - break - case Link.Plugin: - const childNest = seg.nest[0] - code.assertGenericLink(childNest) - code.connectDependency( - observer, - binding, - code.resolvePluginDependencyTree( - code.withLink(load, childNest, 0), - ), - ) - break - default: - code.throwError(code.generateInvalidCompilerStateError()) - } - }) - - return observer -} diff --git a/hack/form/tool/environment.ts b/hack/form/tool/environment.ts deleted file mode 100644 index e59048d..0000000 --- a/hack/form/tool/environment.ts +++ /dev/null @@ -1,119 +0,0 @@ -import type { SiteEnvironmentType } from '~' -import { Base } from '../form/base.js' - -export function assertEnvironment( - object: unknown, -): asserts object is SiteEnvironmentType { - if (!code.isEnvironment(object)) { - code.throwError( - code.generateObjectNotTypeError(object, ['environment']), - ) - } -} - -export function createBase(): Base { - return new Base() -} - -export function createEnvironment( - bindings: Record, - parent?: SiteEnvironmentType, -): SiteEnvironmentType { - return { - bindings, - isEnv: true, - parent, - } -} - -export function getEnvironmentProperty( - environment: SiteEnvironmentType, - name: string | number | symbol, -): unknown { - let source: SiteEnvironmentType = environment - - while (source) { - if (name in source.bindings) { - return ( - source.bindings as Record - )[name] - } else if (source.parent) { - source = source.parent - } else { - return - } - } -} - -export function getEnvironmentVariable( - base: Base, - key: string, -): unknown { - return base.env[key] -} - -export function hasEnvironmentVariable( - environment: SiteEnvironmentType, - name: string | number | symbol, -): boolean { - let source: SiteEnvironmentType = environment - - while (source) { - if (name in source.bindings) { - return true - } else if (source.parent) { - source = source.parent - } else { - return false - } - } - - return false -} -export function isEnvironment( - object: unknown, -): object is SiteEnvironmentType { - return (object as SiteEnvironmentType).isEnv === true -} - -export function setCachedFile( - base: Base, - path: string, - content: string, -): void { - base.textMap[path] = content -} - -export function setEnvironmentProperty( - scope: SiteEnvironmentType, - property: string, - value: unknown, -): void { - if (property in scope.bindings) { - scope.bindings[property] = value - } else if (scope.parent) { - code.setEnvironmentProperty(scope.parent, property, value) - } else { - code.throwError( - code.generateEnvironmentMissingPropertyError(property), - ) - } -} - -export function setEnvironmentVariable( - base: Base, - key: string, - value: unknown, -): void { - base.env[key] = value -} - -export function withEnvironment( - load: MeshLoad, - bindings: Record, -): SiteProcessInputType { - return { - ...load, - environment: code.createEnvironment(bindings, load.environment), - } -} diff --git a/hack/form/tool/file.ts b/hack/form/tool/file.ts deleted file mode 100644 index 0c1aa15..0000000 --- a/hack/form/tool/file.ts +++ /dev/null @@ -1,66 +0,0 @@ -import fs from 'fs' -import glob from 'glob' -import pathResolver from 'path' -import smc from 'source-map' -import { fileURLToPath } from 'url' - -export const SOURCE_MAP_MESH: Record = {} - -const __filename = fileURLToPath(import.meta.url) - -export const __dirname = pathResolver.dirname(__filename) - -export async function findFilePathsRecursively( - pattern: string, -): Promise> { - return glob.sync(pattern) -} - -export function loadLink(load: MeshLoad, loadPath: string): string { - const card = load.module - const path = code.findPath(loadPath, card.directory) - if (!path) { - code.throwError(code.generateUnresolvedPathError(load, loadPath)) - } - code.assertString(path, 'path') - return path -} - -export function readLinkHost(link: string): string { - return pathResolver.dirname(link) -} - -export function readTextFile(base: Base, link: string): string { - return base.textMap[link] ?? fs.readFileSync(link, 'utf-8') -} - -export function resolveDirectoryPath(path: string): string { - return pathResolver.dirname(path) -} - -export function resolveModulePath( - load: MeshLoad, - text: string, -): string { - const { module } = load - const path = code.findPath(text, module.directory) - - if (!path) { - code.throwError(code.generateUnresolvedPathError(load, text)) - } - - code.assertString(path) - - return path -} - -export function resolveNativePath( - path: string, - context: string, -): string { - const relative = pathResolver.relative( - process.cwd(), - pathResolver.resolve(context, path), - ) - return relative.startsWith('.') ? relative : `./${relative}` -} diff --git a/hack/form/tool/halt.ts b/hack/form/tool/halt.ts deleted file mode 100644 index 42803ff..0000000 --- a/hack/form/tool/halt.ts +++ /dev/null @@ -1,1052 +0,0 @@ -import chalk from 'chalk' -import { diffChars } from 'diff' - -import { - ERROR, - LINK_HINT_TEXT, - Link, - LinkHint, - LinkNodeType, - SOURCE_MAP_MESH, - Text, - code, - prettifyJSON, -} from '~' -import type { - FoldStateInputType, - SiteProcessInputType, - TextSplitInputType, - TextTokenType, -} from '~' - -export class BaseNoteError extends Error { - data: SiteErrorType - - constructor(message: string, data: SiteErrorType) { - super(message) - - this.data = data - } -} - -export class CompilerError extends Error {} - -export type CursorLinePositionType = { - character: number - line: number -} - -export type CursorRangeType = { - end: CursorLinePositionType - start: CursorLinePositionType -} - -export enum ErrorTerm { - CompilationError = 'compilation-error', - CompilerError = 'compiler-error', - SyntaxError = 'syntax-error', - SystemError = 'system-error', -} - -export type SiteErrorConfigType = { - code: string - hint?: string - note: (props: Record) => string - text?: string -} - -const consumers = {} - -export type SiteErrorInputType = Record - -export type SiteErrorType = { - code: string - file?: string - hint?: string - note: string - term?: Array - text?: string -} - -export type SiteStackTraceType = { - character?: number - file: string - function?: string - line?: number -} - -export class TypescriptError extends Error {} - -export function assertError( - error: unknown, -): asserts error is SiteErrorConfigType { - if (!code.isError(error)) { - throw new Error('Error handler undefined') - } -} - -export function buildErrorMessage(data: SiteErrorType): Array { - const text: Array = [] - - text.push(``) - text.push( - chalk.gray(` note <`) + - chalk.whiteBright(`${data.note}`) + - chalk.gray('>'), - ) - - if (data.hint) { - text.push( - chalk.gray(` hint <`) + - chalk.whiteBright(`${data.hint}`) + - chalk.gray('>'), - ) - } - - data.term?.forEach(term => { - text.push(chalk.gray(` term `) + chalk.white(`${term}`)) - }) - - text.push(chalk.gray(` code `) + chalk.white(`#${data.code}`)) - - if (data.file) { - if (data.text) { - text.push( - chalk.gray(` file <`) + - chalk.whiteBright(`${data.file}`) + - chalk.gray(`>, <`), - ) - data.text.split('\n').forEach(line => { - text.push(` ${line}`) - }) - text.push(chalk.gray(` >`)) - } else { - text.push( - chalk.gray(` file <`) + - chalk.whiteBright(`${data.file}`) + - chalk.gray(`>`), - ) - } - } else if (data.text) { - text.push(chalk.gray(` text <`)) - data.text.split('\n').forEach(line => { - text.push(` ${line}`) - }) - text.push(chalk.gray(' >')) - } - - return text -} - -export function createDefaultRange(): CursorRangeType { - return { - end: { - character: 0, - line: 0, - }, - start: { - character: 0, - line: 0, - }, - } -} - -export function generateChangeVariableTypeError( - load: MeshLoad, -): SiteErrorType { - return { - code: '0031', - note: `Attempt to change a variable's type.`, - } -} - -export function generateCompilerTodoError( - hint?: string, -): SiteErrorType { - return { - code: `0029`, - hint: [ - `This part of the compiler is unfinished, see the stack trace for where to modify code.`, - hint, - ] - .filter(x => x) - .join(' '), - note: `Compiler TODO`, - term: [ErrorTerm.CompilerError], - } -} - -export function generateEnvironmentMissingPropertyError( - property: string, -): SiteErrorType { - return { - code: '0019', - note: `Environment is missing property ${property}.`, - } -} - -export function generateForkMissingPropertyError( - property: string, -): SiteErrorType { - return { - code: `0010`, - note: `Scope is missing property '${property}'.`, - } -} - -export function generateHighlightedError( - textByLine: Array, - highlight: CursorRangeType, -): string { - const endLine = Math.min( - highlight.start.line + 2, - textByLine.length - 1, - ) - const endLineString = textByLine[endLine] - code.assertString(endLineString) - const endCharacter = endLineString.length - 1 - const boundedRange: CursorRangeType = { - end: { - character: endCharacter, - line: endLine, - }, - start: { - character: 0, - line: Math.max(0, highlight.start.line - 2), - }, - } - - const text = highlightTextRangeForError( - boundedRange, - textByLine, - highlight, - ) - - return text -} - -export function generateHighlightedErrorForLinkTree( - load: MeshLoad, -): string { - const highlightedRange = code.getCursorRangeForTree(load) - return code.generateHighlightedError( - load.module.textByLine, - highlightedRange, - ) -} - -export function generateHighlightedErrorForText( - load: MeshLoad, -): string { - const highlightedRange = code.getCursorRangeForText(load) - return code.generateHighlightedError( - load.module.textByLine, - highlightedRange, - ) -} - -export function generateIncorrectlyTypedVariable( - type: string | Array, - name?: string, - path?: string, -): SiteErrorType { - type = Array.isArray(type) ? type : [type] - const words = - type.length > 1 - ? type - .slice(-1) - .map(x => `\`${x}\``) - .join(', ') + ` or \`${type[type.length - 1]}\`` - : `\`${type[0]}\`` - const text = name ? ` \`${name}\`` : '' - return { - code: `0027`, - file: path, - note: `Variable${text} is not typed as a ${words}.`, - } -} - -export function generateInvalidCompilerStateError( - hint?: string, - path?: string, -): SiteErrorType { - return { - code: `0028`, - file: path, - hint: [ - hint, - `This is some bug with the budding compiler. Check the stack trace to see where the error occurred.`, - ] - .filter(x => x) - .join(' '), - note: `Invalid compiler state`, - } -} - -export function generateInvalidDeckLink( - load: MeshLoad, - link: string, -): SiteErrorType { - return { - code: `0008`, - note: `Invalid deck link '${link}'.`, - } -} - -export function generateInvalidNestCaseError( - load: MeshLoad, - type: LinkHint, -): SiteErrorType { - let scope - try { - scope = code.resolveTermString(load) - } catch (e) {} - const text = code.generateHighlightedErrorForLinkTree(load) - return { - code: `0032`, - file: `${load.module.path}`, - note: `The "${LINK_HINT_TEXT[type]}" elements are invalid in this context.`, - text, - } -} - -export function generateInvalidNestChildrenLengthError( - load: MeshLoad, - length: number, -): SiteErrorType { - return { - code: `0009`, - note: `Term doesn't have ${length} children.`, - } -} - -// export function generateInvalidPatternError( -// load: MeshLoad, -// pattern: unknown, -// ): SiteErrorType { -// const { module } = load -// const nest = code.assumeLink(load) -// const text = code.generateHighlightedErrorForText(load) -// return { -// code: `0012`, -// file: `${module.path}`, -// note: `Text does not match pattern ${pattern}.`, -// text: text, -// } -// } - -export function generateInvalidWhitespaceError( - load: FoldStateInputType, -): SiteErrorType { - const token = load.tokenList[load.state.index] - code.assertTextGenericType(token) - const highlightedRange = code.getCursorRangeForTextWhitespaceToken( - token, - load, - ) - const text = code.generateHighlightedError( - load.textByLine, - highlightedRange, - ) - - return { - code: '0027', - file: load.path, - note: `Invalid whitespace`, - text, - } -} - -export function generateModuleUnresolvableError( - load: MeshLoad, -): SiteErrorType { - return { - code: '0020', - file: `${load.module.path}`, - note: `Module has unresolvable references`, - } -} - -export function generateObjectNotTypeError( - object: unknown, - type: Array, -): SiteErrorType { - const words = - type.length > 1 - ? type - .slice(-1) - .map(x => `\`${x}\``) - .join(', ') + ` or \`${type[-1]}\`` - : `\`${type[0]}\`` - return { - code: `0007`, - note: `Object isn't type ${words}.`, - text: object == null ? String(object) : prettifyJSON(object), - } -} - -export function generateStringMismatchError( - load: TextSplitInputType, - a: string, - b: string, -): SiteErrorType { - return { - code: '0030', - file: load.path, - note: 'String mismatch error', - text: code.renderDiffText(a, b), - } -} - -export function generateSyntaxTokenError( - load: TextSplitInputType, - lastToken?: TextTokenType, -): SiteErrorType { - const highlight: CursorRangeType = { - end: { - character: 0, - line: 0, - }, - start: { - character: 0, - line: 0, - }, - } - - if (lastToken) { - highlight.start.line = lastToken.range.line.start - highlight.end.line = lastToken.range.line.end - highlight.start.character = lastToken.range.character.start - highlight.end.character = lastToken.range.character.end - } - - const text = code.generateHighlightedError(load.textByLine, highlight) - - return { - code: `0021`, - note: `Error in the structure of the text tree.`, - text, - } -} - -export function generateTermMissingChildError(): void {} - -export function generateTermMissingError( - load: MeshLoad, - type: string, - object: string, -): SiteErrorType { - const { module } = load - return { - code: `0018`, - file: `${module.path}`, - note: `Term ${type} is missing on ${object}.`, - text: '', - } -} - -export function generateUnhandledNestCaseBaseError( - load: MeshLoad, -): SiteErrorType { - const { module } = load - const text = code.generateHighlightedErrorForLinkTree(load) - return { - code: `0005`, - file: `${module.path}`, - note: `We haven't implemented handling this type of nest yet.`, - text, - } -} - -export function generateUnhandledNestCaseError( - load: MeshLoad, - type: LinkHint, -): SiteErrorType { - let scope - try { - // scope = code.resolveTermString(load, 1) - scope = code.resolveTermString(load) - } catch (e) {} - const text = code.generateHighlightedErrorForLinkTree(load) - return { - code: `0004`, - file: `${load.module.path}`, - note: `We haven't implemented handling "${ - LINK_HINT_TEXT[type] - }s" yet${scope ? ` on \`${scope}\`` : ''}.`, - text, - } -} - -export function generateUnhandledTermCaseError( - load: MeshLoad, -): SiteErrorType { - let scope - try { - // scope = code.resolveTermString(load, 1) - scope = code.resolveTermString(load) - } catch (e) {} - const name = code.resolveTermString(load) - code.assertString(name) - const handle = ERROR['0002'] - code.assertError(handle) - const text = code.generateHighlightedErrorForLinkTree(load) - return { - code: `0002`, - file: `${load.module.path}`, - note: handle.note({ name, scope }), - term: [ErrorTerm.CompilerError], - text, - } -} - -export function generateUnhandledTermInterpolationError( - load: MeshLoad, -): SiteErrorType { - return { - code: `0001`, - file: `${load.module.path}`, - note: `We haven't implemented handling term interpolation yet.`, - text: '', - } -} - -export function generateUnknownTermError( - load: MeshLoad, -): SiteErrorType { - const { module } = load - const name = code.resolveTermString(load) - const text = code.generateHighlightedErrorForLinkTree(load) - // const insideName = code.resolveTermString(load, 1) - const insideName = code.resolveTermString(load) - return { - code: `0003`, - file: `${module.path}`, - note: `Unknown term \`${name}\`${ - insideName ? ` inside \`${insideName}\`` : '' - }.`, - text: text, - } -} - -export function generateUnresolvedPathError( - load: MeshLoad, - path: string, -): SiteErrorType { - const { module } = load - return { - code: `0013`, - file: module.path, - note: `File not found ${path}.`, - } -} - -export function generatedNotImplementedYetError( - name?: string, - path?: string, -): SiteErrorType { - return { - code: '0024', - file: path, - note: `We have not yet implemented ${ - name ? `${name}` : 'something you referenced' - }.`, - term: [ErrorTerm.CompilerError], - } -} - -export function getCursorRangeForPath(load: MeshLoad): CursorRangeType { - const path = code.assumeLink(load, Link.Path) - const firstSegment = path.segment[0] as LinkNodeType - const lastSegment = path.segment[ - path.segment.length - 1 - ] as LinkNodeType - const start = getCursorRangeForTerm(code.withLink(load, firstSegment)) - const end = getCursorRangeForTerm(code.withLink(load, lastSegment)) - const range: CursorRangeType = { - end: { - character: end.end.character, - line: end.end.line, - }, - start: { - character: start.start.character, - line: start.start.line, - }, - } - return range -} - -export function getCursorRangeForPlugin( - load: MeshLoad, -): CursorRangeType { - const nest = code.assumeLink(load, Link.Plugin) - const child = nest.nest[0] - - switch (child?.type) { - case Link.Term: { - return code.getCursorRangeForTerm(code.withLink(load, nest)) - } - case Link.Path: { - return code.getCursorRangeForPath(code.withLink(load, nest)) - } - case Link.Tree: { - return code.getCursorRangeForTree(code.withLink(load, nest)) - } - default: - code.throwError(code.generateInvalidCompilerStateError()) - throw new CompilerError() - } -} - -export function getCursorRangeForString( - load: MeshLoad, -): CursorRangeType { - const string = code.assumeLink(load, Link.String) - - return { - end: { - character: string.range.character.end, - line: string.range.line.end, - }, - start: { - character: string.range.character.start, - line: string.range.line.start, - }, - } -} - -export function getCursorRangeForTerm(load: MeshLoad): CursorRangeType { - const term = code.assumeLink(load, Link.Term) - const range: CursorRangeType = createDefaultRange() - - const start = term.segment[0] - const end = term.segment[term.segment.length - 1] - - if (!start || start.type !== Link.String) { - return range - } - - if (!end || end.type !== Link.String) { - return range - } - - range.end.character = end.range.character.end - range.end.line = end.range.line.end - - range.start.character = start.range.character.start - range.start.line = start.range.line.start - - return range -} - -export function getCursorRangeForText(load: MeshLoad): CursorRangeType { - const nest = code.assumeLink(load, Link.Text) - - const range: CursorRangeType = { - end: { - character: 0, - line: 0, - }, - start: { - character: 0, - line: 0, - }, - } - - const first = nest.segment[0] - const last = nest.segment[nest.segment.length - 1] - - code.assertGenericLink(first) - code.assertGenericLink(last) - - let firstRange: CursorRangeType - - if (first.type === Link.String) { - firstRange = code.getCursorRangeForString( - code.withLink(load, first), - ) - } else if (first.type === Link.Plugin) { - firstRange = code.getCursorRangeForPlugin( - code.withLink(load, first), - ) - } else { - code.throwError(code.generateInvalidCompilerStateError()) - throw new CompilerError() - } - - if (firstRange) { - range.start.line = firstRange.start.line - range.start.character = firstRange.start.character - range.end.line = firstRange.end.line - range.end.character = firstRange.end.character - } - - let lastRange: CursorRangeType - - if (last.type === Link.String) { - lastRange = code.getCursorRangeForString(code.withLink(load, last)) - } else if (last.type === Link.Plugin) { - lastRange = code.getCursorRangeForPlugin(code.withLink(load, last)) - } else { - code.throwError(code.generateInvalidCompilerStateError()) - throw new CompilerError() - } - - if (lastRange) { - range.end.line = lastRange.end.line - range.end.character = lastRange.end.character - } - - return range -} - -export function getCursorRangeForTextWhitespaceToken( - token: TextTokenType, - load: FoldStateInputType, -): CursorRangeType { - let tokens: Array> = [] - let i = load.state.index - - loop: while (i < load.tokenList.length) { - let t = load.tokenList[i] - code.assertTextGenericType(t) - switch (t.type) { - case Text.OpenIndentation: - case Text.OpenNesting: - tokens.push(t) - break - default: - break loop - } - i++ - } - - const start = tokens[0] - const end = tokens[tokens.length - 1] - - code.assertTextGenericType(start) - code.assertTextGenericType(end) - - return { - end: { - character: end.range.character.end, - line: end.range.line.end, - }, - start: { - character: start.range.character.start, - line: start.range.line.start, - }, - } -} - -export function getCursorRangeForTree(load: MeshLoad): CursorRangeType { - // console.log(load) - const nest = load.link.element - - switch (nest.type) { - case Link.Tree: { - const term = nest.head - if (!term) { - code.throwError(code.generateInvalidCompilerStateError()) - throw new CompilerError() - } - - return getCursorRangeForTerm(code.withLink(load, term)) - } - case Link.Path: { - return getCursorRangeForPath(load) - } - case Link.Term: { - return getCursorRangeForTerm(load) - } - default: - code.throwError(code.generateInvalidCompilerStateError()) - throw new CompilerError() - } -} - -export function getSourceMappedFile( - path: string, - line: number, - character: number, -): [string, number | undefined, number | undefined] { - const map = SOURCE_MAP_MESH[path] - - const trace = { - column: character, - filename: path, - line: line, - } - - if (map) { - const token = map.originalPositionFor(trace) - if (token.source) { - return [ - code.resolveNativePath( - token.source, - code.resolveDirectoryPath(path.replace(/^file:\/\//, '')), - ), - token.line == null ? undefined : token.line, - token.column == null ? undefined : token.column, - ] - } else { - return [path, line, character] - } - } else { - return [path, line, character] - } -} - -export function highlightTextRangeForError( - bound: CursorRangeType, - textByLine: Array, - highlight: CursorRangeType, -): string { - const lines: Array = [] - let i = bound.start.line - let n = bound.end.line - let pad = String(n + 1).length - const defaultIndent = new Array(pad + 1).join(' ') - lines.push(chalk.white(`${defaultIndent} |`)) - while (i <= n) { - const lineText = textByLine[i] - const x = i + 1 - let z = - i < textByLine.length - ? x.toString().padStart(pad, ' ') - : defaultIndent - if (highlight.start.line === i) { - lines.push(chalk.whiteBright(`${z} | ${lineText}`)) - const indentA = new Array(z.length + 1).join(' ') - const indentB = new Array(highlight.start.character + 1).join(' ') - const squiggly = new Array( - highlight.end.character - highlight.start.character + 1, - ).join('~') - lines.push( - chalk.white(`${indentA} | ${indentB}`) + - chalk.red(`${squiggly}`), - ) - } else { - lines.push(chalk.white(`${z} | ${lineText}`)) - } - i++ - } - - lines.push(chalk.white(`${defaultIndent} |`)) - - return lines.join('\n') -} - -export function isError(error: unknown): error is SiteErrorConfigType { - return ( - code.isRecord(error) && Boolean((error as SiteErrorConfigType).code) - ) -} - -export function parseStackLine(text: string) { - const [a, b] = text.trim().split(/\s+/) - code.assertString(a) - if (!b) { - return parseStackLineFileOnly(a) - } else { - return { - ...parseStackLineFileOnly(b), - function: a, - } - } -} - -export function parseStackLineFileOnly( - text: string, -): SiteStackTraceType { - const parts = text.replace(/[\(\)]/g, '').split(':') - const character = parts.pop() - let characterN = character ? parseInt(character, 10) : undefined - const line = parts.pop() - let lineN = line ? parseInt(line, 10) : undefined - let file = parts.join(':') - if (code.isNumber(lineN) && code.isNumber(characterN)) { - ;[file, lineN, characterN] = getSourceMappedFile( - file, - lineN, - characterN, - ) - } - return { - character: characterN, - file, - line: lineN, - } -} - -export function parseTapStackTrace( - stack: string, -): Array { - return stack - .trim() - .split(/\n+/) - .map(line => { - const [a, b] = line.trim().split(/\s+/) - code.assertString(a) - if (!b) { - return parseStackLineFileOnly(a) - } else { - return { - ...parseStackLineFileOnly(b), - function: a, - } - } - }) -} - -export function renderDiffText(a: string, b: string): string { - const text: Array = [] - const diff = diffChars(a, b) - - diff.forEach(part => { - const value = part.value.replace(/ /g, '◌') - if (part.added) { - text.push(chalk.green(value)) - } else if (part.removed) { - text.push(chalk.red(value)) - } else { - text.push(chalk.gray(value)) - } - }) - - return text.join('') -} - -export function renderError(stackTrace: string): Array { - const messageLine: Array = [] - const stack: Array = [] - const parts = stackTrace.trim().split(/\n+/) - - let intoMessage = false - let i = parts.length - 1 - while (i >= 0) { - const line = parts[i--] - if (!intoMessage && line?.startsWith(' at ')) { - stack.push(code.parseStackLine(line.slice(' at '.length))) - } else if (line) { - intoMessage = true - messageLine.push(line) - } - } - - const errorText = code.buildErrorMessage({ - code: '0031', - note: messageLine.reverse().join('\n'), - term: [ErrorTerm.SystemError], - }) - - code.renderStackTrace(stack.reverse()).forEach(line => { - errorText.push(` ${line}`) - }) - - errorText.push('') - - return errorText -} - -export function renderStackTrace( - stack: Array, -): Array { - const g = chalk.gray - const w = chalk.white - const bw = chalk.whiteBright - const text: Array = [] - stack.forEach(node => { - let suffix = [] - if (node.line) { - suffix.push(node.line) - } - if (node.character) { - suffix.push(node.character) - } - - const end = suffix.length ? ':' + suffix.join(':') : '' - text.push( - `${g(`site ${g('<')}`)}${bw(`${node.file}${end}`)}${g('>')}`, - ) - if (node.function) { - text.push(`${g(` call ${g('<')}${w(node.function)}${g('>')}`)}`) - } - }) - return text -} - -export function throwError(data: SiteErrorType): void { - const text = code.buildErrorMessage(data) - text.push(``) - - // Error.stackTraceLimit = Infinity - - const prepareStackTrace = Error.prepareStackTrace - - Error.prepareStackTrace = function prepareStackTrace( - error: Error, - stack: Array, - ): string { - return ( - error.message + - chalk.gray(' list base\n') + - stack - .slice(1) - .map((site: NodeJS.CallSite) => { - let x = site.getFileName() - let a: number | null | undefined = site.getLineNumber() - let b: number | null | undefined = site.getColumnNumber() - - if ( - x && - code.isNumber(a) && - code.isNumber(b) && - code.isString(x) - ) { - ;[x, a, b] = getSourceMappedFile(x, a, b) - } - let m = site.getMethodName()?.trim() - let f = site.getFunctionName()?.trim() - let t = site.getTypeName()?.trim() - let label = m - ? [t, m].join('.') - : t - ? [t, f].join('.') - : f || '[anonymous]' - label = label ? label : '' - const lastLines: Array = [] - if (x) { - lastLines.push( - chalk.gray(' site <') + - chalk.whiteBright([x, a, b].filter(x => x).join(':')) + - chalk.gray('>'), - ) - } else { - lastLines.push(chalk.gray(' site ')) - } - - lastLines.push( - chalk.gray(' call <') + - chalk.white(label) + - chalk.gray('>'), - ) - - return lastLines.join('\n') - }) - .join('\n') + - '\n' - ) - } - - const error = new BaseNoteError(text.join('\n'), data) - error.name = '' - - Error.captureStackTrace(error) - - error.stack - - Error.prepareStackTrace = prepareStackTrace - - throw error -} diff --git a/hack/form/tool/index.ts b/hack/form/tool/index.ts deleted file mode 100644 index 6f25a84..0000000 --- a/hack/form/tool/index.ts +++ /dev/null @@ -1,9 +0,0 @@ -export * from './dependency.js' -export * from './environment.js' -export * from './file.js' -export * from './halt.js' -export * from './module.js' -export * from './nest.js' -export * from './observer.js' -export * from './task.js' -export * from './text.js' diff --git a/hack/form/tool/load/error-handler.ts b/hack/form/tool/load/error-handler.ts deleted file mode 100644 index 0dbaf0d..0000000 --- a/hack/form/tool/load/error-handler.ts +++ /dev/null @@ -1,25 +0,0 @@ -export function watchUnhandledErrors(): void { - process.on('unhandledRejection', (reason: unknown) => { - if (reason instanceof BaseNoteError) { - console.log(reason.stack) - } else if ( - reason instanceof Error && - 'stack' in reason && - code.isString(reason.stack) - ) { - const text = code.renderError(reason.stack) - console.log(text.join('\n')) - } else { - console.log(reason) - } - }) - - process.on('uncaughtException', (error: Error) => { - if (code.isString(error.stack)) { - const text = code.renderError(error.stack) - console.log(text.join('\n')) - } else { - console.log(error.message ?? error) - } - }) -} diff --git a/hack/form/tool/load/index.ts b/hack/form/tool/load/index.ts deleted file mode 100644 index f5e597c..0000000 --- a/hack/form/tool/load/index.ts +++ /dev/null @@ -1,5 +0,0 @@ -import { watchUnhandledErrors } from './error-handler.js' - -export * from './error-handler.js' - -watchUnhandledErrors() diff --git a/hack/form/tool/module.ts b/hack/form/tool/module.ts deleted file mode 100644 index 211fe35..0000000 --- a/hack/form/tool/module.ts +++ /dev/null @@ -1,38 +0,0 @@ -import { - Base, - BaseCard, - SiteModuleBaseType, - SiteModuleType, - SiteCardCode, - code, -} from '~' - -export function assertModule( - object: unknown, -): asserts object is SiteModuleType { - if (!code.isModule(object)) { - code.throwError(code.generateObjectNotTypeError(object, ['module'])) - } -} - -export function hasModuleInitialized(module: BaseCard): boolean { - return Object.keys(module.seed).length > 0 -} - -export function isModule(object: unknown): object is SiteModuleType { - return (object as SiteModuleType).isModule === true -} - -export function loadLinkModule(base: Base, path: string): SiteCardCode { - const text = code.readTextFile(base, path) - const data = code.parseLinkText({ path, text }) - const directory = code.getLinkHost(path) - return { - directory, - ...data, - } -} - -export function testHaveCard(base: Base, path: string): boolean { - return path in base.cardsByPath -} diff --git a/hack/form/tool/nest.ts b/hack/form/tool/nest.ts deleted file mode 100644 index 1550fab..0000000 --- a/hack/form/tool/nest.ts +++ /dev/null @@ -1,103 +0,0 @@ -import type { SiteProcessInputType } from '~' - -export function assumeLinkIndex(load: MeshLoad): number { - const index = load.link.index - code.assertNumber(index) - return index -} - -export function getLinkHint(load: MeshLoad): LinkHint { - if (code.nestIsTerm(load)) { - if (code.termIsInterpolated(load)) { - return LinkHint.DynamicTerm - } else { - return LinkHint.StaticTerm - } - } else if (code.nestIsPath(load)) { - if (code.pathIsInterpolated(load)) { - return LinkHint.DynamicPath - } else { - return LinkHint.StaticPath - } - } else if (code.nestIsText(load)) { - if (code.textIsInterpolated(load)) { - return LinkHint.DynamicText - } else { - return LinkHint.StaticText - } - } else if (code.nestIsUnsignedInteger(load)) { - return LinkHint.Mark - } else if (code.nestIsHashtag(load)) { - return LinkHint.Code - } else { - code.throwError(code.generateUnhandledNestCaseBaseError(load)) - } - - return LinkHint.Empty -} - -export function nestIsHashtag(load: MeshLoad): boolean { - const nest = load.link.element - - return nest.type === Link.Hashtag -} - -export function nestIsPath(load: MeshLoad): boolean { - const nest = load.link.element - - return nest.type === Link.Path -} - -export function nestIsTerm(load: MeshLoad): boolean { - const nest = load.link.element - - if (nest.type === Link.Term) { - return true - } - - if (nest.type !== Link.Tree) { - return false - } - - const child = nest.head - if (!child) { - return false - } - - if (child.type !== Link.Term) { - return false - } - - return true -} - -export function nestIsText(load: MeshLoad): boolean { - const nest = load.link.element - - return nest.type === Link.Text -} - -export function nestIsUnsignedInteger(load: MeshLoad): boolean { - const nest = load.link.element - - return nest.type === Link.UnsignedInteger -} - -export function pathIsInterpolated(load: MeshLoad): boolean { - const nest = load.link.element - - if (nest.type !== Link.Path) { - return false - } - - for (const seg of nest.segment) { - if (seg.type === Link.Index) { - return true - } - if (code.termIsInterpolatedImpl(seg)) { - return true - } - } - - return false -} diff --git a/hack/form/tool/observer.ts b/hack/form/tool/observer.ts deleted file mode 100644 index ff7f5bb..0000000 --- a/hack/form/tool/observer.ts +++ /dev/null @@ -1,470 +0,0 @@ -import { - BlueMapType, - BlueNodeType, - BluePossibleType, - BlueType, - Mesh, - SITE_OBSERVER_COMPLETE_STATE, - SITE_OBSERVER_STATE, - SiteModuleBindingInputType, - SiteObjectWatcherHandleType, - SiteObjectWatcherPropertiesType, - SiteObjectWatcherPropertyType, - SiteObjectWatcherSchemaPropertyType, - SiteObjectWatcherSchemaType, - SiteObjectWatcherType, - SiteObserverState, - code, -} from '~' -import type { SiteProcessInputType } from '~' - -export function bindSchema( - load: SiteModuleBindingInputType, - schema: SiteObjectWatcherSchemaType, -): void { - const watcher = code.registerSchema(load, schema) - code.updateAllThroughWatcher(load, watcher) -} - -export function createCodeModuleObjectNameObserverSchema( - property: string, - handle: SiteObjectWatcherHandleType, -): SiteObjectWatcherSchemaType { - return { - properties: { - definitions: { - properties: { - public: { - properties: { - [property]: { - properties: { - ['*']: { - handle, - properties: { - name: { - state: [SiteObserverState.RuntimeComplete], - }, - }, - state: SITE_OBSERVER_STATE, - }, - }, - state: SITE_OBSERVER_STATE, - }, - }, - state: SITE_OBSERVER_STATE, - }, - }, - state: SITE_OBSERVER_STATE, - }, - }, - } -} - -export function createCodeModulePublicCollectionObserverSchema( - property: string, - handle: SiteObjectWatcherHandleType, -): SiteObjectWatcherSchemaType { - return { - properties: { - definitions: { - properties: { - public: { - properties: { - [property]: { - handle, - state: [SiteObserverState.CollectionGathered], - }, - }, - state: SITE_OBSERVER_STATE, - }, - }, - state: SITE_OBSERVER_STATE, - }, - }, - } -} - -export function createWatcherFromSchema( - schema: SiteObjectWatcherSchemaType, -): SiteObjectWatcherType { - const watcher: SiteObjectWatcherType = { - properties: {}, - } - - Object.keys(schema.properties).forEach(name => { - const property = schema.properties[ - name - ] as SiteObjectWatcherPropertyType - - watcher.properties[name] = code.createWatcherFromSchemaProperty( - property, - name, - ) - }) - - return watcher -} - -export function createWatcherFromSchemaProperty( - property: SiteObjectWatcherSchemaPropertyType, - name: string, - parent?: SiteObjectWatcherPropertyType, - pending = 1, -): SiteObjectWatcherPropertyType { - const watcher: SiteObjectWatcherPropertyType = { - counted: true, - handle: property.handle, - matched: false, - name, - pending, - state: property.state, - } - - const isDynamic = name === '*' - - Object.defineProperty(watcher, 'parent', { - enumerable: false, - value: parent, - }) - - Object.defineProperty(watcher, 'node', { - enumerable: false, - value: undefined, - writable: true, - }) - - let higher = parent - while (higher) { - higher.pending += pending - higher = higher.parent - } - - const propertyProperties = property.properties - - if (propertyProperties) { - const nestedProperties: SiteObjectWatcherPropertiesType = {} - - Object.keys(propertyProperties).forEach(name => { - const child = propertyProperties[ - name - ] as SiteObjectWatcherPropertyType - - const isChildDynamic = name === '*' - - nestedProperties[name] = createWatcherFromSchemaProperty( - child, - name, - isDynamic ? undefined : watcher, - isDynamic ? 0 : 1, - ) - }) - - if (isDynamic) { - watcher.dynamicProperties = nestedProperties - watcher.properties = {} - } else { - watcher.properties = nestedProperties - } - } - - return watcher -} - -export function extendDynamicPropertyWatcher( - load: MeshLoad, - watcher: SiteObjectWatcherPropertyType, - name: string, -): SiteObjectWatcherPropertyType { - const { dynamicProperties } = watcher - code.assertRecord(dynamicProperties) - - const childWatcher: SiteObjectWatcherPropertyType = { - counted: false, - matched: false, - name, - parent: watcher, - pending: 0, - state: [], - } - - const nestedProperties: Record< - string, - SiteObjectWatcherPropertyType - > = {} - - Object.keys(dynamicProperties).forEach(name => { - const child = dynamicProperties[ - name - ] as SiteObjectWatcherPropertyType - - nestedProperties[name] = createWatcherFromSchemaProperty( - child, - name, - childWatcher, - ) - }) - - childWatcher.properties = nestedProperties - - const { properties } = watcher - - code.assertRecord(properties) - - properties[name] = childWatcher - - return childWatcher -} - -export function isObserverStateAccepted( - load: SiteObserverState, - potential: Array, -): boolean { - if (potential.includes(SiteObserverState.CollectionGathered)) { - return load === SiteObserverState.CollectionGathered - } - - if (potential.includes(SiteObserverState.Initialized)) { - return SITE_OBSERVER_STATE.includes(load) - } - - if (potential.includes(SiteObserverState.StaticComplete)) { - return SITE_OBSERVER_COMPLETE_STATE.includes(load) - } - - if (potential.includes(SiteObserverState.RuntimeComplete)) { - return load === SiteObserverState.RuntimeComplete - } - - return false -} - -export function propagatePendingUpwards( - property: SiteObjectWatcherPropertyType, - amount: number, -): void { - let higher: SiteObjectWatcherPropertyType | undefined = property - - while (higher) { - higher.pending += amount - higher = higher.parent - } -} - -export function queuePropertyUpdateHandle( - load: MeshLoad, - handle: SiteObjectWatcherHandleType, - node: BlueNodeType, -): void { - code.addTask(load.base, () => handle(node)) -} - -export function registerSchema( - load: SiteModuleBindingInputType, - schema: SiteObjectWatcherSchemaType, -): SiteObjectWatcherType { - let list = load.base.watchers[load.moduleId] - - if (!list) { - list = load.base.watchers[load.moduleId] = [] - } - - const watcher = code.createWatcherFromSchema(schema) - - list.push(watcher) - - return watcher -} - -export function resolveBluePath( - blue: BlueNodeType, -): Array> { - let node: BlueNodeType | undefined = blue - const array: Array> = [] - while (node) { - array.push(node) - node = node.parent - } - return array.reverse() -} - -export function triggerObjectBindingUpdate( - load: MeshLoad, - node: BlueNodeType, -): void { - const watchers = load.base.watchers[load.module.id] - - if (!watchers) { - return - } - - const path = code.resolveBluePath(node) - watchers.forEach(watcher => { - code.updateWatcherForPath(load, watcher, path) - }) -} - -export function updateAllThroughWatcher( - load: SiteModuleBindingInputType, - watcher: SiteObjectWatcherType, -): void { - let node = load.module.blue.node as BlueMapType< - Record - > - - for (const name in watcher.properties) { - const property = watcher.properties[ - name - ] as SiteObjectWatcherPropertyType - - let child = node.value[name] as BlueType - - code.updateAllThroughWatcherProperty(load, property, child) - } - - // console.log(JSON.stringify(watcher, null, 2)) -} - -export function updateAllThroughWatcherProperty( - load: SiteModuleBindingInputType, - property: SiteObjectWatcherPropertyType, - node: Record, -): void { - code.assertGenericBlue(node) - - if (code.isObserverStateAccepted(node.state, property.state)) { - property.matched = true - code.propagatePendingUpwards(property, -1) - } - - property.node = node - - const { properties } = property - - if (properties) { - Object.keys(properties).forEach(name => { - const childProperty = properties[ - name - ] as SiteObjectWatcherPropertyType - - if (childProperty.dynamicProperties) { - switch (node.type) { - case Mesh.Array: { - const potentialChildren = node.value as Array - potentialChildren.forEach((childValue, i) => { - const elementProperty = code.extendDynamicPropertyWatcher( - load, - property, - String(i), - ) - - code.updateAllThroughWatcherProperty( - load, - elementProperty, - childValue, - ) - }) - break - } - case Mesh.Map: { - const potentialMap = node.value as Record - for (const key in potentialMap) { - const childValue = potentialMap[key] as BlueType - const elementProperty = code.extendDynamicPropertyWatcher( - load, - property, - key, - ) - - code.updateAllThroughWatcherProperty( - load, - elementProperty, - childValue, - ) - } - break - } - default: - code.throwError(code.generateInvalidCompilerStateError()) - } - } else { - switch (node.type) { - case Mesh.Map: { - node = node.value as Record - } - default: - break - } - - const childValue = node[name] as BlueType - - code.updateAllThroughWatcherProperty( - load, - childProperty, - childValue, - ) - } - }) - } -} - -export function updateWatcherForPath( - load: MeshLoad, - watcher: SiteObjectWatcherType, - path: Array>, -): void { - let properties: SiteObjectWatcherPropertiesType | undefined = - watcher.properties - - let i = 0 - - while (i < path.length) { - const node = path[i++] as BlueNodeType - code.assertString(node.attachedAs) - - let property: SiteObjectWatcherPropertyType | undefined = - properties[node.attachedAs] - - if (!property) { - return - } - - property.node = node - - if (i === path.length) { - if (property.matched) { - return - } - - property.matched = property.state.includes(node.state) - - if (property.matched) { - while (property) { - property.pending-- - if (property.pending === 0 && property.handle) { - code.assertRecord(property.node) - - const parent = property.parent - if (parent?.properties) { - delete parent.properties[property.name] - } - - code.queuePropertyUpdateHandle( - load, - property.handle, - property.node, - ) - } - property = property.parent - } - } - - return - } - - properties = property.properties - - if (!properties) { - return - } - } -} diff --git a/hack/form/tool/task.ts b/hack/form/tool/task.ts deleted file mode 100644 index 8006e00..0000000 --- a/hack/form/tool/task.ts +++ /dev/null @@ -1,12 +0,0 @@ -import { Base } from '../form/base.js' - -export function callTask(base: Base): void { - const task = base.task.shift() - if (task) { - task() - } -} - -export function hostTask(base: Base, hook: SiteCallbackType): void { - base.task.push(hook) -} diff --git a/hack/form/tool/text.ts b/hack/form/tool/text.ts deleted file mode 100644 index 7d2b9e0..0000000 --- a/hack/form/tool/text.ts +++ /dev/null @@ -1,37 +0,0 @@ -import { MeshLoad } from '../form.js' -import card from '../card.js' -import tool from '../tool.js' - -export function bindText(load: MeshLoad, hook: (text: string) => void) { - const hint = tool.readLinkHint(load) - switch (hint) { - case LinkHint.Text: { - const string = tool.loadText(load) - hook(string) - break - } - case LinkHint.NickText: { - const string = tool.loadNickText(load) - - if (string) { - hook(string) - } else { - tool.waitText(load, () => { - const string = tool.loadNickText(load) - if (!string) { - tool.throwError(`Received null for string`, load) - } else { - hook(string) - } - }) - } - } - default: - tool.throwError(tool.generateUnhandledNestCaseError(load, hint)) - } -} - -// https://github.com/nerdbond/base.link/blob/make/make/tool/dependency.ts#L277 -export function loadNickText(load: MeshLoad) {} - -export function loadText(load: MeshLoad) {} diff --git a/hack/types/annotate.ts b/hack/types/annotate.ts new file mode 100644 index 0000000..9494be2 --- /dev/null +++ b/hack/types/annotate.ts @@ -0,0 +1 @@ +export function annotate() {} diff --git a/hack/types/index.ts b/hack/types/index.ts new file mode 100644 index 0000000..43a6ce0 --- /dev/null +++ b/hack/types/index.ts @@ -0,0 +1,419 @@ +// https://github.com/termsurf/make.tree/tree/465133c1daa64cd231c5ce4d8daef9d5173577e0/hack/code/types + +// Term types, representing different syntax tree nodes in a type system +export type Term = + | UniversalType + | Function + | Call + | Binding + | Annotation + | Self + | SelfInstance + | AlgebraicDataType + | Constructor + | PatternMatch + | Reference + | LocalDefinition + | LocalUsage + | Base + | UInt64 + | Float64 + | Integer + | Float + | BinaryOperation + | SwitchCase + | MapType + | KeyValueMap + | MapGetter + | MapSetter + | Placeholder + | MetaVariable + | Logger + | Variable + | SourceCode + | Text + | List + | NaturalNumber + | Substitution + +// Universal Type (e.g., ∀(x: A) B) +export type UniversalType = { + bodyFn: (param: Term) => Term + name: string + paramType: Term + tag: 'UniversalType' +} + +// Function (e.g., λx f) +export type Function = { + bodyFn: (param: Term) => Term + name: string + tag: 'Function' +} + +// Empty Value +export type Void = { + tag: 'Void' +} + +// Call of a function to an argument +export type Call = { + arg: Term + func: Term + tag: 'Call' +} + +// Type Annotation (e.g., {x: T}) +export type Annotation = { + expr: Term + flag: boolean + tag: 'Annotation' + type: Term +} + +// Self Type (e.g., $(x: A) B) +export type Self = { + bodyFn: (param: Term) => Term + name: string + paramType: Term + tag: 'Self' +} + +// Instance of a Self Type (e.g., ~x) +export type SelfInstance = { + tag: 'SelfInstance' + term: Term +} + +// Constructor Parameter +export type ConstructorParameter = { + name: string | null + type: Term +} + +// Constructor Definition +export type ConstructorDefinition = { + name: string + params: Array +} + +// Algebraic Data Type (e.g., #[i0 i1...]{ #C0 Tele0 #C1 Tele1 ... }) +export type AlgebraicDataType = { + constructors: Array + indices: Array + tag: 'AlgebraicDataType' + term: Term +} + +// Constructor +export type Constructor = { + name: string + params: Array + tag: 'Constructor' +} + +// Binding +export type Binding = { + name: string + tag: 'Binding' + value: Term +} + +// Pattern Matching (e.g., λ{ #C0:B0 #C1:B1 ... }) +export type PatternMatch = { + cases: Array + tag: 'PatternMatch' +} + +// Top-Level Reference +export type Reference = { + name: string + tag: 'Reference' +} + +// Local Definition (e.g., let x = val body) +export type LocalDefinition = { + bodyFn: (val: Term) => Term + name: string + tag: 'LocalDefinition' + value: Term +} + +// Local Usage (e.g., use x = val body) +export type LocalUsage = { + bodyFn: (val: Term) => Term + name: string + tag: 'LocalUsage' + value: Term +} + +// Type Universe +export type Base = { + tag: 'Base' +} + +// UInt64 Type +export type UInt64 = { + tag: 'UInt64' +} + +// Float64 Type +export type Float64 = { + tag: 'Float64' +} + +// Integer Value (e.g., 123) +export type Integer = { + tag: 'Integer' + value: number +} + +// Floating Point Value (e.g., 1.5) +export type Float = { + tag: 'Float' + value: number +} + +// Binary Operation Enum +export enum Operation { + ADD, + SUBTRACT, + MULTIPLY, + DIVIDE, + MODULO, + EQUAL, + NOT_EQUAL, + LESS_THAN, + GREATER_THAN, + LESS_THAN_OR_EQUAL, + GREATER_THAN_OR_EQUAL, + AND, + OR, + XOR, + LEFT_SHIFT, + RIGHT_SHIFT, +} + +// Binary Operation (e.g., (+ x y)) +export type BinaryOperation = { + left: Term + operator: Operation + right: Term + tag: 'BinaryOperation' +} + +// Switch Case (e.g., λ{ 0:A 1+p:B }) +export type SwitchCase = { + successorCase: Term + tag: 'SwitchCase' + zeroCase: Term +} + +// Map Type (e.g., (Map T)) +export type MapType = { + elementType: Term + tag: 'MapType' +} + +// Key-Value Map +export type KeyValueMap = { + defaultValue: Term + entries: Map + tag: 'KeyValueMap' +} + +// Map Getter +export type MapGetter = { + accessor: string + bodyFn: (value: Term, map: Term) => Term + key: Term + map: Term + mapName: string + tag: 'MapGetter' +} + +// Map Setter +export type MapSetter = { + accessor: string + bodyFn: (oldValue: Term, newMap: Term) => Term + key: Term + map: Term + mapName: string + tag: 'MapSetter' + value: Term +} + +// Placeholder +export type Placeholder = { + name: string + tag: 'Placeholder' + terms: Array +} + +// Meta Variable for Unification +export type MetaVariable = { + id: number + tag: 'MetaVariable' + terms: Array +} + +// Logging +export type Logger = { + message: Term + next: Term + tag: 'Logger' +} + +// Variable +export type Variable = { + index: number + name: string + tag: 'Variable' +} + +// Source Location +export type SourceLocation = { + columnNumber: number + lineNumber: number +} + +// Source Code Span +export type CodeSpan = { + end: SourceLocation + fileName: string + start: SourceLocation +} + +// Source Code Term +export type SourceCode = { + span: CodeSpan + tag: 'SourceCode' + term: Term +} + +// Text Literal +export type Text = { + tag: 'Text' + value: string +} + +// List Literal +export type List = { + items: Array + tag: 'List' +} + +// Natural Number Literal +export type NaturalNumber = { + tag: 'NaturalNumber' + value: number +} + +// Substitution +export type Substitution = { + tag: 'Substitution' + term: Term +} + +// Telescope Types +export type Telescope = TelescopeReturn | TelescopeExtension + +// Return Telescope +export type TelescopeReturn = { + tag: 'Return' + term: Term +} + +// Extend Telescope +export type TelescopeExtension = { + bodyFn: (param: Term) => Telescope + name: string + paramType: Term + tag: 'Extension' +} + +// Info Types for Type-Checker Outputs +export type Info = + | FoundInfo + | SolvedInfo + | ErrorInfo + | GenericInfo + | PrintInfo + +// Found Information +export type FoundInfo = { + name: string + occurrence: number + tag: 'FoundInfo' + term: Term + terms: Array +} + +// Solved Information +export type SolvedInfo = { + id: number + occurrence: number + solution: Term + tag: 'SolvedInfo' +} + +// Error Information +export type ErrorInfo = { + actual: Term + expected: Term + location: CodeSpan | null + occurrence: number + tag: 'ErrorInfo' + term: Term +} + +// Generic Information +export type GenericInfo = { + message: string + tag: 'GenericInfo' +} + +// Print Information +export type PrintInfo = { + occurrence: number + tag: 'PrintInfo' + term: Term +} + +// Book of Definitions +export type DefinitionsBook = Map + +// Unification Solutions +export type SolutionMap = Map + +// Checker State +export type CheckerState = { + checks: Array + definitions: DefinitionsBook + info: Array + solutions: SolutionMap +} + +// Checker Result +export type CheckerResult = { + actual: Term + expected: Term + location: CodeSpan | null + occurrence: number +} + +// Result Types +export type Result = Success | Failure + +// Success Result +export type Success = { + state: CheckerState + tag: 'Success' + value: T +} + +// Failure Result +export type Failure = { + state: CheckerState + tag: 'Failure' +} diff --git a/hack/types/readme.md b/hack/types/readme.md new file mode 100644 index 0000000..b342c1e --- /dev/null +++ b/hack/types/readme.md @@ -0,0 +1,48 @@ +## Flow + +``` +compile + ├─ parse # Parse initial code into AST + ├─ raise # Raise the AST into high-level AST + ├─ annotate # Add initial type annotations + ├─ check # Validate types and structures + │ └─ checkTerm + │ ├─ inferTerm + │ └─ checkTermLater + ├─ lower # Convert to intermediate representation (IR) + ├─ prune # Remove dead code + ├─ inline # Inline functions/values + ├─ render # Render final representation (e.g., bytecode) + └─ file # Output to a file + +make + load + rise + note + test + find + cast + toss + line + code + file +``` + +## API Ideas + +```ts +{ + $form: 'annotation', + term, + form, +} +``` + +## Notes + +- `check` builds a bunch of annotations + - then after building annotations + +## Inspiration + +- [Functional TS version of Kind language](https://github.com/cluesurf/make.tree/pull/1) diff --git a/package.json b/package.json index cb63d69..d2e3b4c 100644 --- a/package.json +++ b/package.json @@ -1,5 +1,5 @@ { - "name": "@termsurf/make", + "name": "@cluesurf/make", "main": "./host", "type": "module", "version": "0.1.0", @@ -47,8 +47,8 @@ "dependencies": { "@babel/parser": "^7.22.5", "@babel/types": "^7.22.5", - "@termsurf/have": "^0.x.x", - "@termsurf/link": "*", + "@cluesurf/have": "^0.x.x", + "@cluesurf/link": "*", "error-stack-parser": "^2.1.4", "events": "^3.3.0", "glob": "^8.0.3", diff --git a/readme.md b/readme.md index 7e0e0f1..d705937 100644 --- a/readme.md +++ b/readme.md @@ -112,7 +112,7 @@ were potential errors. ## License -Copyright 2021-2024 TermSurf +Copyright 2021-2024 ClueSurf Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain @@ -126,11 +126,11 @@ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. -## TermSurf +## ClueSurf -This is being developed by the folks at [TermSurf](https://term.surf), a +This is being developed by the folks at [ClueSurf](https://clue.surf), a California-based project for helping humanity master information and -computation. Find us on [Twitter](https://twitter.com/termsurf), -[LinkedIn](https://www.linkedin.com/company/termsurf), and -[Facebook](https://www.facebook.com/termsurf). Check out our other -[GitHub projects](https://github.com/termsurf) as well! +computation. Find us on [Twitter](https://twitter.com/cluesurf), +[LinkedIn](https://www.linkedin.com/company/cluesurf), and +[Facebook](https://www.facebook.com/cluesurf). Check out our other +[GitHub projects](https://github.com/cluesurf) as well!