Skip to content

Instantly share code, notes, and snippets.

@naugtur
Last active August 1, 2022 20:49
Show Gist options
  • Save naugtur/daf2aaf415e03e6c3ae5030e06f7b20e to your computer and use it in GitHub Desktop.
Save naugtur/daf2aaf415e03e6c3ae5030e06f7b20e to your computer and use it in GitHub Desktop.
Visual representation of the module refactor

ModuleRecord refactoring diagrams

The purpose of this document is to ensure complete understanding of changes proposed by an attempt to reproduce them in a different medium.

Before

classDiagram
direction TB
    ModuleRecord <|-- CyclicModuleRecord
    CyclicModuleRecord <|-- SourceTextModuleRecord

    CyclicModuleRecord

    ModuleRecord "n" --> "1" RealmRecord 

    CyclicModuleRecord --> CyclicModuleRecord

    class ModuleRecord{
        <<abstract>>
        Realm: RealmRecord
        Environment: ModuleEnvironmentRecord
        Namespace: ModuleNamespaceObject
        HostDefined

        GetExportedNames([exportStarSet])* List~names~
        ResolveExport(exportName [, resolveSet])*
        Link()* unused
        Evaluate()* Promise
    }
    class CyclicModuleRecord{
        Status
        EvaluationError
        DFSIndex
        DFSAncestorIndex
        RequestedModules: List of String
        CycleRoot: CyclicModuleRecord
        HasTLA
        AsyncEvaluation
        TopLevelCapability
        AsyncParentModules
        PendingAsyncDependencies

        InitializeEnvironment()*
        ExecuteModule([ promiseCapability ])*

        +Link() unused
        +Evaluate() Promise
    }
    class SourceTextModuleRecord{
        ECMAScriptCode
        Context
        ImportMeta
        ImportEntries
        LocalExportEntries
        IndirectExportEntries
        StarExportEntries

        +GetExportedNames([ exportStarSet ]) List~string~
        +ResolveExport(exportName [, resolveSet ])  ResolvedBindingRecord
        +InitializeEnvironment() unused
        +ExecuteModule([ capability ]) unused
        ParseModule(sourceText, realm, hostDefined)* SourceTextModuleRecord
        HostResolveImportedModule(referencingScriptOrModule, specifier)* ModuleRecord
        HostImportModuleDynamically(referencingScriptOrModule, specifier, promiseCapability)* unused
        FinishDynamicImport( referencingScriptOrModule, specifier, promiseCapability, innerPromise)* unused
        GetModuleNamespace(module)* ModuleNamespaceObject
    }

    class RealmRecord{
        Intrinsics
        GlobalObject
        GlobalEnv: GlobalEnvironmentRecord
        TemplateMap
        HostDefined
    }


Loading

Layer 0 refactor

note
1 This Abstract Operation is analogous to FinishDynamicImport but for Module Records with an associated Module Instance.
2 A Module Instance without a [[ModuleSourceInstance]] value associated to it is a Module Instance created via the Import Reflection API where the host decides that the source is not available. E.g.: fs module or any built-in module in the future.
3 Why is the relationship between Module and SourceTextModuleRecord bidirectional?
4 design writeup says it's supposed to be abstract, Layer0 refactor spec doesn't mention that
classDiagram
direction TB
    ModuleRecord <|-- CyclicModuleRecord
    CyclicModuleRecord <|-- SourceTextModuleRecord

    ModuleRecord "n" --> "1" RealmRecord
    CyclicModuleRecord --> CyclicModuleRecord



    ModuleSource "1" --> "0..1" ModuleSourceRecord
    Module "n" --> "0..1" ModuleSource
    Module "1" --> "1" SourceTextModuleRecord : 3❓ has Module
    SourceTextModuleRecord "1" --> "0..1" Module : 3❓ has ModuleInstance 

    class ModuleSourceRecord {
        <<4❓static portion of ModuleRecord>>
        ECMAScriptCode
        ImportEntries
        LocalExportEntries
        IndirectExportEntries
        StarExportEntries
        HasTLA
        RequestedModules
        HostDefined
    }
    class ModuleSource {
        ModuleSource: ModuleSourceRecord
        ParseModuleSource(sourceText)* ModuleSourceRecord
    }

    class Module {
        Module: SourceTextModuleRecord
        2❓ModuleSourceInstance: ModuleSource
        ImportHook

        CreateModuleRecord(moduleSource:ModuleSourceRecord)* SourceTextModuleRecord
        ResolveModuleRecordDependency(moduleRecord, specifier, promiseCapab)* unused
        HostImportModuleRecordDynamically(moduleRecord, specifier, promiseCapability)* unused
        1❓FinishModuleDynamicImport(moduleRecord, promiseCapability, innerPromise)* unused
    }

  class ModuleRecord{
        <<abstract>>
        Realm: RealmRecord
        Environment: ModuleEnvironmentRecord
        Namespace: ModuleNamespaceObject
        HostDefined

        GetExportedNames([exportStarSet])* List~names~
        ResolveExport(exportName [, resolveSet])*
        Link()* unused
        Evaluate()* Promise
    }
    class CyclicModuleRecord{
        Status
        EvaluationError
        DFSIndex
        DFSAncestorIndex
        RequestedModules: List of String
        CycleRoot: CyclicModuleRecord
        HasTLA
        AsyncEvaluation
        TopLevelCapability
        AsyncParentModules
        PendingAsyncDependencies

        InitializeEnvironment()*
        ExecuteModule([ promiseCapability ])*

        +Link() unused
        +Evaluate() Promise
    }
    class SourceTextModuleRecord{
        ECMAScriptCode
        Context
        ImportMeta
        ImportEntries
        LocalExportEntries
        IndirectExportEntries
        StarExportEntries
        ModuleInstance: Module

        +GetExportedNames([ exportStarSet ]) List~string~
        +ResolveExport(exportName [, resolveSet ])  ResolvedBindingRecord
        +InitializeEnvironment() unused
        +ExecuteModule([ capability ]) unused
        ParseModule(sourceText, realm, hostDefined)* SourceTextModuleRecord
        HostResolveImportedModule(referencingScriptOrModule, specifier)* ModuleRecord
        HostImportModuleDynamically(referencingScriptOrModule, specifier, promiseCapability)* unused
        1❓FinishDynamicImport( referencingScriptOrModule, specifier, promiseCapability, innerPromise)* unused
        GetModuleNamespace(module)* ModuleNamespaceObject
    }

    class RealmRecord{
        Intrinsics
        GlobalObject
        GlobalEnv: GlobalEnvironmentRecord
        TemplateMap
        HostDefined
    }


Loading
@caridy
Copy link

caridy commented Aug 1, 2022

It is confusing that records and object instances are combined in the same diagram, maybe try to use a color code or something to differentiate them, they are not the same thing.

The only note is: ModuleSource instance has a 1-1 mapping to a ModuleSourceRecord.

@naugtur
Copy link
Author

naugtur commented Aug 1, 2022

Had mixed feelings about that too, mermaid (the tool used here that GH also supports) doesn't give me a lot of options to distinguish those. I'll see what I can do.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment