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

@eigenjoy/cq

v0.1.1

Published

query code with selectors

Downloads

6

Readme

cq: Code Query Dolpins

A tool to extract code snippets using selectors (instead of line numbers)

Install

$ npm install --global @eigenjoy/cq

Usage

$ cq <query> <file>

# or

$ cat file | cq <query>

Examples

Say we have a file examples/basics.js with the following code:

// examples/basics.js
const bye = function() {
  return 'bye';
}
bye(); // -> 'bye'

let Farm = () => 'cow';

class Barn {
  constructor(height, width) {
    this.height = height;
    this.width = width;
  }
  
  calcArea() {
    return this.height * this.width;
  }
}

Get the bye() function:

$ cq '.bye' examples/basics.js

const bye = function() {
  return 'bye';
}

Get the bye() function plus the invocation line after using a modifier:

$ cq '.bye:+1' examples/basics.js

const bye = function() {
  return 'bye';
}
bye(); // -> 'bye'

Get the calcArea function on the Barn class:

$ cq '.Barn .calcArea' examples/basics.js

  calcArea() {
    return this.height * this.width;
  }

Get the range of constructor through calcArea, inclusive, of the Barn class

$ cq '.Barn .constructor-.calcArea' examples/basics.js

  constructor(height, width) {
    this.height = height;
    this.width = width;
  }

  calcArea() {
    return this.height * this.width;
  }

Features

  • Extract chunks of code from text using robust selectors (vs. brittle line numbers)
  • Locate ranges of code using identifiers
  • Parses ES6 & JSX (with babylon)

Motivation

When writing blog posts, tutorials, and books about programming there's a tension between code that gets copied and pasted into the text and runnable code on disk.

If you copy and paste your code into the copy, then you're prone to typos, missing steps. When things change, you have to update all of the copypasta and eyeball it to make sure you didn't miss anything. Mistakes are really easy to make because you can't really test code that's in your manuscript without it's context.

A better solution is to keep your code (or steps of your code) as runnable examples on disk. You can then load the code into your manuscript with some pre-processing.

The problem with the code-on-disk approach is how to designate the ranges of code you wish to import. Line numbers are the most obvious approach, but if you add or remove a line of code, then you have to adjust all line numbers accordingly.

cq is a tool that lets you specify selectors to extract portions of code. Rather than using brittle line numbers, instead cq lets you query your code. It uses babylon to understand the semantics of your code and will extract the appropriate lines.

Query Grammar

.Identifier

Examples:

  • .Simple
  • .render

A dot . preceding JavaScript identifier characters represents an identifier.

In this code:

const Simple = React.createClass({
  render() {
    return (
      <div>
        {this.renderName()}
      </div>
    )
  }
});

The query .Simple would find the whole const Simple = ... variable declaration.

Searches for identifiers traverse the whole tree, relative to the parent, and return the first match. This means that you do not have to start at the root. In this case you could query for .render and would receive the render() function. That said, creating more specific queries can help in the case where you want to disambiguate.

[space]

Examples:

  • .Simple .render
  • .foo .bar .baz

The space in a query selection expression designates a parent for the next identifier. For instance, the query .Simple .render will first look for the identifier Simple and then find the render function that is a child of Simple.

The space indicates to search for the next identifier anywhere within the parent. That is, it does not require that the child identifier be a direct child the parent.

In this way the space is analogous to the space in a CSS selector. E.g. search for any child that matches. cq does not yet support the > notation (which would require the identifier to be a direct child), but we may in the future.

Range

Examples:

  • .constructor-.calcArea
  • .Barn .constructor-.calcArea

Given:

class Barn {
  constructor(height, width) {
    this.height = height;
    this.width = width;
  }
  
  calcArea() {
    return this.height * this.width;
  }
}

A pair of identifiers joined by a dash - form a range. A range will emit the code from the beginning of the match of the first identifier to the end of the match of the last.

You can use a parent identifier to limit the scope of the search of the range as in the query: .Barn .constructor-.calcArea

Modifiers

Examples:

  • .bye:+1
  • .bye:+1,-1

Given:

// here is the bye function (emitted with -1)
const bye = function() {
  return 'bye';
}
bye(); // -> 'bye' (emitted with +1)

After the selection expression you pass additional query modifiers. Query modifiers follow a colon and are comma separated. The two modifiers currently supported are:

  • adding additional lines following an identifier (or range)
  • adding additional lines preceding an identifier (or range)

Lines following the identifier are designated by +n whereas lines preceding are specified by -n, where n is the number of lines desired.

Library Usage

var cq = require('@eigenjoy/cq');
var results = cq(codeString, query);
console.log(results.code);

Related

  • GraspJS - another tool to search JavaScript code based on structure
  • Pygments - a handy tool to colorize code snippets on the command line
  • ASTExplorer - an online tool to explore the AST of your code

Fullstack React Book

This repo was written and is maintained by the Fullstack React team. If you're looking to learn React, there's no faster way than by spending a few hours with the Fullstack React book.

License

MIT