Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
This PR includes a huge refactor of all the internal implementation of the lib while keeping the tests basically the same (to guarantee it's an internal-only change).
Why
So, the previous implementation began small because Structure didn't have all the features it has today back then, so it kinda did suffice. When new contributors were added to the projects one of the main things that held them back was to understand how everything interacted. Now that the next major of this project is being developed, I decided it was a good time to refactor everything.
How
Previously everything was attached to the schema object, including the attributes and features (validation, coercion, ...), and everything that wasn't an attribute was a "private" (non-enumerable, symbol-keyed) attribute of it.
Now there are three main classes in the whole architecture:
Schema
,AttributeDefinitions
andAttributeDefinition
.Schema
The schema is still the entry point of most of the features but it now has a field called
attributeDefinitions
instead of have all of them directly attached to the schema object.This class is used to manage everything that operates over the whole structure (even if it internally delegates to each of the attribute definitions), including initialization, coercion, dynamic types, validation, and serialization.
AttributeDefinitions
Previously named as "type descriptors" (or "attribute descriptors"), the concept was renamed to "attribute definitions" to avoid confusion with the property descriptors that are passed to
Object.defineProperty
. This class inherits from array so it's a collection of attribute definitions that can be accessed both as an array (so you can.map
,.forEach
over each) and it also has each of attributes as a property of it, so you can also doattributeDefinitions.name
to get the definition of the attributename
of this given collection.AttributeDefinition
Each of the items inside a
AttributeDefinitions
instance is an instance ofAttributeDefinition
. Like the schema, this is the entry point of everything that is related only to a specific attribute. So this is where the ordering of attributes (base on initialization order) is implemented, dynamic type resolution and coercion.Descriptors
Previously implemented inside each module, now all the property descriptors are inside a descriptors object that receives the schema and the wrapper class in its constructor. All the links between the features and the instance (or the wrapped class) are created there.
The only features that won't delegate directly to the schema or the attributeDefinitions inside the descriptors are cloning and strict mode because these features aren't implemented in any of these objects.
A whole lot of indirection and confusion were removed in this PR in order to make the code clearer and more welcoming to contributors, and it's also now to add new features since the responsibilities were better separated.