'use strict';
-var escope = require('escope'),
- esprima = require('esprima'),
+var escope = require('./lib/escope'),
+ esprima = require('./lib/esprima'),
- // Given an array of definitions, determines if a definition already exists
- // for a given range. (escope detects variables twice if they are declared
- // and initialized simultaneously; this filters them.)
- isDefined = function (definitions, range) {
- var i, definition;
- for (i = 0; i < definitions.length; i += 1) {
- definition = definitions[i];
- if (definition[1] === range[0] && definition[2] === range[1]) {
- return true;
- }
- }
- return false;
- };
+ normal = 0,
+ bold = 1,
+ italic = 2;
-// Given code, returns an array of `[level, start, end]' tokens for
+// Given code, returns an array of `[start, end, level, style]' tokens for
// context-coloring.
module.exports = function (code) {
- var ast,
-
- analyzedScopes,
+ var analyzedScopes,
+ ast,
+ comment,
+ definition,
+ definitionsCount,
+ definitionsIndex,
i,
- scope,
- range,
-
+ isDefined,
j,
k,
- variable,
- mappedDefinitions,
- definition,
+ pointer,
+ range,
reference,
-
- definitions,
- references,
-
- scopes = [],
- symbols = [],
-
- comments,
- comment;
+ scope,
+ scopes,
+ tokens,
+ variable;
// Gracefully handle parse errors by doing nothing.
try {
process.exit(1);
}
+ scopes = [];
+ tokens = [];
+
for (i = 0; i < analyzedScopes.length; i += 1) {
scope = analyzedScopes[i];
// Having its level set implies it was already annotated.
// done now.
if (!scope.functionExpressionScope) {
range = scope.block.range;
- scopes.push([
- scope.level,
+ scopes.push(
range[0] + 1,
- range[1] + 1
- ]);
- definitions = [];
+ range[1] + 1,
+ scope.level,
+ normal
+ );
+ definitionsIndex = tokens.length;
+ definitionsCount = 0;
for (j = 0; j < scope.variables.length; j += 1) {
variable = scope.variables[j];
- mappedDefinitions = [];
+ definitionsCount += variable.defs.length;
for (k = 0; k < variable.defs.length; k += 1) {
definition = variable.defs[k];
range = definition.name.range;
- mappedDefinitions.push([
- scope.level,
+ tokens.push(
range[0] + 1,
- range[1] + 1
- ]);
+ range[1] + 1,
+ scope.level,
+ bold
+ );
}
- Array.prototype.push.apply(definitions, mappedDefinitions);
}
- references = [];
for (j = 0; j < scope.references.length; j += 1) {
reference = scope.references[j];
range = reference.identifier.range;
- if (!isDefined(definitions, range)) {
- references.push([
+ isDefined = false;
+ // Determine if a definition already exists for the
+ // range. (escope detects variables twice if they are
+ // declared and initialized simultaneously; this filters
+ // them.)
+ for (k = 0; k < definitionsCount; k += 1) {
+ pointer = definitionsIndex + (k * 4);
+ if (tokens[pointer] === range[0] + 1 &&
+ tokens[pointer + 1] === range[1] + 1) {
+ isDefined = true;
+ break;
+ }
+ }
+ if (!isDefined) {
+ tokens.push(
// Handle global references too.
- reference.resolved ? reference.resolved.scope.level : 0,
range[0] + 1,
- range[1] + 1
- ]);
+ range[1] + 1,
+ reference.resolved ? reference.resolved.scope.level : 0,
+ reference.__maybeImplicitGlobal ? bold : normal
+ );
}
}
- Array.prototype.push.apply(symbols, definitions);
- Array.prototype.push.apply(symbols, references);
}
}
}
- comments = [];
for (i = 0; i < ast.comments.length; i += 1) {
comment = ast.comments[i];
range = comment.range;
- comments.push([
- -1,
+ tokens.push(
range[0] + 1,
- range[1] + 1
- ]);
+ range[1] + 1,
+ -1,
+ italic
+ );
}
- return scopes.concat(symbols).concat(comments);
+ return scopes.concat(tokens);
};