Logo Xantham

Naming Module

The naming contract (O7): the deterministic scheme mapping package identities to F# module names. Pinned, because a `reference` group's templated names must be exactly what a `ship` run of that group produces - independently generated packages have to agree on every name here. Renaming anything below is a breaking change to every shipped binding.

Nested modules

Modules Description

BrowserBindings

The compiler-lib names the `Fable.Browser.*` family binds - the DOM half of the same disposition `LibBindings` covers for the ECMAScript half. The table itself is generated (`BrowserBindingTable`, from `tools/browser-gen/generate.fsx`), because it is four hundred names read off two authorities that both move: what the referenced `Browser.*` assemblies export, and what the pinned compiler's `lib.*.d.ts` files declare. Only their intersection is here, so an entry is by construction a real lib name with a real binding. The *rule* below is hand-written and tested, next to the one it mirrors. Arity is a lookup key rather than a property of the name, which is where this rule and `LibBindings` differ: `CustomEvent` is bound both bare and generic, so a reference carrying one type argument should reach the generic binding and a bare one the other. Failing an exact match, the widest binding the reference has arguments for wins and the extras are dropped with a finding - `LibBindings`' rule, generalised. A reference with fewer arguments than the narrowest binding is some other type wearing a familiar name, and widens. Unlike `LibBindings` no entry carries a loss note: a `Browser.Types` name is the same type under a different spelling, so the mapping is Exact. Whether Fable's binding has caught up with the member the caller wants is that package's business, exactly as it is for `JS.Promise`.

LibBindings

The compiler-lib names Fable.Core already binds, and the F# spelling of each. O7 left the compiler-lib group widening to `obj` "until the shipped compiler-lib package exists". For the ECMAScript half of `lib.d.ts` it already does, and every generated file opens it: `Fable.Core.JS` is that package. So `Promise` is `JS.Promise` rather than a bare `obj`, which is one honest loss (the DOM name inside) instead of two. Each entry is the F# name and the arity that name takes. The arity is here rather than inferred because it is the whole safety argument: TypeScript's own lib moves - it made `Uint8Array` generic in a buffer parameter that Fable's abbreviation does not have - and a mapping that guessed would emit code that does not compile. Arities that agree map exactly; a lib type carrying *more* arguments than Fable's binding maps with the extras dropped and a finding; one carrying fewer is not this type at all and widens. The DOM half (`HTMLElement`, `EventTarget`, `Blob`, ...) is not here: it is four hundred names, so it is generated rather than transcribed, and it lives in `BrowserBindings` below. What stays hand-written here is what has a hand-judged loss note attached.

Functions and values

Function or value Description

CompilerLibModule

Full Usage: CompilerLibModule

Returns: string

The compiler-lib group's module.

Returns: string

defaultExport packageName

Full Usage: defaultExport packageName

Parameters:
    packageName : string

Returns: string

The name a default export falls back to when its symbol is itself named `default`: the package name's last segment, camelCased (`ansi-regex` -> `ansiRegex`).

packageName : string
Returns: string

defaultImportKey

Full Usage: defaultImportKey

Returns: string

The import selector a default export binds under - the JavaScript key, not an F# name. Shared because a class's statics compose it into a dotted selector of their own (`default.MAX`, which Fable reads as "the default import, then `.MAX`").

Returns: string

enumCaseOfNumber value

Full Usage: enumCaseOfNumber value

Parameters:
    value : float

Returns: string

The DU case name for a numeric-literal union member (D12): `1` -> `N1`, `1.5` -> `N1_5`, `-1` -> `NMinus1`.

value : float
Returns: string

enumCaseOfString text

Full Usage: enumCaseOfString text

Parameters:
    text : string

Returns: string

The DU case name for a string-literal union member: PascalCased over separator segments (`"utf-8"` -> `Utf8`), prefixed when the result cannot start an F# case. Pinned like the module scheme - StringEnum case names are part of a binding's surface.

text : string
Returns: string

groupModule config entryPackageName _arg1

Full Usage: groupModule config entryPackageName _arg1

Parameters:
Returns: string

The module a group's declarations live in (or are templated to live in). A package generated as the entry takes the same name under a namespace that a run referencing it templates, so one `namespace` in each member of a family is the whole configuration. The family's root sets `module` to take the namespace bare.

config : GeneratorConfig
entryPackageName : string
_arg1 : PackageId
Returns: string

isWritableTypeName name

Full Usage: isWritableTypeName name

Parameters:
    name : string

Returns: bool

Whether a name can head an F# declaration. Backticks rescue keywords and spaces, but not every symbol name is spellable even so: an ambient module declaration's symbol *is* its quoted specifier (`"cloudflare:email"`), and `` ``"cloudflare:email"`` `` is FS0883, not a type name. The rule is deliberately conservative - letters, digits and underscore, not starting with a digit - because the failure it prevents is a whole file that will not compile, and the cost of a false negative is one finding.

name : string
Returns: bool

memberName name

Full Usage: memberName name

Parameters:
    name : string

Returns: string

The JavaScript key a member symbol stands for. The checker escapes a name that begins with two underscores by prepending a third, so that a real `__html` cannot collide with the internal names it invents (`__type`, `__call`); undoing that is what turns the symbol back into the key the object actually carries. Apply it only *after* testing for an internal name - the escaping is the one thing that tells the two apart.

name : string
Returns: string

namespacedModule config packageName

Full Usage: namespacedModule config packageName

Parameters:
Returns: string

A dependency's module under the entry package's configured namespace, or its derived module where the configuration leaves the dependency unnamed. The namespace reaches the groups `groups` names, which is the family the entry package declares itself part of. Selecting them by configuration rather than by npm scope lets a family span scopes, and lets an unscoped one exist at all.

config : GeneratorConfig
packageName : string
Returns: string

packageModule packageName

Full Usage: packageModule packageName

Parameters:
    packageName : string

Returns: string

A package's module name: `@scope/pkg-name` -> `Scope.PkgName`. The name is taken from the runtime package, so a DefinitelyTyped package is named for the library it describes: `@types/three` -> `Three`, `@types/babel__core` -> `Babel.Core`. An F# consumer opens the binding for the library, and `@types/` is a TypeScript-side convention for attaching declarations to a package that shipped without them - it distinguishes nothing on this side, where the declarations and the library are one binding. Deriving it here rather than at the call site keeps a declaration and every cross-package reference to it on the same name.

packageName : string
Returns: string

pascalSegment text

Full Usage: pascalSegment text

Parameters:
    text : string

Returns: string

One path segment of a package name, PascalCased: `workers-types` -> `WorkersTypes`.

text : string
Returns: string

Type something to start searching.