@reyalp/debug-utils
Version:
ts transformers for debug
638 lines (637 loc) • 35.8 kB
JavaScript
"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
__setModuleDefault(result, mod);
return result;
};
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.transform = void 0;
const path_1 = __importStar(require("path"));
const resolve_1 = __importDefault(require("resolve"));
const typescript_1 = __importDefault(require("typescript"));
const logger_1 = require("./logger");
const package_name = '@reyalp/debug-utils';
const modules = {
logger: {
types: _enum('Logger', 'LogCallChain1', 'LogCallChain2'),
rt: _enum('format', 'filter', 'inspect', 'write'),
chained: _enum('msg', 'dump', 'trace'),
methods: _enum('tag', 'error', 'warn', 'info', 'verbose', 'debug', 'silly'),
levels: {
error: logger_1.LogLevel.ERROR,
warn: logger_1.LogLevel.WARN,
info: logger_1.LogLevel.INFO,
verbose: logger_1.LogLevel.VERBOSE,
debug: logger_1.LogLevel.DEBUG,
silly: logger_1.LogLevel.SILLY
}
},
introspect: _enum('introspect', 'quoteval')
};
const transform = (program, opts, compiler) => (context) => {
var _a, _b;
const options = program.getCompilerOptions();
const common_dir = program.getCommonSourceDirectory();
const root_dirs = [...((_a = options.rootDirs) !== null && _a !== void 0 ? _a : []), (_b = options.rootDir) !== null && _b !== void 0 ? _b : '', common_dir.endsWith('/') ? common_dir : (common_dir + '/')].filter(Boolean);
const printer = typescript_1.default.createPrinter({ omitTrailingSemicolon: true, removeComments: true, preserveSourceNewlines: false });
const checker = program.getTypeChecker();
const factory = context.factory;
const host = typescript_1.default.createCompilerHost(program.getCompilerOptions());
return (source) => {
var _a, _b, _c, _d;
const source_dir = (0, path_1.parse)(source.fileName).dir;
const resolved = typescript_1.default.resolveModuleName(package_name, source.fileName, program.getCompilerOptions(), host);
const resolved_lib_index = (_b = (_a = resolved.resolvedModule) === null || _a === void 0 ? void 0 : _a.resolvedFileName) !== null && _b !== void 0 ? _b : resolve_1.default.sync(package_name, { basedir: source_dir });
const resolved_lib_dir = (0, path_1.parse)(resolved_lib_index).dir;
if (opts === null || opts === void 0 ? void 0 : opts.progress) {
console.log(`TSC: ${source.fileName.slice((_d = (_c = root_dirs.find(r => source.fileName.startsWith(r))) === null || _c === void 0 ? void 0 : _c.length) !== null && _d !== void 0 ? _d : 0)}`);
}
void _debug_print_node;
return typescript_1.default.visitNode(source, visit);
// === SOURCE_LOCATION =============================================================================
function format_node_name(node, fallback = '<expr>') {
return typescript_1.default.isPropertyAccessExpression(node) ? format_call_expr(node, fallback)
: typescript_1.default.isCallExpression(node) ? format_prop_access_expr(node, fallback)
: is_simple_node(node) ? printer.printNode(typescript_1.default.EmitHint.Expression, node, source)
: (fallback + _debug_print_node(node));
}
function format_prop_access_expr(node, fallback = '<expr>') {
const fn = _strip_paren_down(node.expression);
return typescript_1.default.isPropertyAccessExpression(fn) ? format_call_expr(fn, fallback) : format_node_name(fn, fallback);
}
function format_call_expr(node, fallback = '<expr>') {
var _a;
if (typescript_1.default.isCallExpression(node.expression)) {
const lhs = (_a = format_prop_access_expr(node.expression, fallback)) !== null && _a !== void 0 ? _a : format_node_name(node, fallback);
return lhs + '.' + format_node_name(node.name, fallback);
}
else {
return format_node_name(node.expression, fallback) + '.' + format_node_name(node.name, fallback);
}
}
function collect_source_location(node, ups) {
const loc = typescript_1.default.getLineAndCharacterOfPosition(source, node.getStart(source));
const line = loc.line + 1;
const column = loc.character + 1;
const file = collect_file_info(source.fileName, root_dirs);
function _mk_item(consume) {
return (node) => {
const { kind, name } = consume(node);
const loc = typescript_1.default.getLineAndCharacterOfPosition(source, node.getStart(source));
const line = loc.line + 1;
const column = loc.character + 1;
return { kind, name, line, column };
};
}
const spine = unwind(node, ups);
const symbols = spine.map(_mk_item(root => {
var _a, _b;
if (!root)
return { kind: 'toplevel', name: '<toplevel>' };
if (typescript_1.default.isSourceFile(root))
return { kind: 'toplevel', name: '<toplevel>' };
if (typescript_1.default.isArrowFunction(root))
return { kind: 'func', name: 'λ' };
if (typescript_1.default.isConstructorDeclaration(root))
return { kind: 'func', name: '(ctor)' };
if (typescript_1.default.isFunctionDeclaration(root))
return { kind: 'func', name: root.name ? format_node_name(root.name) : 'λ' };
if (typescript_1.default.isFunctionExpression(root))
return { kind: 'func', name: root.name ? format_node_name(root.name) : 'λ' };
if (typescript_1.default.isCallExpression(root))
return { kind: 'call', name: format_node_name(root.expression, '<call>') };
if (typescript_1.default.isArrayLiteralExpression(root))
return { kind: 'elem', name: '[]' };
if (typescript_1.default.isPropertyAssignment(root))
return { kind: 'prop', name: format_node_name(root.name, '<assign>') };
if (typescript_1.default.isPropertyDeclaration(root))
return { kind: 'prop', name: format_node_name(root.name, '<assign>') };
if (typescript_1.default.isClassDeclaration(root))
return { kind: 'class', name: (_b = (_a = root.name) === null || _a === void 0 ? void 0 : _a.text) !== null && _b !== void 0 ? _b : '*Annoymous' };
if (typescript_1.default.isMethodDeclaration(root))
return { kind: 'func', name: format_node_name(root.name) };
if (typescript_1.default.isModuleDeclaration(root))
return { kind: 'namespace', name: format_node_name(root.name) };
if (typescript_1.default.isVariableDeclaration(root)) {
if (typescript_1.default.isArrayBindingPattern(root.name))
return { kind: 'var', name: '[]' };
if (typescript_1.default.isObjectBindingPattern(root.name))
return { kind: 'var', name: '{}' };
if (typescript_1.default.isEmptyBindingPattern(root.name))
return { kind: 'var', name: '{}' };
return { kind: 'var', name: format_node_name(root.name) };
}
if (typescript_1.default.isAssignmentExpression(root)) {
if (typescript_1.default.isArrayLiteralExpression(root.left))
return { kind: 'var', name: '[]' };
return { kind: 'var', name: format_node_name(root.left, '<assign>') };
}
return { kind: 'expr', name: format_node_name(root, `<${typescript_1.default.SyntaxKind[root.kind]}>`) };
}));
const sympath = symbols.filter(c => c.kind !== 'toplevel').map(c => c.name).reverse().join('.') || '<toplevel>';
return { line, column, symbols, spine, file, sympath };
}
function _flatten_source_location_expr_prop_chain(node) {
const path = [];
while (typescript_1.default.isPropertyAccessExpression(node)) {
path.push(node.name.text);
node = _strip_paren_down(node.expression);
}
// node should be ts.Identifier
if (typescript_1.default.isIdentifier(node))
path.push(node.text);
return path.reverse();
}
function _is_source_location_expr(node) {
if (_should_skip(node))
return false;
const root = _get_prop_chain_root(node);
if (!root)
return false;
const ty = checker.getTypeAtLocation(root);
const tyname = checker.typeToString(ty);
if (tyname !== 'SourceLocation')
return false;
const sym = checker.getSymbolAtLocation(root); // should be `source_location`
if (!sym)
return false;
const decls = sym.getDeclarations();
if (!decls || decls.length === 0)
return false;
return _is_imported_from_this_package(decls[0]);
}
// path is something like `source_location` / `source_location.file.name` / `source_location.up`...
function _create_source_location_expr(node, path) {
const ups = path.slice(1).filter(t => t === 'up');
const trail = path.slice(ups.length + 1).join('.');
const info = collect_source_location(node, ups.length);
const full = `${info.file.rel_path}:${info.line} ${info.sympath}`;
const create_symbols = () => factory.createArrayLiteralExpression(info.symbols.map(s => factory.createObjectLiteralExpression([
factory.createPropertyAssignment('kind', factory.createStringLiteral(s.kind)),
factory.createPropertyAssignment('name', factory.createStringLiteral(s.name)),
factory.createPropertyAssignment('line', factory.createNumericLiteral(s.line)),
factory.createPropertyAssignment('column', factory.createNumericLiteral(s.column))
])));
const create_file = () => factory.createObjectLiteralExpression(Object.entries(info.file).map(([name, val]) => factory.createPropertyAssignment(name, factory.createStringLiteral(val))));
if (trail === 'symbols')
return create_symbols();
if (trail === 'file')
return create_file();
if (trail === 'sympath')
return factory.createStringLiteral(info.sympath);
if (trail === 'full')
return factory.createStringLiteral(full);
const { line, column } = info;
for (const [name, val] of Object.entries({ line, column })) {
if (trail === name)
return factory.createNumericLiteral(val);
}
for (const [name, val] of Object.entries(info.file)) {
if (trail === 'file.' + name)
return factory.createStringLiteral(val);
}
return factory.createObjectLiteralExpression([
factory.createPropertyAssignment('line', factory.createNumericLiteral(line)),
factory.createPropertyAssignment('column', factory.createNumericLiteral(column)),
factory.createPropertyAssignment('sympath', factory.createStringLiteral(info.sympath)),
factory.createPropertyAssignment('full', factory.createStringLiteral(full)),
factory.createPropertyAssignment('symbols', create_symbols()),
factory.createPropertyAssignment('file', create_file())
]);
}
function _check_source_location_param_initializer(node) {
const sig = checker.getResolvedSignature(node);
if (!sig)
return undefined;
const decl = sig.getDeclaration();
if (!decl)
return undefined;
const parameters = decl.parameters;
const index = parameters.findIndex(p => p.initializer && _is_source_location_expr(p.initializer));
if (index === -1)
return undefined;
return { index, initializer: parameters[index].initializer };
}
function _try_transform_source_location_call_param(node) {
if (!typescript_1.default.isCallExpression(node))
return undefined;
const p = _check_source_location_param_initializer(node);
if (!p)
return undefined;
const fn = visit(node.expression);
const initializer = _strip_paren_down(p.initializer);
const path = _flatten_source_location_expr_prop_chain(initializer);
const sl = _create_source_location_expr(node, path);
const args = _list(Math.max(node.arguments.length, p.index + 1))
.map(i => node.arguments[i] ? visit(node.arguments[i]) : factory.createVoidZero())
.map((expr, i) => i === p.index ? factory.createBinaryExpression(expr, typescript_1.default.SyntaxKind.QuestionQuestionToken, sl) : expr);
return factory.updateCallExpression(node, fn, node.typeArguments, args);
}
function _try_transform_source_location_expr(node) {
const parent = _strip_paren_up(node.parent);
if (parent && typescript_1.default.isParameter(parent))
return undefined;
if (!typescript_1.default.isExpression(node))
return undefined;
if (!_is_source_location_expr(node))
return undefined;
const path = _flatten_source_location_expr_prop_chain(node); // path[0] is always source_location (or it's alias)
return _create_source_location_expr(node, path);
}
// =================================================================================================
// === INTROSPECTION ===============================================================================
function _check_introspection_call(node) {
var _a;
const decl = (_a = checker.getResolvedSignature(node)) === null || _a === void 0 ? void 0 : _a.declaration;
if (!decl)
return undefined;
if (!typescript_1.default.isFunctionDeclaration(decl))
return undefined;
if (!decl.name)
return undefined;
if (!typescript_1.default.isIdentifier(decl.name))
return undefined;
if (!modules.introspect[decl.name.text])
return undefined;
const fn = node.expression;
if (!typescript_1.default.isIdentifier(fn))
return undefined;
const sym = checker.getSymbolAtLocation(fn);
if (!sym)
return undefined;
const decls = sym.getDeclarations();
if (!decls || decls.length === 0)
return undefined;
if (!_is_imported_from_this_package(decls[0]))
return undefined;
return decl.name.text;
}
function _try_transform_introspection_call(node) {
if (!typescript_1.default.isCallExpression(node))
return undefined;
const fn = _check_introspection_call(node);
if (!fn)
return undefined;
if (fn === modules.introspect.introspect) {
const code = printer.printNode(typescript_1.default.EmitHint.Expression, node.arguments[0], source);
const arg = visit(node.arguments[0]);
return factory.createArrayLiteralExpression([factory.createStringLiteral(code), arg]);
}
else if (fn === modules.introspect.quoteval) {
// quoteval: (expr, j, print)
const code = printer.printNode(typescript_1.default.EmitHint.Expression, node.arguments[0], source);
const args = node.arguments.map(visit);
const j_fallback = factory.createStringLiteral(' = ');
const j = args[1] ? factory.createBinaryExpression(args[1], typescript_1.default.SyntaxKind.QuestionQuestionToken, j_fallback) : j_fallback;
const p_fallback = factory.createPropertyAccessExpression(node.expression, '_inspect');
const p_fn = args[2] ? factory.createBinaryExpression(args[2], typescript_1.default.SyntaxKind.QuestionQuestionToken, p_fallback) : p_fallback;
const p = factory.createCallExpression(p_fn, undefined, [args[0]]);
return factory.createTemplateExpression(factory.createTemplateHead(code), [
factory.createTemplateSpan(j, factory.createTemplateMiddle('')),
factory.createTemplateSpan(p, factory.createTemplateTail(''))
]);
}
}
function _validate_introspection_usage(node) {
if (_should_skip(node))
return;
if (!typescript_1.default.isIdentifier(node))
return;
if (typescript_1.default.isImportSpecifier(node.parent))
return;
const sym = checker.getSymbolAtLocation(node);
if (!sym)
return;
const decls = sym.getDeclarations();
if (!decls || decls.length === 0)
return;
const decl = decls[0];
if (!typescript_1.default.isImportSpecifier(decl))
return;
if (!_is_imported_from_this_package(decl))
return;
const name = _import_names(decl);
if (!modules.introspect[name])
return;
if (typescript_1.default.isCallExpression(node))
return;
compiler.addDiagnostic(_make_diag(node, 'invalid introspect usage', `only '${node.text}(...)' is allowed`));
}
// =================================================================================================
// === LOGGER ======================================================================================
function _check_log_call(node) {
var _a, _b;
const fn = _strip_paren_down(node.expression);
if (!typescript_1.default.isPropertyAccessExpression(fn))
return undefined;
const lhs = fn.expression;
const ty = checker.getTypeAtLocation(lhs);
const tyname = checker.typeToString(ty);
if (!modules.logger.types[tyname])
return undefined;
if (!modules.logger.chained[fn.name.text] && !modules.logger.methods[fn.name.text])
return undefined;
const decl = (_b = (_a = ty.symbol) === null || _a === void 0 ? void 0 : _a.getDeclarations()) === null || _b === void 0 ? void 0 : _b[0];
if (!decl)
return undefined;
let decl_source = decl.parent;
while (decl_source && !typescript_1.default.isSourceFile(decl_source)) {
decl_source = decl_source.parent;
}
return decl_source.fileName === (0, path_1.join)(resolved_lib_dir, 'logger.d.ts') ? tyname : undefined;
}
function _flatten_log_call_chain(node) {
/*
* CallExpression
* / \
* PropertyAccessExpression (args)
* / \
* CallExpression Identifier (method name)
* ........
*/
const chain = [];
let start = node;
while (typescript_1.default.isCallExpression(start)) {
const ty = _check_log_call(start);
if (!ty)
break;
const args = [...start.arguments];
const prop = _strip_paren_down(start.expression);
if (!typescript_1.default.isPropertyAccessExpression(prop)) {
// not possible...
throw new Error(`call.parent is not PropertyAccessExpression!`);
}
chain.push({ name: prop.name.text, args });
start = prop.expression;
}
return { start, chain: chain.reverse() };
}
function _log_format_arg(expr, rt) {
if (typescript_1.default.isLiteralExpression(expr))
return expr;
const node = visit(expr);
const ty = checker.getTypeAtLocation(expr);
if (ty.getFlags() & (typescript_1.default.TypeFlags.StringLike)) {
return node;
}
if (ty.getFlags() & (typescript_1.default.TypeFlags.NumberLike | typescript_1.default.TypeFlags.BooleanLike | typescript_1.default.TypeFlags.EnumLike)) {
return node;
}
return factory.createCallExpression(factory.createPropertyAccessExpression(rt, modules.logger.rt.inspect), undefined, [node, factory.createStringLiteral(checker.typeToString(ty)), rt]);
}
function _log_format_dump_arg(expr, rt) {
return factory.createTemplateExpression(factory.createTemplateHead(`${printer.printNode(typescript_1.default.EmitHint.Expression, expr, source)} = `), [factory.createTemplateSpan(_log_format_arg(expr, rt), factory.createTemplateTail(''))]);
}
function _create_log_stmts(call, { chain, start } = _flatten_log_call_chain(call)) {
var _a, _b;
// <logger>.<method₁>(args₁).<method₂>(args₂)...
// =>
// {
// var logger = <logger>, rt = logger.rt, level = <level>, tags = <tags>
// if (rt.filter(ll, tags, rt)) {
// var file = <file>, line = <line>, name = <name>
// rt.write(rt.format([...], ll, tags, file, line, name, rt), ll, tags, file, line, name, rt)
// }
// }
const logger_var = typescript_1.default.isIdentifier(start) ? start : factory.createUniqueName('logger');
const rt_var = factory.createUniqueName('rt');
const tags_var = factory.createUniqueName('tags');
const level_var = factory.createUniqueName('log_level');
const extra_tags = chain.filter(c => c.name === modules.logger.methods.tag).flatMap(c => c.args).map((visit));
const log_level_call = chain.find(c => modules.logger.levels[c.name]);
const log_level = log_level_call ? modules.logger.levels[log_level_call.name] : logger_1.LogLevel.INFO;
const args = chain
.filter(c => c.name !== modules.logger.methods.tag && c.name !== modules.logger.chained.trace)
.flatMap(c => c.args.map(arg => c.name === modules.logger.chained.dump ? _log_format_dump_arg(arg, rt_var) : _log_format_arg(arg, rt_var)));
const logger_tags = factory.createPropertyAccessExpression(logger_var, 'tags');
const tags_init = extra_tags.length === 0 ? logger_tags : factory.createArrayLiteralExpression([
factory.createSpreadElement(logger_tags), ...extra_tags
]);
const decl_vars = factory.createVariableStatement(undefined, factory.createVariableDeclarationList([
...typescript_1.default.isIdentifier(start) ? [] : [factory.createVariableDeclaration(logger_var, undefined, undefined, start)],
factory.createVariableDeclaration(rt_var, undefined, undefined, factory.createPropertyAccessExpression(logger_var, 'rt')),
factory.createVariableDeclaration(tags_var, undefined, undefined, tags_init),
factory.createVariableDeclaration(level_var, undefined, undefined, factory.createNumericLiteral(log_level))
]));
const pred_expr = factory.createCallExpression(factory.createPropertyAccessExpression(rt_var, modules.logger.rt.filter), undefined, [level_var, tags_var, rt_var]);
const info = collect_source_location(call, 1);
const file_var = factory.createUniqueName('file');
const line_var = factory.createUniqueName('line');
const name_var = factory.createUniqueName('name');
const trace_cfg = (_b = (_a = chain.find(c => c.name === modules.logger.chained.trace)) === null || _a === void 0 ? void 0 : _a.args) === null || _b === void 0 ? void 0 : _b[0];
const trace_cfg_expr = trace_cfg && visit(trace_cfg);
const wrap_trace_init = (expr) => !trace_cfg_expr ? expr
: !typescript_1.default.isBooleanLiteral(trace_cfg_expr) ? factory.createConditionalExpression(trace_cfg_expr, undefined, expr, undefined, factory.createVoidZero())
: trace_cfg_expr.kind === typescript_1.default.SyntaxKind.TrueKeyword ? expr : factory.createVoidZero();
const write_decls = factory.createVariableStatement(undefined, factory.createVariableDeclarationList([
factory.createVariableDeclaration(file_var, undefined, undefined, wrap_trace_init(factory.createStringLiteral((0, path_1.join)(info.file.rel_dir, info.file.name)))),
factory.createVariableDeclaration(line_var, undefined, undefined, wrap_trace_init(factory.createNumericLiteral(info.line))),
factory.createVariableDeclaration(name_var, undefined, undefined, wrap_trace_init(factory.createStringLiteral(info.sympath)))
]));
const trace_args = [level_var, tags_var, rt_var, file_var, line_var, name_var];
const format_call = factory.createCallExpression(factory.createPropertyAccessExpression(rt_var, modules.logger.rt.format), undefined, [factory.createArrayLiteralExpression(args), ...trace_args]);
const write_call = factory.createCallExpression(factory.createPropertyAccessExpression(rt_var, modules.logger.rt.write), undefined, [format_call, ...trace_args]);
const write_stmt = factory.createBlock([write_decls, factory.createExpressionStatement(write_call)]);
const log_stmt = factory.createIfStatement(pred_expr, write_stmt);
return [decl_vars, log_stmt];
}
function _try_transform_log_call(node) {
if (typescript_1.default.isExpressionStatement(node) && typescript_1.default.isCallExpression(node.expression) && _check_log_call(node.expression)) {
return factory.createBlock(_create_log_stmts(node.expression));
}
else if (typescript_1.default.isCallExpression(node) && _check_log_call(node)) {
const call_chain = _flatten_log_call_chain(node);
const logger_var = factory.createUniqueName('logger');
const decl = factory.createVariableDeclaration(logger_var, undefined, undefined, call_chain.start);
return factory.createImmediatelyInvokedArrowFunction([
factory.createVariableStatement(undefined, [decl]),
..._create_log_stmts(node, { chain: call_chain.chain, start: logger_var }),
factory.createReturnStatement(logger_var)
]);
}
return undefined;
}
// =================================================================================================
function _debug_print_node(node) {
return `${printer.printNode(typescript_1.default.EmitHint.Unspecified, node, source)} :: ${typescript_1.default.SyntaxKind[node.kind]}`;
}
function _validate_import(node) {
var _a;
if (!typescript_1.default.isImportClause(node))
return;
const nb = node.namedBindings;
if (!node.name && (!nb || !typescript_1.default.isNamespaceImport(nb)))
return;
const specifier = (_a = node.parent) === null || _a === void 0 ? void 0 : _a.moduleSpecifier;
if (!typescript_1.default.isStringLiteral(specifier))
return;
if (specifier.text !== package_name)
return;
compiler.addDiagnostic(_make_diag(node.parent, `module specifier`, `use import { ... } from '${package_name}' instead`));
}
function validate_node(node) {
_validate_import(node);
_validate_introspection_usage(node);
}
function next(node) {
return typescript_1.default.visitEachChild(node, visit, context);
}
function visit(node) {
var _a, _b, _c, _d;
validate_node(node);
return ((_d = (_c = (_b = (_a = _try_transform_log_call(node)) !== null && _a !== void 0 ? _a : _try_transform_introspection_call(node)) !== null && _b !== void 0 ? _b : _try_transform_source_location_call_param(node)) !== null && _c !== void 0 ? _c : _try_transform_source_location_expr(node)) !== null && _d !== void 0 ? _d : next(node));
}
};
};
exports.transform = transform;
exports.default = exports.transform;
const is_stop_root = (node) => typescript_1.default.isArrowFunction(node)
|| typescript_1.default.isFunctionExpression(node)
|| typescript_1.default.isFunctionDeclaration(node)
|| typescript_1.default.isModuleDeclaration(node)
|| typescript_1.default.isClassDeclaration(node)
|| typescript_1.default.isClassExpression(node)
|| typescript_1.default.isVariableDeclaration(node)
|| typescript_1.default.isMethodDeclaration(node)
|| typescript_1.default.isMethodDeclaration(node)
|| typescript_1.default.isPropertyDeclaration(node)
|| typescript_1.default.isPropertyAssignment(node)
|| typescript_1.default.isAssignmentExpression(node)
|| typescript_1.default.isConstructorDeclaration(node)
|| typescript_1.default.isParameter(node)
|| typescript_1.default.isCallExpression(node);
function seek_stop_root(node) {
while (node && node.parent && !is_stop_root(node)) {
node = _strip_paren_up(node.parent);
}
return node;
}
function skip_stop_root(node) {
while (node) {
if (!typescript_1.default.isCallExpression(node))
return _strip_paren_up(node.parent);
// node is CallExpression
node = _strip_paren_up(node.parent);
while (typescript_1.default.isPropertyAccessExpression(node)) {
node = _strip_paren_up(node.parent);
}
}
return node;
}
function unwind(node, ups) {
const spine = [];
while (node && node.parent) {
spine.push(node = seek_stop_root(node));
node = skip_stop_root(node);
}
return spine.slice(ups);
}
function is_simple_node(node) {
if (node.kind === typescript_1.default.SyntaxKind.ThisKeyword)
return true;
if (typescript_1.default.isIdentifier(node))
return true;
if (typescript_1.default.isPrivateIdentifier(node))
return true;
if (typescript_1.default.isNoSubstitutionTemplateLiteral(node))
return true;
if (typescript_1.default.isStringLiteral(node))
return true;
if (typescript_1.default.isNumericLiteral(node))
return true;
if (typescript_1.default.isBigIntLiteral(node))
return true;
if (typescript_1.default.isPropertyAccessExpression(node))
return is_simple_node(node.expression) && is_simple_node(node.name);
if (typescript_1.default.isElementAccessExpression(node))
return is_simple_node(node.expression) && is_simple_node(node.argumentExpression);
if (typescript_1.default.isCallExpression(node))
return is_simple_node(node.expression) && node.arguments.every(is_simple_node);
if (typescript_1.default.isComputedPropertyName(node))
return is_simple_node(node.expression);
return false;
}
function trim_leading_slash(s) {
return (s !== '/' && s.startsWith('/')) ? s.slice(1) : s;
}
function collect_file_info(full_path, root_dirs) {
var _a, _b;
const p = path_1.default.parse(full_path);
const rel = root_dirs.find(dir => full_path.startsWith(dir));
const full_dir = p.dir;
const rel_path = trim_leading_slash(full_path.slice((_a = rel === null || rel === void 0 ? void 0 : rel.length) !== null && _a !== void 0 ? _a : 0));
const rel_dir = trim_leading_slash(full_dir.slice((_b = rel === null || rel === void 0 ? void 0 : rel.length) !== null && _b !== void 0 ? _b : 0));
const ext = p.ext;
const name = p.name;
const fullname = p.base;
return { full_path, full_dir, rel_path, rel_dir, ext, name, fullname };
}
function _get_prop_chain_root(node) {
while (typescript_1.default.isPropertyAccessExpression(node)) {
node = _strip_paren_down(node.expression);
}
return typescript_1.default.isIdentifier(node) ? node : undefined;
}
function _is_imported_from_this_package(decl) {
if (!typescript_1.default.isImportSpecifier(decl))
return false;
const import_decl = decl.parent.parent.parent;
const specifier = import_decl.moduleSpecifier;
if (!typescript_1.default.isStringLiteral(specifier))
return false;
return specifier.text === package_name;
}
function _enum(...names) {
return Object.fromEntries(names.map(k => [k, k]));
}
function _import_names(decl) {
var _a;
return ((_a = decl.propertyName) !== null && _a !== void 0 ? _a : decl.name).text;
}
function _make_diag(node, key, message, category = typescript_1.default.DiagnosticCategory.Error) {
const code = `(${package_name})`;
return typescript_1.default.createDiagnosticForNode(node, { code, key, category, message });
}
function _list(length) {
return Array.from({ length }).map((_, i) => i);
}
function _strip_paren_up(node) {
while (node && typescript_1.default.isParenthesizedExpression(node)) {
node = node.parent;
}
return node;
}
function _strip_paren_down(node) {
while (typescript_1.default.isParenthesizedExpression(node)) {
node = node.expression;
}
return node;
}
function _should_skip(node) {
return !node.parent
|| typescript_1.default.isImportSpecifier(node.parent)
|| typescript_1.default.isJsxOpeningElement(node.parent)
|| typescript_1.default.isJsxClosingElement(node.parent)
|| typescript_1.default.isJsxSelfClosingElement(node.parent);
}