Analyzing JavaScript React Native: the Zooniverse case study

Zooniverse is a JavaScript / React/ React Native system. We first clone it:

rootDirectory := 'zooniverse' asFileReference.
  
rootDirectory ensureDeleteAll.
repository := IceRepositoryCreator
		fromUrl: 'git@github.com:zooniverse/mobile.git'
		to: rootDirectory
  

Reasoning About Package Dependencies

Let's start with a simple question: How many dependencies does this project have? And how many do not point to react-native libraries?

The answers can be found in package.json:

packageJson := rootDirectory / 'package.json'
  

Of course, you can find the answer by reading, but you are here to learn how not to read. So, how do we do it without reading? Well, JSON happens to be a reasonably structured piece of data. So, let's parse it:

dictionary := STONJSON fromString: packageJson contents.
dependencies := dictionary at: #dependencies
  

So, how many dependencies are there? It's a simple query:

dependencies size
  

What about the dependencies that do not point to react-native libraries? Another query:

dependencies associations
	reject: [ :each | each key includesSubstring: 'react-native' ]
  

This is a rather small problem. Yet, even here we can outcompete reading by means of custom tools.

Reasoning About React Dependencies

A more complicated problem is that of reasoning about dependencies between React components. For example, are there cycles between components?

To answer this question, we create a model:

model := GtReactImporter new
	parserClass: JSXParser;
	importDirectory: rootDirectory;
	model.
  

Now, inspect the components and pick the Dependencies view:

model allReactComponents
  

In this case, to answer the question effectively, we need an analysis at the level of React. To this end, we created a custom importer that understands React patterns (specifically, component definitions and dependencies), extended the base model with React specific entities, and created a custom visualization.