Coder Social home page Coder Social logo

minim's People

Contributors

abacaphiliac avatar char0n avatar danielgtaylor avatar dependabot-preview[bot] avatar fosrias avatar greenkeeper[bot] avatar honzajavorek avatar klokane avatar kylef avatar opichals avatar pksunkara avatar realityking avatar smizell avatar tjanc avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar

minim's Issues

Meta getProperty mutates underlying storage

This leads to non-obvious behavior which I think we need to properly define or change. Here is the implementation as it stands:

pimitives.es6#34-40

class Meta {
  getProperty(name, value) {
    if (!this.meta[name]) {
      this.meta[name] = registry.toType(value);
    }

    return this.meta[name];
  }
}

Here is the surprising part:

const element = new ElementType();

console.log(element.toCompactRefract());
// => ['element', {}, {}, null]

// Access the non-existing name property
element.name;

// What? Now there is a meta name for some reason!?
console.log(element.toCompactRefract());
// => ['element', {name: ''}, {}, null]

// Try to get something from meta with a default if not found
element.getProperty('foo', 'bar');

// What? Now my default value is getting serialized!
console.log(element.toCompactRefract());
// => ['element', {name: '', foo: 'bar'}, {}, null]

I'm sorry I glossed over this in the initial review! I believe the code is written this way to cache the conversion to refract element classes for the default value, but I think we need to either do that conversion each time or keep a separate cache that doesn't mutate the original meta values..

Thoughts @smizell?

Interface to Refract Properties

Refract has three properties:

  • element
  • meta
  • attributes
  • content

What should the interface to these values be on an element? With #25 I've introduced meta as a special class where each property is a Minim instance. Additionally, with #27 I've introduced elementName instance method and removed the element.

  • Should elementName be accessible through a getter for element?
  • Should attributes be a lazy loaded Minim object?
  • Should content be a Minim Collection?

toEmbeddedRefract

AFAICT the toEmbeddedRefract is not part of the library any more, yet it is still mentioned in the README. Is it correct observation?

Immutability

I am interested in making the getters and setters be immutable. This means that when you set a value, the old value is not changed, but rather a new object is returned. This requires some fancy work to pass changes up and down the hierarchy and to share the tree, which shouldn't be too hard.

When it's done, it could be a really cool library for use with React, as a component could listen in on only one part of the tree using callbacks.

Better handling of undefined

This is a fun experiment:

el = new minim.ObjectElement({a: 1});

// This works
el.toRefract();

// This fails
el.set('a', undefined);
el.toRefract(); // => throws exception

// Also this one is fun
el = new minim.ArrayElement([1, undefined]);
el.findByElement('test'); // => throws exception

Lots of other stuff falls down like this too. Question: should forEach be returning undefined items? What about for an object where the key is defined but the value is undefined? Is this just something that we need to check for in most of the convenience methods?

How would you run into this? I had some malformed serialized refract which I loaded and it wound up having undefined keys and values for object elements. Any searching that included those elements wound up throwing exceptions.

Slimmer Full Refract Output

Right now, each call of #toRefract outputs meta and attributes even if they are empty. We should not output these if they are empty.

Merge dredd-transactions' refract.coffee with Minim

When implementing dredd-transacitons, I made my own implementation of a small Refract library on top of traverse and sift, because neither refract-query or minim seemed to solve my problems. It lives in refract.coffee file, hence the name in the title of this issue.

I wrote down rough list of requirements I expect from a Refract library: apiaryio/dredd-transactions#10

Minim 1.0.0

Per issue #81, it seems like a good idea to move forward to 1.0.0 as soon we can. I've tried to go through and put the issues under the milestone of 1.0.0 that seem to be important to complete before we say "this is stable."

In addition that, I'd be really interested in other's thoughts. Is there anything else? Should any of the issues I've added not be considered?

Making a Usable Minim

I'm on User Support, so I have a little time to type this out. I've mostly been away from the computer this week, which has been nice :)

I wanted to write out some thoughts that I have to get Minim to a usable state. Minim started out as a POC for interacting with Refract elements. Now all the sudden it's something that we may like to use, so it will be good to give it some added care.

First, I think the most important thing here is to get the API right, and I don't think it's quite there yet. Currently, to create a new type object, you have to extend one of the primitive type classes, and this is not good for several reasons. I believe "classes" only exist in CoffeeScript and ES6, and I don't think they are interoperable at this point (maybe?).

To get it right, I think we need to have one element object that handles certain categories of elements that can be easily wrapped to create new element types and functionality (like ArrayElement.createClass, much like React and Backbone). This base class can introspect the content to see what methods should be made available to the user. This means we don't have to care if an element is an array or object, we can know they are iterable because the content of the element is iterable.

