npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

cogz

v0.2.2

Published

A simple JS framework to help you understand what your code is doing.

Downloads

7

Readme

Cogz

A JavaScript microframework

Build Status Coverage Status

Synopsis

I created this in my limited spare time during June and July of 2016. I'm almost ready to use it myself, but I'm guessing others probably won't want to use it yet.

Code Example

    // Create one or more containers for namespacing.
    // There may be model, view, and controller containers,
    // but this demo will simplify things into just an app container.
    var app = {};
    cogz.add({
      container: app,
      cogName: 'watchedArray',
      value: ['arrayItem0']
    });

    // So now app has app.watchedArray.
    expect(app.watchedArray instanceof Array).to.equal(true);

    // And its current form is saved so that changes can be tracked.
    expect(cogz.changes.length).to.equal(1);
    expect(cogz.changes[0].cogName).to.equal('watchedArray');
    expect(cogz.changes[0].changeRecord.stringValue).to.equal('["arrayItem0"]');

    // By default, cogz saves the last 100 changes. Configuring that is easy.
    cogz.maxChangesToSave = 20;

    // The watchedArray cog also keeps some records in its own .asCog property.
    var arrayAsCog = app.watchedArray.asCog;
    expect(arrayAsCog.cogName).to.equal('watchedArray');

    // The cogz.changes array interleaves changes from all data cogs,
    // but if you're more interested in watchedArray, it tracks its own changes.
    expect(arrayAsCog.changes.length).to.equal(1);
    arrayAsCog.maxChangesToSave = 1000;

    // A cog can also be a function, set up in a similar way.
    // If a function needs to observe or inject, it specifies argGroups.
    cogz.add({
      container: app,
      cogName: 'arrayWatcherFunction',
      argGroups: {
        groupX: [
          { watch: 'watchedArray' },
          { include: 'newsObject' }
        ]
      },
      value: function (arr, obj) {
        obj.news.push(arr.asCog.cogName + ' has been changed');
      }
    });

    // So now app has app.arrayWatcherFunction()
    expect(typeof app.arrayWatcherFunction).to.equal('function');

    // It has one argGroup which is hoping for a 'newsObject'. Let's create one.
    cogz.add({
      container: app,
      cogName: 'newsObject',
      value: { news: [] }
    });

    // Now that all arguments are ready, arrayWatcherFunction automatically runs.
    expect(app.newsObject.news.length).to.equal(1);
    expect(cogz.changes.length).to.equal(3);
    expect(cogz.changes[0].cogName).to.equal('watchedArray');
    expect(cogz.changes[1].cogName).to.equal('newsObject');
    expect(cogz.changes[2].cogName).to.equal('newsObject');

    // Function cogs do not need to specify argGroups.
    cogz.add({
      container: app,
      cogName: 'arrayChanger',
      value: function (arr) {
        arr.push('newArrayItem');
      }
    });

    // When watchedArray is changed, arrayWatcherFunction runs again.
    app.arrayChanger(app.watchedArray);
    expect(app.watchedArray.length).to.equal(2);
    expect(app.watchedArray.asCog.changes.length).to.equal(2);
    expect(app.newsObject.news.length).to.equal(2);
    expect(app.newsObject.asCog.changes.length).to.equal(3);
    expect(cogz.changes.length).to.equal(5);

    // These saved changes can be used to implement undo (using cogz.replace).
    cogz.add({
      container: app,
      cogName: 'undo',
      value: function undo(dataCog) {
        var asCog = dataCog.asCog;
        // Remember where we are in the undo-redo history.
        if (!asCog.undoRedoIndex) {
          asCog.undoRedoIndex = asCog.changes.length - 1;
        }
        // To undo, we're going back to the previous state.
        asCog.undoRedoIndex = asCog.undoRedoIndex - 1;
        // And let's account for old states we deleted to honor maxChangesToSave
        var modifiedIndex = asCog.undoRedoIndex - asCog.numChangesDeleted;
        // If we have called undo too many times and ran out of older states, quit.
        if (!asCog.changes[modifiedIndex]) {
          return;
        }
        // Otherwise, grab the older stringified state.
        var olderStringValue = asCog.changes[modifiedIndex].stringValue;
        // Rehydrate it.
        var olderValue = JSON.parse(olderStringValue);
        // Replace the current value with the older value, and we're done.
        cogz.replace({
          cogName: asCog.cogName,
          value: olderValue
        });
      }
    });

    // Let's use our new undo function to remove newArrayItem from watchedArray.
    app.undo(app.watchedArray);
    expect(app.watchedArray.length).to.equal(1); // Length went down again.
    expect(app.newsObject.news.length).to.equal(3); // Watchers still work.
    expect(cogz.changes.length).to.equal(7); // This .changes increased by 2.
    expect(app.watchedArray.asCog.changes.length).to.equal(3); // This by 1.

    // For cogz users who do not want to keep up with their own containers,
    // Cogz includes an empty object named 'x' for 'extensions', and
    // if the user does not specify a container, cogz.x is used as the default..
    cogz.add({
      cogName: 'cogWithNoSpecifiedContainer',
      value: { someProp: 'someVal' }
    });
    expect(cogz.x.cogWithNoSpecifiedContainer.someProp).to.equal('someVal');

Why I created Cogz

First, I must confess to being full of doubt and even anxiety about this. Why write my own framework when there are so many excellent, battle-hardened frameworks already available? Perhaps the overarching reason is that I want to create apps that are easier for me to reason about. Cogz does that for me. Will it do that for other developers? I don't know. But just in case it helps someone, I'll go ahead and mention some benefits I see in Cogz.

Debugging

When something goes wrong with my code, the culprits line up and confess. For example, to see what changed an object (or array) named myData, I can simply look in myData.asCog.changerCogs and see them all. And I can see more details (e.g., their chronological order and what changes they made) by checking app.myData.asCog.changes (in isolation) or by checking cogz.changes (in the context of the rest of the app).

Refactoring

When I'm thinking of changing a part of my code (i.e., modifying a cog such as app.myFunction), I can quickly find out what other cogs are depending on it, like by checking app.myFunction.neederCogs. For an object or an array (in this example: app.myData), the dependent cogz are divided into app.myData.nonChangerCogs and app.myData.changerCogs.

Ease of reading code

Cogz reinforces the convention of putting everything a function will need in its parameters. The argGroups also clarifies in what contexts the function will be used.

Modularity

Cogz makes it easy for me to keep data separated from the functions that use it. This naturally leads to separating model and view and controller code, but it is more complete.

No error redirection

No more long lists of errors that don't even tell you what part of your code is to blame. Here, when you mess up, the error points directly at your code because your errors have not been intercepted, redirected, and logged from some meaningless error handler.

Minimal magic

Cogz does just a few easy-to-understand bits of magic:

  1. It wraps functions in order to stringify and thus detect changes in arguments.
  2. It maintains an accessible lists of observers that can respond to those changes. This simplicity means that I don't have to learn dozens of apis just to develop a simple app. Instead, I can just look up how to do something in vanilla JavaScript and see it work the first time.

Universal/isomorphic

Cogz works both in the browser and in Node.js, without depending on any bundler/converter.

No tree of components

Every cog, as a vertex/node with all of its edge relationships revealed, provides an abstracted, simplified view of the app. In a tree structure, it's hard to figure out how a component can live in multiple levels of a tree, but in a graph like this, I don't have to deal with the question of what "level" a cog is on because there are no required levels here. I just connect to whatever cog I need.

Installation

npm install cogz --save

Tests

npm test

Contributors

Welcome.

License

ISC (like MIT)