You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
typesetting/pitfall/pdfkit/node_modules/lexical-scope/index.js

176 lines
5.2 KiB
JavaScript

var astw = require('astw');
module.exports = function (src) {
var locals = {};
var implicit = {};
var exported = {};
if (typeof src === 'string') {
src = String(src).replace(/^#![^\n]*\n/, '');
}
if (src && typeof src === 'object'
&& typeof src.copy === 'function' && typeof src.toString === 'function') {
src = src.toString('utf8');
}
var walk = astw(src);
walk(function (node) {
if (node.type === 'VariableDeclaration') {
// take off the leading `var `
var id = getScope(node);
for (var i = 0; i < node.declarations.length; i++) {
var d = node.declarations[i];
locals[id][d.id.name] = d;
}
}
else if (node.type === 'CatchClause') {
var id = getScope(node);
locals[id][node.param.name] = node.param
}
else if (isFunction(node)) {
var id = getScope(node.parent);
if (node.id) locals[id][node.id.name] = node;
var nid = node.params.length && getScope(node);
if (nid && !locals[nid]) locals[nid] = {};
for (var i = 0; i < node.params.length; i++) {
var p = node.params[i];
locals[nid][p.name] = p;
}
}
});
walk(function (node) {
if (node.type === 'Identifier'
&& lookup(node) === undefined) {
if (node.parent.type === 'Property'
&& node.parent.key === node) return;
if (node.parent.type === 'MemberExpression'
&& node.parent.property === node) return;
if (isFunction(node.parent)) return;
if (node.parent.type === 'LabeledStatement') return;
if (node.parent.type === 'ContinueStatement') return;
if (node.parent.type === 'BreakStatement') return;
if (node.parent.type === 'AssignmentExpression') {
var isLeft0 = node.parent.left.type === 'MemberExpression'
&& node.parent.left.object === node.name
;
var isLeft1 = node.parent.left.type === 'Identifier'
&& node.parent.left.name === node.name
;
if (isLeft0 || isLeft1) {
exported[node.name] = keyOf(node).length;
}
}
if (!exported[node.name]
|| exported[node.name] < keyOf(node).length) {
implicit[node.name] = keyOf(node).length;
}
}
});
var localScopes = {};
var lks = objectKeys(locals);
for (var i = 0; i < lks.length; i++) {
var key = lks[i];
localScopes[key] = objectKeys(locals[key]);
}
return {
locals: localScopes,
globals: {
implicit: objectKeys(implicit),
exported: objectKeys(exported)
}
};
function lookup (node) {
for (var p = node; p; p = p.parent) {
if (isFunction(p) || p.type === 'Program') {
var id = getScope(p);
if (locals[id][node.name]) {
return id;
}
}
}
return undefined;
}
function getScope (node) {
for (
var p = node;
!isFunction(p) && p.type !== 'Program';
p = p.parent
);
var id = idOf(p);
if (!locals[id]) locals[id] = {};
return id;
}
};
function isFunction (x) {
return x.type === 'FunctionDeclaration'
|| x.type === 'FunctionExpression'
;
}
function idOf (node) {
var id = [];
for (var n = node; n.type !== 'Program'; n = n.parent) {
var key = keyOf(n).join('.');
id.unshift(key);
}
return id.join('.');
}
function keyOf (node) {
if (node.lexicalScopeKey) return node.lexicalScopeKey;
var p = node.parent;
var ks = objectKeys(p);
var kv = { keys : [], values : [], top : [] };
for (var i = 0; i < ks.length; i++) {
var key = ks[i];
kv.keys.push(key);
kv.values.push(p[key]);
kv.top.push(undefined);
if (isArray(p[key])) {
var keys = objectKeys(p[key]);
kv.keys.push.apply(kv.keys, keys);
kv.values.push.apply(kv.values, p[key]);
var nkeys = [];
for (var j = 0; j < keys.length; j++) nkeys.push(key);
kv.top.push.apply(kv.top, nkeys);
}
}
var ix = indexOf(kv.values, node);
var res = [];
if (kv.top[ix]) res.push(kv.top[ix]);
if (kv.keys[ix]) res.push(kv.keys[ix]);
if (node.parent.type === 'CallExpression') {
res.unshift.apply(res, keyOf(node.parent.parent));
}
return node.lexicalScopeKey = res;
}
var isArray = Array.isArray || function (xs) {
return Object.prototype.toString.call(xs) === '[object Array]';
};
var objectKeys = Object.keys || function (obj) {
var keys = [];
for (var key in obj) keys.push(key);
return keys;
};
function indexOf (xs, x) {
if (xs.indexOf) return xs.indexOf(x);
for (var i = 0; i < xs.length; i++) {
if (x === xs[i]) return i;
}
return -1;
}