To think of an example, a string element is a value-like element, but it is not iterable. This means calling map on it throws a Minim error. For array elements, though, they are iterable, so the user may map over each element in content. This all saves us from having element explosion while encapsulating all functionality in one "class."

Next, we need to define all base elements from Refract (once we finalize the first iteration of it, which we are hopefully close). This is important for Minim to interact with new element types. With the previous recommendation above, I believe this will allow for working with any Refract document without having to pull in namespaces. This will be a big win I think, and may save us from needing to have a factory for registering elements.

Next, I believe we need to work to remove lodash as a dependency. I like using it to get up and running quickly, but if this is going to be used in a browser, there is no need to load another library for simply things. This is not a hard requirement in my mind, but could be beneficial.

Lastly and related, to bring this all together, this needs to be ran through Browserify to make it usable in the browser. At that point, it should be a very small and usable library for interacting with Refract payloads.

Doing all of this gets Minim to a usable state in my mind, and we are not far from this at all. In light of this, I vote that we close #21 for now to focus on these other things, as error handling will be much easier with a central class. I would then like to do a refactor on how the elements class are organized to greatly simply the code, making it easier for Minim to simply interact with a document that introduces any kind of element.

Handling Circular Structures

This is going to come up quickly, but we need to think about how to handle circular structures.

var minim = require('.minim');

var arr1 = new minim.ArrayElement();
var arr2 = new minim.ArrayElement();

arr1.push(arr2);
arr2.push(arr1);

console.log(arr1.toRefract());

This results in RangeError: Maximum call stack size exceeded.

Find Methods

Add a method to find the first item matching the criteria given. This will be similar to find, but it will be optimized to return the first one found and stop recursing the tree.

  • Find first
  • Find by element
  • Find by class

Convenience Methods

In reading this utility code, it may be helpful to provide convenience methods for better filtering. I think the utility code there is moving toward a structured way to query the tree, which I think we want to avoid at the moment. Using pure JS code is preferred. This means we need some better convenience methods.

For collections:

  • .getById() takes a string and returns the first element found with ID in entire tree
  • .filterByClass() returns collection of elements where class matches given class name. Searches entire tree.

For items:

  • .getClass() returns an array of classes (or should it be collection?) (or .classList() or .classes())
  • .getId() returns the ID of the element (undefined if not found) (or .id())
  • .withClass() takes a string and returns true/false depending on if element has the class name given. Should also take an options argument where you can do things like ignoreCase: true.
  • .hasClass() returns true/false if element has classes
  • .withId() takes a string and returns true/false if the element has matching meta.id
  • .hasId() return true/false if element has an ID
  • .withName() takes a string and returns true/false if the element has matching meta.name (do we have a better name for this function?) Should take options like hasClass.
  • .hasName() returns true/false if name exists. Should take options like hasClass.
  • .isType() takes a string and returns true/false if the element is the given value (better name?)

To make this happen, I think it would be nice to also have some additional methods.

  • .getContent() returns the content. Up for discussion... if it's array, it may be nice to return a collection element. This is people are not working directly with content property, which we should consider private.
  • .children()with no condition returns a collection of of the content. This is essentially .getContent()
  • .first() returns .get(0)
  • .second() returns .get(1)

Support for traversing upwards in an element in a tree

For example, given I have a reference element, I should be able dereference it.

Given the following tree called, structures

const element = {
  element: 'array',
  content: [
    {
      element: 'dataStructure',
      meta: {
        id: {
          element: 'string',
          content: 'User',
        }
      },
      content: {
        element: 'object',
        content: [
          {
            element: 'member',
            content: {
              key: {
                element: 'string',
                content: 'last_comment'
              },
              value: {
                element: 'ref',
                content: 'Comment'
              }
            }
          }
        ]
      }
    },
    {
      element: 'dataStructure',
      meta: {
        id: {
          element: 'string',
          content: 'Comment',
        }
      }
    }
  ]
};

Given I have a reference to the User dataStructure as user:

const last_comment = user.get('last_comment');
last_comment.dereference();

Support MSON inheritance

Right now this won't behave as expected. Think of the MSON which defines one type which is an object, then another which inherits from it:

  • A (object)
  • B (A)
    • C: test

Without expansion/preprocessing it's likely it will get expanded to something like this:

