]> code.delx.au - gnu-emacs-elpa/blob - scopifier.js
Remove styling from faces.
[gnu-emacs-elpa] / scopifier.js
1 'use strict';
2
3 var escope = require('./lib/escope'),
4 esprima = require('./lib/esprima');
5
6 // Given code, returns an array of tokens for context-coloring.
7 module.exports = function (code) {
8 var analyzedScopes,
9 ast,
10 comment,
11 definition,
12 definitionsCount,
13 definitionsIndex,
14 i,
15 isDefined,
16 j,
17 k,
18 pointer,
19 range,
20 reference,
21 scope,
22 scopes,
23 tokens,
24 variable;
25
26 // Gracefully handle parse errors by doing nothing.
27 try {
28 ast = esprima.parse(code, {
29 comment: true,
30 range: true
31 });
32 analyzedScopes = escope.analyze(ast).scopes;
33 } catch (error) {
34 process.exit(1);
35 }
36
37 scopes = [];
38 tokens = [];
39
40 for (i = 0; i < analyzedScopes.length; i += 1) {
41 scope = analyzedScopes[i];
42 // Having its level set implies it was already annotated.
43 if (scope.level === undefined) {
44 if (scope.upper) {
45 if (scope.upper.functionExpressionScope) {
46 // Pretend function expression scope doesn't exist.
47 scope.level = scope.upper.level;
48 scope.variables = scope.upper.variables.concat(scope.variables);
49 } else {
50 scope.level = scope.upper.level + 1;
51 }
52 } else {
53 // Base case.
54 scope.level = 0;
55 }
56 // We've only given the scope a level for posterity's sake. We're
57 // done now.
58 if (!scope.functionExpressionScope) {
59 range = scope.block.range;
60 scopes.push(
61 range[0] + 1,
62 range[1] + 1,
63 scope.level
64 );
65 definitionsIndex = tokens.length;
66 definitionsCount = 0;
67 for (j = 0; j < scope.variables.length; j += 1) {
68 variable = scope.variables[j];
69 definitionsCount += variable.defs.length;
70 for (k = 0; k < variable.defs.length; k += 1) {
71 definition = variable.defs[k];
72 range = definition.name.range;
73 tokens.push(
74 range[0] + 1,
75 range[1] + 1,
76 scope.level
77 );
78 }
79 }
80 for (j = 0; j < scope.references.length; j += 1) {
81 reference = scope.references[j];
82 range = reference.identifier.range;
83 isDefined = false;
84 // Determine if a definition already exists for the
85 // range. (escope detects variables twice if they are
86 // declared and initialized simultaneously; this filters
87 // them.)
88 for (k = 0; k < definitionsCount; k += 1) {
89 pointer = definitionsIndex + (k * 3);
90 if (tokens[pointer] === range[0] + 1 &&
91 tokens[pointer + 1] === range[1] + 1) {
92 isDefined = true;
93 break;
94 }
95 }
96 if (!isDefined) {
97 tokens.push(
98 // Handle global references too.
99 range[0] + 1,
100 range[1] + 1,
101 reference.resolved ? reference.resolved.scope.level : 0
102 );
103 }
104 }
105 }
106 }
107 }
108
109 for (i = 0; i < ast.comments.length; i += 1) {
110 comment = ast.comments[i];
111 range = comment.range;
112 tokens.push(
113 range[0] + 1,
114 range[1] + 1,
115 -1
116 );
117 }
118
119 return scopes.concat(tokens);
120 };