// cell audit [] - Test-compile all .ce and .cm scripts // // Usage: // cell audit Audit all packages // cell audit Audit specific package // cell audit . Audit current directory package // cell audit --function-hoist [] Report function hoisting usage // // Compiles every script in the package(s) to check for errors. // Continues past failures and reports all issues at the end. var shop = use('internal/shop') var pkg = use('package') var fd = use('fd') var target_package = null var function_hoist = false var i = 0 var run = function() { var packages = null var tokenize_mod = null var parse_mod = null var hoist_files = 0 var hoist_refs = 0 var total_ok = 0 var total_errors = 0 var total_scripts = 0 var all_failures = [] var all_unresolved = [] var summary = null for (i = 0; i < length(args); i++) { if (args[i] == '--help' || args[i] == '-h') { log.console("Usage: cell audit [--function-hoist] []") log.console("") log.console("Test-compile all .ce and .cm scripts in package(s).") log.console("Reports all errors without stopping at the first failure.") log.console("") log.console("Flags:") log.console(" --function-hoist Report files that rely on function hoisting") return } else if (args[i] == '--function-hoist') { function_hoist = true } else if (!starts_with(args[i], '-')) { target_package = args[i] } } // Resolve local paths if (target_package) { target_package = shop.resolve_locator(target_package) } if (target_package) { packages = [target_package] } else { packages = shop.list_packages() } if (function_hoist) { tokenize_mod = use('tokenize') parse_mod = use('parse') arrfor(packages, function(p) { var scripts = shop.get_package_scripts(p) var pkg_dir = shop.get_package_dir(p) if (length(scripts) == 0) return arrfor(scripts, function(script) { var src_path = pkg_dir + '/' + script var src = null var tok_result = null var ast = null var scan = function() { if (!fd.is_file(src_path)) return src = text(fd.slurp(src_path)) tok_result = tokenize_mod(src, script) ast = parse_mod(tok_result.tokens, src, script, tokenize_mod) if (ast._hoisted_fns != null && length(ast._hoisted_fns) > 0) { log.console(p + '/' + script + ":") hoist_files = hoist_files + 1 arrfor(ast._hoisted_fns, function(ref) { var msg = " " + ref.name if (ref.line != null) msg = msg + " (ref line " + text(ref.line) if (ref.decl_line != null) msg = msg + ", declared line " + text(ref.decl_line) if (ref.line != null) msg = msg + ")" log.console(msg) hoist_refs = hoist_refs + 1 }) } } disruption { // skip files that fail to parse } scan() }) }) log.console("") log.console("Summary: " + text(hoist_files) + " files with function hoisting, " + text(hoist_refs) + " total forward references") return } arrfor(packages, function(p) { var scripts = shop.get_package_scripts(p) var result = null var resolution = null if (length(scripts) == 0) return log.console("Auditing " + p + " (" + text(length(scripts)) + " scripts)...") result = shop.build_package_scripts(p) total_ok = total_ok + result.ok total_errors = total_errors + length(result.errors) total_scripts = total_scripts + result.total arrfor(result.errors, function(e) { all_failures[] = p + ": " + e }) // Check use() resolution resolution = shop.audit_use_resolution(p) arrfor(resolution.unresolved, function(u) { all_unresolved[] = p + '/' + u.script + ": use('" + u.module + "') cannot be resolved" }) }) log.console("") if (length(all_failures) > 0) { log.console("Failed scripts:") arrfor(all_failures, function(f) { log.console(" " + f) }) log.console("") } if (length(all_unresolved) > 0) { log.console("Unresolved modules:") arrfor(all_unresolved, function(u) { log.console(" " + u) }) log.console("") } summary = "Audit complete: " + text(total_ok) + "/" + text(total_scripts) + " scripts compiled" if (total_errors > 0) summary = summary + ", " + text(total_errors) + " failed" if (length(all_unresolved) > 0) summary = summary + ", " + text(length(all_unresolved)) + " unresolved use() calls" log.console(summary) } run()