['object', {name: 'Data types'}, {}, [
  ['object', {name: 'A'}, {}, []],
  ['A', {name: 'B'}, {}, [
    ['string', {name: 'C'}, {}, 'test']
  ]]
]

In the above example we'll get an ElementType for B instead of ObjectType because there is no registered type for A. That means that B.content will be the raw content above instead of proper element instances. The solution may be to create some kind of lookup tree for the base type or some kind of preprocessing loop. Ideas?

Commenting

Methods should have comments that describe the input parameters and what is returned.

Maybe use Codo.

Add remove method

The remove method would be for array and object elements. Remove would not destroy the instance, but simply remove it from the content of the item.

JSON06Serialiser is not able to serialise frozen elements

Following code

new JSON06Serialiser(fury.minim).serialise(element);

blows up when provided with API Elements, which has been previously frozen:

element.freeze();

I'm getting exceptions like this one:

TypeError: Can't add property _attributes, object is not extensible
      at constructor.get (node_modules/minim/lib/primitives/element.js:295:26)
      at constructor.shouldRefract (node_modules/minim/lib/serialisers/json-0.6.js:217:16)
      at constructor.convertKeyToRefract (node_modules/minim/lib/serialisers/json-0.6.js:250:18)
      at constructor.<anonymous> (node_modules/minim/lib/serialisers/json-0.6.js:288:26)
      at Array.forEach (native)
      at constructor.serialiseObject (node_modules/minim/lib/serialisers/json-0.6.js:287:16)
      at constructor.serialise (node_modules/minim/lib/serialisers/json-0.6.js:19:30)
      at Array.map (native)
      at constructor.serialiseContent (node_modules/minim/lib/serialisers/json-0.6.js:190:22)
      at constructor.serialise (node_modules/minim/lib/serialisers/json-0.6.js:42:33)
      at module.exports (src/api-elements-to-refract.coffee:10:36)
      at compile (src/compile.coffee:19:13)
      at test/utils.coffee:26:16
      at src/parse.coffee:39:5
      at node_modules/fury/lib/fury.js:169:13
      at node_modules/fury-adapter-apib-parser/lib/adapter.js:71:7

This blocks apiaryio/dredd-transactions#88.

Minim 1.0 Proposal

This writeup outlines some ideas and thoughts on bringing Minim to a stable 1.0 release. I would like to work on stabilizing the interface and get some good use out of it before moving to 1.0, but would also like to not spend forever in pre-1.0 versions.

Aligning Minim with Refract

Right now, we call elements as types, such as StringType, NumberType, etc. We should align the naming of these to be StringElement, NumberElement, etc.

This goes for places where we call things "DOM."

Better Class Support for Non-ES6 Platform

Right now, to extend a class, you must be using ES6 or use a separate library for extending the prototype. I believe this is less than optimal, as it is a very important aspect of creating new elements. We need to think through how to provide support for this.

Backbone.js models extend models by adding a custom extend method on to classes [0]. They actually extend these classes using the underscore extend function.

Here is an example of a class in Backbone.js being extended.

_.extend(Model.prototype, Events, {
  foo: function() { return 'bar'; }
}

Model then provides a special extend method for extending that particular class with conventions such as:

var Book = Backbone.Model.extend({
  foo: function() { return 'hello world'; }
});

Now Book has all of the methods that Model has, but has a different foo method attached to the prototype.

I believe we should support extending classes this way, but it provides issues. For instance, how can this extend override the constructor for an ES6 class? How can we provide a super for those using ES5? It brings with it the question, should we be doing all of this in ES5 (yikes)? I believe we can do everything here in ES5 that we need without the ES6 syntax.

No matter what direction we take, I believe extending a class in ES6 will still work correctly, even if we use ES5.

Meta and Attributes as Minim Objects

Right now, the interface to meta is that it is a pseudo Minim Object that provides defaults for each of the values. Right now, you have a different interface to meta and attributes, as meta has a Minim interface and attributes is a simple object.

As Daniel pointed out, this pseudo Minim Object for meta creates some undesired effects. We need to solve this, which I belive takes:

  • We need to lazy load meta and attributes since it would create an infinite loop
  • We need to make meta and attributes Minim Objects
  • We need to be able to provide default values so the user does not have to set things like id or class. They should always be there and the user should not have to check. This would also be helpful for providing defaults for attributes.

Content as Minim Type

It would be helpful to store the content in a normal array, but provide a Minim instance for accessing the content. This means that meta, attributes, and content will all have the same interface.

Object Property Setter

Setters for objects currently require two argumentsβ€”a property name and a value for that property. Backbone.js allows for providing an object directly to set.

obj.set({ foo: 'bar' });

This would be really nice to support, and would be very similar to Backbone.js as a common convention.

Better Output of Full Refract

Right now, outputing full refract will always output meta and attributes. It would be beneficial in reducing size to only output meta and attributes if they have properties set. Since we will be (hopefully) be setting these as Minim Objects, it may be helpful to add an isEmpty method to determine if the contents are empty.

Handling Null Values

We need to handle null and undefined values better when parsing a Refract tree. For example, when the value of a MemberType is undefined, we should determine how to treat those values values. Same goes for StringType instances where the value is null.

Conclusion

There are more issues than outlined here, but these are the big ones. I would like to tackle these first and we can evaluate afterwards.

[0] I know JavaScript before ES6 didn't have classes, but it's the language we use.

Sync code with spec

It would be good to sync up the code of Minim with the spec.

  • Change classes from StringType to String Element
  • Remove instances of DOM
  • Support Extend
  • Support Select/Option

Type Registry

What is needed is a place to register types. Currently they are simply passed into a function and several if statements. Instead, this should be extendable where new types and conditions for those types can be set.

An in-range update of watchify is breaking the build 🚨

The devDependency watchify was updated from 3.11.0 to 3.11.1.

🚨 View failing branch.

This version is covered by your current version range and after updating it in your project the build failed.

watchify is a devDependency of this project. It might not break your production code or affect downstream projects, but probably breaks your build or test tools, which may prevent deploying or publishing.

Status Details
  • ❌ continuous-integration/travis-ci/push: The Travis CI build could not complete due to an error (Details).

Commits

The new version differs by 8 commits.

  • c3fe218 3.11.1
  • e90101b Merge pull request #362 from digipost/upgrade-deps
  • d163b4f upgrade dependencies: fix errors from npm audit
  • 1917270 Merge pull request #351 from menzow/feature/update-docs
  • d232754 Merge pull request #357 from Kamil93/patch-1
  • d924e9b Update readme.markdown
  • 9ea8a65 Support for working with transforms
  • 8147bc5 Add troubleshooting information for silenced errors

See the full diff

FAQ and help

There is a collection of frequently asked questions. If those don’t help, you can always ask the humans behind Greenkeeper.


Your Greenkeeper Bot 🌴

Copy method for elements

Create a method on elements that allows for a deep copy.

In the short term, this could be as simple as:

return registry.fromRefract(this.toRefract());

Per @danielgtaylor's idea

An in-range update of mocha is breaking the build 🚨

The devDependency mocha was updated from 6.0.2 to 6.1.0.

🚨 View failing branch.

This version is covered by your current version range and after updating it in your project the build failed.

mocha is a devDependency of this project. It might not break your production code or affect downstream projects, but probably breaks your build or test tools, which may prevent deploying or publishing.

Status Details
  • βœ… ci/circleci: lint: Your tests passed on CircleCI! (Details).
  • βœ… ci/circleci: test-browser: Your tests passed on CircleCI! (Details).
  • βœ… ci/circleci: test-node10: Your tests passed on CircleCI! (Details).
  • βœ… ci/circleci: test-node8: Your tests passed on CircleCI! (Details).
  • ❌ ci/circleci: test-node6: Your tests failed on CircleCI (Details).

Release Notes for v6.1.0

6.1.0 / 2019-04-07

πŸ”’ Security Fixes

  • #3845: Update dependency "js-yaml" to v3.13.0 per npm security advisory (@plroebuck)

πŸŽ‰ Enhancements

  • #3766: Make reporter constructor support optional options parameter (@plroebuck)
  • #3760: Add support for config files with .jsonc extension (@sstephant)

πŸ“  Deprecations

These are soft-deprecated, and will emit a warning upon use. Support will be removed in (likely) the next major version of Mocha:

πŸ› Fixes

  • #3829: Use cwd-relative pathname to load config file (@plroebuck)
  • #3745: Fix async calls of this.skip() in "before each" hooks (@juergba)
  • #3669: Enable --allow-uncaught for uncaught exceptions thrown inside hooks (@givanse)

and some regressions:

πŸ“– Documentation

πŸ”© Other

  • #3830: Replace dependency "findup-sync" with "find-up" for faster startup (@cspotcode)
  • #3799: Update devDependencies to fix many npm vulnerabilities (@XhmikosR)
Commits

The new version differs by 28 commits.

  • f4fc95a Release v6.1.0
  • bd29dbd update CHANGELOG for v6.1.0 [ci skip]
  • aaf2b72 Use cwd-relative pathname to load config file (#3829)
  • b079d24 upgrade deps as per npm audit fix; closes #3854
  • e87c689 Deprecate this.skip() for "after all" hooks (#3719)
  • 81cfa90 Copy Suite property "root" when cloning; closes #3847 (#3848)
  • 8aa2fc4 Fix issue 3714, hide pound icon showing on hover header on docs page (#3850)
  • 586bf78 Update JS-YAML to address security issue (#3845)
  • d1024a3 Update doc examples "tests.html" (#3811)
  • 1d570e0 Delete "/docs/example/chai.js"
  • ade8b90 runner.js: "self.test" undefined in Browser (#3835)
  • 0098147 Replace findup-sync with find-up for faster startup (#3830)
  • d5ba121 Remove "package" flag from sample config file because it can only be passes as CLI arg (#3793)
  • a3089ad update package-lock
  • 75430ec Upgrade yargs-parser dependency to avoid loading 2 copies of yargs

There are 28 commits in total.

See the full diff

FAQ and help

There is a collection of frequently asked questions. If those don’t help, you can always ask the humans behind Greenkeeper.


Your Greenkeeper Bot 🌴

Hierarchy

Elements should know of their children and their parents.

Which brings me to a question I have. An ObjectType is basically a collection of PropertyType elements (which are essentially key-value pairs). To have the same format, and potentially help in future features, should ArrayType collections consist of some kind of IndexType that instead of having a key, it has an index.

Reason being, an element needs to know where it is in the tree of elements, and without this having an explicit element (like IndexType), it would need to know the index for itself as well. If it did have this IndexType, it could know the array that it is in plus it's location without storing that.

Hope that makes sense.

@fosrias @zdne

Events

One piece that is going to make this library great is events. Allowing for code to listen in on parts of the tree is a great feature, especially for React components. Basically, when a setter is called, it sends a message up the tree and calls any attached listeners.

This will be dependent upon #17.

Follow semver rules?

Don't be afraid to start with 1.0.0 and bump to 2.0.0 if things changes.
You will save our lives: imagine us when seeing 0.10 and 0.11, consider it as a minor release and then you realise that there is a breaking change behind that.

Handle elements inside attributes better

Is there a way we can handle elements inside of attributes better. The current way seems tied directly to one use case, where a property at the root of the object is an element.

  • Have a preToRefract hook?
  • Have a preAttributeConvert hook?

Then we leave it up to the user to decide how this works in those methods.

Break up the non-SRP files

Better to have multiple files and associated tests to figure out what is going on and then tests and files only have one reason to change.

Remove get keywords for special methods?

Right now, we have methods that include the keyword get. Of course there is the main method get for arrays and objects. Below are the methods we currently have get on.

  • getMember
  • getKey
  • getValue

Should we have get on these methods?

Broken for refracted element in meta

Looks like Minim is actually broken when using source maps, or seemingly any refracted element in metadata:

var minim = require('minim').namespace();

var el = minim.fromRefract({
  element: 'object',
  meta: {
    title: {
      element: 'string',
      content: 'Test'
    }
  }
  content: []
});

console.log(el.title);
// => { element: 'string', content: 'test' }
// Should be => 'test'

console.log(el.meta.get('title').element);
// => 'object'
// Should be => 'string'

The result of this bug is that Minim is basically unusable with source maps, since they break out the title/description/etc into elements and you then need to determine whether to access el.title or el.title.content. It also breaks the concept of el.title always returning a simple non-refracted type.

Interestingly, el.toRefract() seems to output the correct data.

cc @smizell

Functionality of Get

The get method has different functionality depending on the class. Should it return the toValue() of the content, or should it return this when no input is given?

Serialization Formats

We need to decide if we are going to pull the serialization formats out of Minim. I can see leaving the main Refract format in there, but pulling compact and embedded out.

`find*` methods should return optional element

This is a breaking change and I would wait a bit before we do this to settle the current unreleased changes.

We should rename the current find* methods to filter* because in JavaScript find methods are expected to return the single element and our implementation if the method is inconsistent. We should implement find* to return first matching item.

Take the following example:

// JS Array `find`
["a", "b", "c"].find(c => c === "b"); // "b"
// Array Element `find`
ArrayElement(["a", "b", "c"]).find(c => c.toValue() === "b"); // ["b"]
// We return array slice of B not just B.

Error Handling

There needs to be a way to handle errors in Minim. Some options:

Throw JavaScript errors

minim.toElement({ foo: 'bar'})
  .get('a') // Undefined and throws error
  .set('b', 'c')

Create special Minim Error object

With the latter, we can attach methods from every element, and then (try to) mimic promises.

minim.toElement({ foo: 'bar'})
  .get('a') // Undefined and should create an error
  .set('b', 'c') // The error object would simply pass itself along
  .then(function() { console.log('all good') })
  .catch(function(error) { console.log('oops', error) })

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    πŸ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. πŸ“ŠπŸ“ˆπŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❀️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.