new syntax for internals
This commit is contained in:
@@ -865,6 +865,7 @@ $_.clock(_ => {
|
|||||||
var pkg = file_info ? file_info.package : null
|
var pkg = file_info ? file_info.package : null
|
||||||
env.use = function(path) { return shop.use(path, pkg) }
|
env.use = function(path) { return shop.use(path, pkg) }
|
||||||
env.args = _cell.args.arg
|
env.args = _cell.args.arg
|
||||||
|
env.log = log
|
||||||
|
|
||||||
var script = text(fd.slurp(prog_path))
|
var script = text(fd.slurp(prog_path))
|
||||||
var ast = analyze(script, prog_path)
|
var ast = analyze(script, prog_path)
|
||||||
|
|||||||
Binary file not shown.
245
internal/shop.cm
245
internal/shop.cm
@@ -35,7 +35,8 @@ function ensure_dir(path) {
|
|||||||
if (fd.stat(path).isDirectory) return
|
if (fd.stat(path).isDirectory) return
|
||||||
var parts = array(path, '/')
|
var parts = array(path, '/')
|
||||||
var current = starts_with(path, '/') ? '/' : ''
|
var current = starts_with(path, '/') ? '/' : ''
|
||||||
for (var i = 0; i < length(parts); i++) {
|
var i = 0
|
||||||
|
for (i = 0; i < length(parts); i++) {
|
||||||
if (parts[i] == '') continue
|
if (parts[i] == '') continue
|
||||||
current = current + parts[i] + '/'
|
current = current + parts[i] + '/'
|
||||||
if (!fd.stat(current).isDirectory) {
|
if (!fd.stat(current).isDirectory) {
|
||||||
@@ -119,12 +120,16 @@ function split_explicit_package_import(path)
|
|||||||
if (!looks_explicit) return null
|
if (!looks_explicit) return null
|
||||||
|
|
||||||
// Find the longest prefix that is an installed package
|
// Find the longest prefix that is an installed package
|
||||||
for (var i = length(parts) - 1; i >= 1; i--) {
|
var i = 0
|
||||||
var pkg_candidate = text(array(parts, 0, i), '/')
|
var pkg_candidate = null
|
||||||
var mod_path = text(array(parts, i), '/')
|
var mod_path = null
|
||||||
|
var candidate_dir = null
|
||||||
|
for (i = length(parts) - 1; i >= 1; i--) {
|
||||||
|
pkg_candidate = text(array(parts, 0, i), '/')
|
||||||
|
mod_path = text(array(parts, i), '/')
|
||||||
if (!mod_path || length(mod_path) == 0) continue
|
if (!mod_path || length(mod_path) == 0) continue
|
||||||
|
|
||||||
var candidate_dir = get_packages_dir() + '/' + safe_package_path(pkg_candidate)
|
candidate_dir = get_packages_dir() + '/' + safe_package_path(pkg_candidate)
|
||||||
if (fd.is_file(candidate_dir + '/cell.toml'))
|
if (fd.is_file(candidate_dir + '/cell.toml'))
|
||||||
return {package: pkg_candidate, path: mod_path}
|
return {package: pkg_candidate, path: mod_path}
|
||||||
|
|
||||||
@@ -158,8 +163,9 @@ function abs_path_to_package(package_dir)
|
|||||||
return 'core'
|
return 'core'
|
||||||
}
|
}
|
||||||
// Also check if core_dir is a symlink pointing to package_dir
|
// Also check if core_dir is a symlink pointing to package_dir
|
||||||
|
var core_target = null
|
||||||
if (fd.is_link(core_dir)) {
|
if (fd.is_link(core_dir)) {
|
||||||
var core_target = fd.readlink(core_dir)
|
core_target = fd.readlink(core_dir)
|
||||||
if (core_target == package_dir || fd.realpath(core_dir) == package_dir) {
|
if (core_target == package_dir || fd.realpath(core_dir) == package_dir) {
|
||||||
return 'core'
|
return 'core'
|
||||||
}
|
}
|
||||||
@@ -181,9 +187,11 @@ function abs_path_to_package(package_dir)
|
|||||||
|
|
||||||
// For local directories (e.g., linked targets), read the package name from cell.toml
|
// For local directories (e.g., linked targets), read the package name from cell.toml
|
||||||
var _toml_path = package_dir + '/cell.toml'
|
var _toml_path = package_dir + '/cell.toml'
|
||||||
|
var content = null
|
||||||
|
var cfg = null
|
||||||
if (fd.is_file(_toml_path)) {
|
if (fd.is_file(_toml_path)) {
|
||||||
var content = text(fd.slurp(_toml_path))
|
content = text(fd.slurp(_toml_path))
|
||||||
var cfg = toml.decode(content)
|
cfg = toml.decode(content)
|
||||||
if (cfg.package)
|
if (cfg.package)
|
||||||
return cfg.package
|
return cfg.package
|
||||||
}
|
}
|
||||||
@@ -316,12 +324,16 @@ Shop.verify_package_name = function(pkg) {
|
|||||||
// Convert module package to download URL
|
// Convert module package to download URL
|
||||||
Shop.get_download_url = function(pkg, commit_hash) {
|
Shop.get_download_url = function(pkg, commit_hash) {
|
||||||
var info = Shop.resolve_package_info(pkg)
|
var info = Shop.resolve_package_info(pkg)
|
||||||
|
var parts = null
|
||||||
|
var host = null
|
||||||
|
var user = null
|
||||||
|
var repo = null
|
||||||
|
|
||||||
if (info == 'gitea') {
|
if (info == 'gitea') {
|
||||||
var parts = array(pkg, '/')
|
parts = array(pkg, '/')
|
||||||
var host = parts[0]
|
host = parts[0]
|
||||||
var user = parts[1]
|
user = parts[1]
|
||||||
var repo = parts[2]
|
repo = parts[2]
|
||||||
|
|
||||||
return 'https://' + host + '/' + user + '/' + repo + '/archive/' + commit_hash + '.zip'
|
return 'https://' + host + '/' + user + '/' + repo + '/archive/' + commit_hash + '.zip'
|
||||||
}
|
}
|
||||||
@@ -332,12 +344,16 @@ Shop.get_download_url = function(pkg, commit_hash) {
|
|||||||
// Get the API URL for checking remote git commits
|
// Get the API URL for checking remote git commits
|
||||||
Shop.get_api_url = function(pkg) {
|
Shop.get_api_url = function(pkg) {
|
||||||
var info = Shop.resolve_package_info(pkg)
|
var info = Shop.resolve_package_info(pkg)
|
||||||
|
var parts = null
|
||||||
|
var host = null
|
||||||
|
var user = null
|
||||||
|
var repo = null
|
||||||
|
|
||||||
if (info == 'gitea') {
|
if (info == 'gitea') {
|
||||||
var parts = array(pkg, '/')
|
parts = array(pkg, '/')
|
||||||
var host = parts[0]
|
host = parts[0]
|
||||||
var user = parts[1]
|
user = parts[1]
|
||||||
var repo = parts[2]
|
repo = parts[2]
|
||||||
return 'https://' + host + '/api/v1/repos/' + user + '/' + repo + '/branches/'
|
return 'https://' + host + '/api/v1/repos/' + user + '/' + repo + '/branches/'
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -393,9 +409,12 @@ function inject_env(inject) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Add capability injections
|
// Add capability injections
|
||||||
for (var i = 0; i < length(inject); i++) {
|
var i = 0
|
||||||
var inj = inject[i]
|
var inj = null
|
||||||
var key = trim(inj, '$')
|
var key = null
|
||||||
|
for (i = 0; i < length(inject); i++) {
|
||||||
|
inj = inject[i]
|
||||||
|
key = trim(inj, '$')
|
||||||
if (key == 'fd') env[key] = fd
|
if (key == 'fd') env[key] = fd
|
||||||
else env[key] = my$_[key]
|
else env[key] = my$_[key]
|
||||||
}
|
}
|
||||||
@@ -409,15 +428,19 @@ function inject_bindings_code(inject) {
|
|||||||
var runtime_fns = ['logical', 'some', 'every', 'starts_with', 'ends_with',
|
var runtime_fns = ['logical', 'some', 'every', 'starts_with', 'ends_with',
|
||||||
'actor', 'is_actor', 'log', 'send',
|
'actor', 'is_actor', 'log', 'send',
|
||||||
'fallback', 'parallel', 'race', 'sequence']
|
'fallback', 'parallel', 'race', 'sequence']
|
||||||
for (var i = 0; i < length(runtime_fns); i++) {
|
var i = 0
|
||||||
var fn = runtime_fns[i]
|
var fn = null
|
||||||
|
var inj = null
|
||||||
|
var key = null
|
||||||
|
for (i = 0; i < length(runtime_fns); i++) {
|
||||||
|
fn = runtime_fns[i]
|
||||||
push(lines, `var ${fn} = env["${fn}"];`)
|
push(lines, `var ${fn} = env["${fn}"];`)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Capability bindings ($delay, $start, etc.)
|
// Capability bindings ($delay, $start, etc.)
|
||||||
for (var i = 0; i < length(inject); i++) {
|
for (i = 0; i < length(inject); i++) {
|
||||||
var inj = inject[i]
|
inj = inject[i]
|
||||||
var key = trim(inj, '$')
|
key = trim(inj, '$')
|
||||||
push(lines, `var $${key} = env["${key}"];`)
|
push(lines, `var $${key} = env["${key}"];`)
|
||||||
}
|
}
|
||||||
return text(lines, '\n')
|
return text(lines, '\n')
|
||||||
@@ -474,26 +497,34 @@ function resolve_mod_fn(path, pkg) {
|
|||||||
// given a path and a package context
|
// given a path and a package context
|
||||||
// return module info about where it was found
|
// return module info about where it was found
|
||||||
function resolve_locator(path, ctx)
|
function resolve_locator(path, ctx)
|
||||||
{
|
{
|
||||||
var explicit = split_explicit_package_import(path)
|
var explicit = split_explicit_package_import(path)
|
||||||
|
var explicit_path = null
|
||||||
|
var fn = null
|
||||||
|
var core_dir = null
|
||||||
|
var core_file_path = null
|
||||||
|
var is_core = null
|
||||||
|
var scope = null
|
||||||
|
var alias_path = null
|
||||||
|
|
||||||
if (explicit) {
|
if (explicit) {
|
||||||
if (is_internal_path(explicit.path) && ctx && explicit.package != ctx)
|
if (is_internal_path(explicit.path) && ctx && explicit.package != ctx)
|
||||||
explicit = null
|
explicit = null
|
||||||
}
|
}
|
||||||
if (explicit) {
|
if (explicit) {
|
||||||
var explicit_path = get_packages_dir() + '/' + safe_package_path(explicit.package) + '/' + explicit.path
|
explicit_path = get_packages_dir() + '/' + safe_package_path(explicit.package) + '/' + explicit.path
|
||||||
if (fd.is_file(explicit_path)) {
|
if (fd.is_file(explicit_path)) {
|
||||||
var fn = resolve_mod_fn(explicit_path, explicit.package)
|
fn = resolve_mod_fn(explicit_path, explicit.package)
|
||||||
return {path: explicit_path, scope: SCOPE_PACKAGE, symbol: fn}
|
return {path: explicit_path, scope: SCOPE_PACKAGE, symbol: fn}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 1. If no context, resolve from core only
|
// 1. If no context, resolve from core only
|
||||||
if (!ctx) {
|
if (!ctx) {
|
||||||
var core_dir = Shop.get_core_dir()
|
core_dir = Shop.get_core_dir()
|
||||||
var core_file_path = core_dir + '/' + path
|
core_file_path = core_dir + '/' + path
|
||||||
if (fd.is_file(core_file_path)) {
|
if (fd.is_file(core_file_path)) {
|
||||||
var fn = resolve_mod_fn(core_file_path, 'core')
|
fn = resolve_mod_fn(core_file_path, 'core')
|
||||||
return {path: core_file_path, scope: SCOPE_CORE, symbol: fn}
|
return {path: core_file_path, scope: SCOPE_CORE, symbol: fn}
|
||||||
}
|
}
|
||||||
return null
|
return null
|
||||||
@@ -502,7 +533,7 @@ function resolve_locator(path, ctx)
|
|||||||
// check in ctx package
|
// check in ctx package
|
||||||
// If ctx is an absolute path (starts with /), use it directly
|
// If ctx is an absolute path (starts with /), use it directly
|
||||||
// Otherwise, look it up in the packages directory
|
// Otherwise, look it up in the packages directory
|
||||||
var ctx_dir
|
var ctx_dir = null
|
||||||
if (starts_with(ctx, '/')) {
|
if (starts_with(ctx, '/')) {
|
||||||
ctx_dir = ctx
|
ctx_dir = ctx
|
||||||
} else {
|
} else {
|
||||||
@@ -511,10 +542,10 @@ function resolve_locator(path, ctx)
|
|||||||
var ctx_path = ctx_dir + '/' + path
|
var ctx_path = ctx_dir + '/' + path
|
||||||
|
|
||||||
if (fd.is_file(ctx_path)) {
|
if (fd.is_file(ctx_path)) {
|
||||||
var fn = resolve_mod_fn(ctx_path, ctx)
|
fn = resolve_mod_fn(ctx_path, ctx)
|
||||||
// Check if ctx is the core package (either by name or by path)
|
// Check if ctx is the core package (either by name or by path)
|
||||||
var is_core = (ctx == 'core') || (ctx_dir == Shop.get_core_dir())
|
is_core = (ctx == 'core') || (ctx_dir == Shop.get_core_dir())
|
||||||
var scope = is_core ? SCOPE_CORE : SCOPE_LOCAL
|
scope = is_core ? SCOPE_CORE : SCOPE_LOCAL
|
||||||
return {path: ctx_path, scope: scope, symbol: fn}
|
return {path: ctx_path, scope: scope, symbol: fn}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -524,24 +555,24 @@ function resolve_locator(path, ctx)
|
|||||||
// check for aliased dependency
|
// check for aliased dependency
|
||||||
var alias = pkg_tools.split_alias(ctx, path)
|
var alias = pkg_tools.split_alias(ctx, path)
|
||||||
if (alias) {
|
if (alias) {
|
||||||
var alias_path = get_packages_dir() + '/' + safe_package_path(alias.package) + '/' + alias.path
|
alias_path = get_packages_dir() + '/' + safe_package_path(alias.package) + '/' + alias.path
|
||||||
if (fd.is_file(alias_path)) {
|
if (fd.is_file(alias_path)) {
|
||||||
var fn = resolve_mod_fn(alias_path, ctx)
|
fn = resolve_mod_fn(alias_path, ctx)
|
||||||
return {path: alias_path, scope:SCOPE_PACKAGE, symbol:fn}
|
return {path: alias_path, scope:SCOPE_PACKAGE, symbol:fn}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var package_path = get_packages_dir() + '/' + safe_package_path(path)
|
var package_path = get_packages_dir() + '/' + safe_package_path(path)
|
||||||
if (fd.is_file(package_path)) {
|
if (fd.is_file(package_path)) {
|
||||||
var fn = resolve_mod_fn(package_path, ctx)
|
fn = resolve_mod_fn(package_path, ctx)
|
||||||
return {path: package_path, scope: SCOPE_PACKAGE, symbol: fn}
|
return {path: package_path, scope: SCOPE_PACKAGE, symbol: fn}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 4. Check core as fallback
|
// 4. Check core as fallback
|
||||||
var core_dir = Shop.get_core_dir()
|
core_dir = Shop.get_core_dir()
|
||||||
var core_file_path = core_dir + '/' + path
|
core_file_path = core_dir + '/' + path
|
||||||
if (fd.is_file(core_file_path)) {
|
if (fd.is_file(core_file_path)) {
|
||||||
var fn = resolve_mod_fn(core_file_path, 'core')
|
fn = resolve_mod_fn(core_file_path, 'core')
|
||||||
return {path: core_file_path, scope: SCOPE_CORE, symbol: fn}
|
return {path: core_file_path, scope: SCOPE_CORE, symbol: fn}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -573,7 +604,7 @@ Shop.open_package_dylib = function(pkg) {
|
|||||||
var link_target = link.get_target(pkg)
|
var link_target = link.get_target(pkg)
|
||||||
var resolved_pkg = link_target ? link_target : pkg
|
var resolved_pkg = link_target ? link_target : pkg
|
||||||
|
|
||||||
var pkg_dir;
|
var pkg_dir = null
|
||||||
if (starts_with(resolved_pkg, '/')) {
|
if (starts_with(resolved_pkg, '/')) {
|
||||||
pkg_dir = resolved_pkg
|
pkg_dir = resolved_pkg
|
||||||
} else {
|
} else {
|
||||||
@@ -581,9 +612,11 @@ Shop.open_package_dylib = function(pkg) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var toml_path = pkg_dir + '/cell.toml'
|
var toml_path = pkg_dir + '/cell.toml'
|
||||||
|
var content = null
|
||||||
|
var cfg = null
|
||||||
if (fd.is_file(toml_path)) {
|
if (fd.is_file(toml_path)) {
|
||||||
var content = text(fd.slurp(toml_path))
|
content = text(fd.slurp(toml_path))
|
||||||
var cfg = toml.decode(content)
|
cfg = toml.decode(content)
|
||||||
if (cfg.dependencies) {
|
if (cfg.dependencies) {
|
||||||
arrfor(array(cfg.dependencies), function(alias, i) {
|
arrfor(array(cfg.dependencies), function(alias, i) {
|
||||||
var dep_pkg = cfg.dependencies[alias]
|
var dep_pkg = cfg.dependencies[alias]
|
||||||
@@ -606,12 +639,19 @@ Shop.open_package_dylib = function(pkg) {
|
|||||||
// Core is never loaded as a dynamic library via dlopen
|
// Core is never loaded as a dynamic library via dlopen
|
||||||
function resolve_c_symbol(path, package_context) {
|
function resolve_c_symbol(path, package_context) {
|
||||||
var explicit = split_explicit_package_import(path)
|
var explicit = split_explicit_package_import(path)
|
||||||
|
var sym = null
|
||||||
|
var dl_path = null
|
||||||
|
var _path = null
|
||||||
|
var core_sym = null
|
||||||
|
var canon_pkg = null
|
||||||
|
var mod_name = null
|
||||||
|
|
||||||
if (explicit) {
|
if (explicit) {
|
||||||
if (is_internal_path(explicit.path) && package_context && explicit.package != package_context)
|
if (is_internal_path(explicit.path) && package_context && explicit.package != package_context)
|
||||||
explicit = null
|
explicit = null
|
||||||
}
|
}
|
||||||
if (explicit) {
|
if (explicit) {
|
||||||
var sym = make_c_symbol(explicit.package, explicit.path)
|
sym = make_c_symbol(explicit.package, explicit.path)
|
||||||
if (os.internal_exists(sym)) {
|
if (os.internal_exists(sym)) {
|
||||||
return {
|
return {
|
||||||
symbol: function() { return os.load_internal(sym) },
|
symbol: function() { return os.load_internal(sym) },
|
||||||
@@ -622,7 +662,7 @@ function resolve_c_symbol(path, package_context) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Shop.open_package_dylib(explicit.package)
|
Shop.open_package_dylib(explicit.package)
|
||||||
var dl_path = get_lib_path(explicit.package)
|
dl_path = get_lib_path(explicit.package)
|
||||||
if (open_dls[dl_path] && os.dylib_has_symbol(open_dls[dl_path], sym)) {
|
if (open_dls[dl_path] && os.dylib_has_symbol(open_dls[dl_path], sym)) {
|
||||||
return {
|
return {
|
||||||
symbol: function() { return os.dylib_symbol(open_dls[dl_path], sym) },
|
symbol: function() { return os.dylib_symbol(open_dls[dl_path], sym) },
|
||||||
@@ -635,8 +675,8 @@ function resolve_c_symbol(path, package_context) {
|
|||||||
|
|
||||||
// If no package context, only check core internal symbols
|
// If no package context, only check core internal symbols
|
||||||
if (!package_context || package_context == 'core') {
|
if (!package_context || package_context == 'core') {
|
||||||
var _path = replace(path, '/', '_')
|
_path = replace(path, '/', '_')
|
||||||
var core_sym = `js_${_path}_use`
|
core_sym = `js_${_path}_use`
|
||||||
if (os.internal_exists(core_sym)) {
|
if (os.internal_exists(core_sym)) {
|
||||||
return {
|
return {
|
||||||
symbol: function() { return os.load_internal(core_sym) },
|
symbol: function() { return os.load_internal(core_sym) },
|
||||||
@@ -648,7 +688,7 @@ function resolve_c_symbol(path, package_context) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 1. Check own package first (internal, then dylib)
|
// 1. Check own package first (internal, then dylib)
|
||||||
var sym = make_c_symbol(package_context, path)
|
sym = make_c_symbol(package_context, path)
|
||||||
if (os.internal_exists(sym)) {
|
if (os.internal_exists(sym)) {
|
||||||
return {
|
return {
|
||||||
symbol: function() { return os.load_internal(sym) },
|
symbol: function() { return os.load_internal(sym) },
|
||||||
@@ -658,7 +698,7 @@ function resolve_c_symbol(path, package_context) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Shop.open_package_dylib(package_context)
|
Shop.open_package_dylib(package_context)
|
||||||
var dl_path = get_lib_path(package_context)
|
dl_path = get_lib_path(package_context)
|
||||||
|
|
||||||
if (open_dls[dl_path] && os.dylib_has_symbol(open_dls[dl_path], sym)) {
|
if (open_dls[dl_path] && os.dylib_has_symbol(open_dls[dl_path], sym)) {
|
||||||
return {
|
return {
|
||||||
@@ -674,10 +714,10 @@ function resolve_c_symbol(path, package_context) {
|
|||||||
// 2. Check aliased package imports (e.g. 'prosperon/sprite')
|
// 2. Check aliased package imports (e.g. 'prosperon/sprite')
|
||||||
var pkg_alias = get_import_package(path)
|
var pkg_alias = get_import_package(path)
|
||||||
if (pkg_alias) {
|
if (pkg_alias) {
|
||||||
var canon_pkg = get_aliased_package(path, package_context)
|
canon_pkg = get_aliased_package(path, package_context)
|
||||||
if (canon_pkg) {
|
if (canon_pkg) {
|
||||||
var mod_name = get_import_name(path)
|
mod_name = get_import_name(path)
|
||||||
var sym = make_c_symbol(canon_pkg, mod_name)
|
sym = make_c_symbol(canon_pkg, mod_name)
|
||||||
|
|
||||||
// Check internal first
|
// Check internal first
|
||||||
if (os.internal_exists(sym)) {
|
if (os.internal_exists(sym)) {
|
||||||
@@ -691,7 +731,7 @@ function resolve_c_symbol(path, package_context) {
|
|||||||
|
|
||||||
// Then check dylib
|
// Then check dylib
|
||||||
Shop.open_package_dylib(canon_pkg)
|
Shop.open_package_dylib(canon_pkg)
|
||||||
var dl_path = get_lib_path(canon_pkg)
|
dl_path = get_lib_path(canon_pkg)
|
||||||
if (open_dls[dl_path] && os.dylib_has_symbol(open_dls[dl_path], sym)) {
|
if (open_dls[dl_path] && os.dylib_has_symbol(open_dls[dl_path], sym)) {
|
||||||
return {
|
return {
|
||||||
symbol: function() { return os.dylib_symbol(open_dls[dl_path], sym) },
|
symbol: function() { return os.dylib_symbol(open_dls[dl_path], sym) },
|
||||||
@@ -704,7 +744,7 @@ function resolve_c_symbol(path, package_context) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 3. Check core internal symbols (core is never a dynamic library)
|
// 3. Check core internal symbols (core is never a dynamic library)
|
||||||
var core_sym = `js_${replace(path, '/', '_')}_use`
|
core_sym = `js_${replace(path, '/', '_')}_use`
|
||||||
if (os.internal_exists(core_sym)) {
|
if (os.internal_exists(core_sym)) {
|
||||||
return {
|
return {
|
||||||
symbol: function() { return os.load_internal(core_sym) },
|
symbol: function() { return os.load_internal(core_sym) },
|
||||||
@@ -732,31 +772,37 @@ function resolve_module_info(path, package_context) {
|
|||||||
if (min_scope == 999)
|
if (min_scope == 999)
|
||||||
return null
|
return null
|
||||||
|
|
||||||
var cache_key
|
var cache_key = null
|
||||||
|
var real_path = null
|
||||||
|
var real_info = null
|
||||||
|
var pkg_alias = null
|
||||||
|
var canon_pkg = null
|
||||||
|
var mod_name = null
|
||||||
|
|
||||||
if (mod_resolve.scope == SCOPE_CORE) {
|
if (mod_resolve.scope == SCOPE_CORE) {
|
||||||
cache_key = 'core/' + path
|
cache_key = 'core/' + path
|
||||||
} else if (mod_resolve.scope < 900 && mod_resolve.path) {
|
} else if (mod_resolve.scope < 900 && mod_resolve.path) {
|
||||||
var real_path = fd.realpath(mod_resolve.path)
|
real_path = fd.realpath(mod_resolve.path)
|
||||||
if (real_path) {
|
if (real_path) {
|
||||||
var real_info = Shop.file_info(real_path)
|
real_info = Shop.file_info(real_path)
|
||||||
if (real_info.package && real_info.name)
|
if (real_info.package && real_info.name)
|
||||||
cache_key = real_info.package + '/' + real_info.name
|
cache_key = real_info.package + '/' + real_info.name
|
||||||
else
|
else
|
||||||
cache_key = real_path
|
cache_key = real_path
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!cache_key) {
|
if (!cache_key) {
|
||||||
if (min_scope == SCOPE_CORE)
|
if (min_scope == SCOPE_CORE)
|
||||||
cache_key = 'core/' + path
|
cache_key = 'core/' + path
|
||||||
else if (min_scope == SCOPE_LOCAL && package_context)
|
else if (min_scope == SCOPE_LOCAL && package_context)
|
||||||
cache_key = package_context + '/' + path
|
cache_key = package_context + '/' + path
|
||||||
else if (min_scope == SCOPE_PACKAGE) {
|
else if (min_scope == SCOPE_PACKAGE) {
|
||||||
var pkg_alias = get_import_package(path)
|
pkg_alias = get_import_package(path)
|
||||||
if (pkg_alias) {
|
if (pkg_alias) {
|
||||||
var canon_pkg = get_canonical_package(pkg_alias, package_context)
|
canon_pkg = get_canonical_package(pkg_alias, package_context)
|
||||||
if (canon_pkg) {
|
if (canon_pkg) {
|
||||||
var mod_name = get_import_name(path)
|
mod_name = get_import_name(path)
|
||||||
cache_key = canon_pkg + '/' + mod_name
|
cache_key = canon_pkg + '/' + mod_name
|
||||||
} else
|
} else
|
||||||
cache_key = path
|
cache_key = path
|
||||||
@@ -807,20 +853,26 @@ function execute_module(info)
|
|||||||
var c_resolve = info.c_resolve
|
var c_resolve = info.c_resolve
|
||||||
var mod_resolve = info.mod_resolve
|
var mod_resolve = info.mod_resolve
|
||||||
|
|
||||||
var used
|
var used = null
|
||||||
|
var context = null
|
||||||
|
var file_info = null
|
||||||
|
var inject = null
|
||||||
|
var env = null
|
||||||
|
var pkg = null
|
||||||
|
var use_fn = null
|
||||||
|
|
||||||
if (mod_resolve.scope < 900) {
|
if (mod_resolve.scope < 900) {
|
||||||
var context = null
|
context = null
|
||||||
if (c_resolve.scope < 900) {
|
if (c_resolve.scope < 900) {
|
||||||
context = call_c_module(c_resolve)
|
context = call_c_module(c_resolve)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get file info to determine inject list
|
// Get file info to determine inject list
|
||||||
var file_info = Shop.file_info(mod_resolve.path)
|
file_info = Shop.file_info(mod_resolve.path)
|
||||||
var inject = Shop.script_inject_for(file_info)
|
inject = Shop.script_inject_for(file_info)
|
||||||
var env = inject_env(inject)
|
env = inject_env(inject)
|
||||||
var pkg = file_info.package
|
pkg = file_info.package
|
||||||
var use_fn = make_use_fn(pkg)
|
use_fn = make_use_fn(pkg)
|
||||||
|
|
||||||
// Call with signature: setup_module(args, use, env)
|
// Call with signature: setup_module(args, use, env)
|
||||||
// args is null for module loading
|
// args is null for module loading
|
||||||
@@ -942,17 +994,18 @@ Shop.fetch = function(pkg) {
|
|||||||
// Check if we have the zip cached
|
// Check if we have the zip cached
|
||||||
var zip_blob = get_cached_zip(pkg, commit)
|
var zip_blob = get_cached_zip(pkg, commit)
|
||||||
|
|
||||||
|
var actual_hash = null
|
||||||
if (zip_blob) {
|
if (zip_blob) {
|
||||||
// If we have a hash on record, verify it
|
// If we have a hash on record, verify it
|
||||||
if (expected_hash) {
|
if (expected_hash) {
|
||||||
var actual_hash = text(crypto.blake2(zip_blob), 'h')
|
actual_hash = text(crypto.blake2(zip_blob), 'h')
|
||||||
if (actual_hash == expected_hash) {
|
if (actual_hash == expected_hash) {
|
||||||
return { status: 'cached' }
|
return { status: 'cached' }
|
||||||
}
|
}
|
||||||
log.console("Zip hash mismatch for " + pkg + ", re-fetching...")
|
log.console("Zip hash mismatch for " + pkg + ", re-fetching...")
|
||||||
} else {
|
} else {
|
||||||
// No hash stored yet - compute and store it
|
// No hash stored yet - compute and store it
|
||||||
var actual_hash = text(crypto.blake2(zip_blob), 'h')
|
actual_hash = text(crypto.blake2(zip_blob), 'h')
|
||||||
lock_entry.zip_hash = actual_hash
|
lock_entry.zip_hash = actual_hash
|
||||||
Shop.save_lock(lock)
|
Shop.save_lock(lock)
|
||||||
return { status: 'cached' }
|
return { status: 'cached' }
|
||||||
@@ -1004,10 +1057,12 @@ Shop.extract = function(pkg) {
|
|||||||
// Check if already extracted at correct commit
|
// Check if already extracted at correct commit
|
||||||
var lock = Shop.load_lock()
|
var lock = Shop.load_lock()
|
||||||
var lock_entry = lock[pkg]
|
var lock_entry = lock[pkg]
|
||||||
|
var extracted_commit_file = null
|
||||||
|
var extracted_commit = null
|
||||||
if (lock_entry && lock_entry.commit) {
|
if (lock_entry && lock_entry.commit) {
|
||||||
var extracted_commit_file = target_dir + '/.cell_commit'
|
extracted_commit_file = target_dir + '/.cell_commit'
|
||||||
if (fd.is_file(extracted_commit_file)) {
|
if (fd.is_file(extracted_commit_file)) {
|
||||||
var extracted_commit = trim(text(fd.slurp(extracted_commit_file)))
|
extracted_commit = trim(text(fd.slurp(extracted_commit_file)))
|
||||||
if (extracted_commit == lock_entry.commit) {
|
if (extracted_commit == lock_entry.commit) {
|
||||||
// Already extracted at this commit, skip
|
// Already extracted at this commit, skip
|
||||||
return true
|
return true
|
||||||
@@ -1059,6 +1114,7 @@ Shop.update = function(pkg) {
|
|||||||
|
|
||||||
log.console(`checking ${pkg}`)
|
log.console(`checking ${pkg}`)
|
||||||
|
|
||||||
|
var new_entry = null
|
||||||
if (info == 'local') {
|
if (info == 'local') {
|
||||||
// Check if local path exists
|
// Check if local path exists
|
||||||
if (!fd.is_dir(pkg)) {
|
if (!fd.is_dir(pkg)) {
|
||||||
@@ -1066,7 +1122,7 @@ Shop.update = function(pkg) {
|
|||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
// Local packages always get a lock entry
|
// Local packages always get a lock entry
|
||||||
var new_entry = {
|
new_entry = {
|
||||||
type: 'local',
|
type: 'local',
|
||||||
updated: time.number()
|
updated: time.number()
|
||||||
}
|
}
|
||||||
@@ -1089,7 +1145,7 @@ Shop.update = function(pkg) {
|
|||||||
if (local_commit == remote_commit)
|
if (local_commit == remote_commit)
|
||||||
return null
|
return null
|
||||||
|
|
||||||
var new_entry = {
|
new_entry = {
|
||||||
type: info,
|
type: info,
|
||||||
commit: remote_commit,
|
commit: remote_commit,
|
||||||
updated: time.number()
|
updated: time.number()
|
||||||
@@ -1114,21 +1170,28 @@ function install_zip(zip_blob, target_dir) {
|
|||||||
var count = zip.count()
|
var count = zip.count()
|
||||||
var created_dirs = {}
|
var created_dirs = {}
|
||||||
|
|
||||||
for (var i = 0; i < count; i++) {
|
var i = 0
|
||||||
|
var filename = null
|
||||||
|
var slash_pos = null
|
||||||
|
var rel_path = null
|
||||||
|
var full_path = null
|
||||||
|
var dir_path = null
|
||||||
|
var file_data = null
|
||||||
|
for (i = 0; i < count; i++) {
|
||||||
if (zip.is_directory(i)) continue
|
if (zip.is_directory(i)) continue
|
||||||
var filename = zip.get_filename(i)
|
filename = zip.get_filename(i)
|
||||||
var slash_pos = search(filename, '/')
|
slash_pos = search(filename, '/')
|
||||||
if (slash_pos == null) continue
|
if (slash_pos == null) continue
|
||||||
if (slash_pos + 1 >= length(filename)) continue
|
if (slash_pos + 1 >= length(filename)) continue
|
||||||
var rel_path = text(filename, slash_pos + 1)
|
rel_path = text(filename, slash_pos + 1)
|
||||||
var full_path = target_dir + '/' + rel_path
|
full_path = target_dir + '/' + rel_path
|
||||||
var dir_path = fd.dirname(full_path)
|
dir_path = fd.dirname(full_path)
|
||||||
|
|
||||||
if (!created_dirs[dir_path]) {
|
if (!created_dirs[dir_path]) {
|
||||||
ensure_dir(dir_path)
|
ensure_dir(dir_path)
|
||||||
created_dirs[dir_path] = true
|
created_dirs[dir_path] = true
|
||||||
}
|
}
|
||||||
var file_data = zip.slurp(filename)
|
file_data = zip.slurp(filename)
|
||||||
|
|
||||||
stone(file_data)
|
stone(file_data)
|
||||||
|
|
||||||
@@ -1151,14 +1214,16 @@ Shop.remove = function(pkg) {
|
|||||||
|
|
||||||
Shop.get = function(pkg) {
|
Shop.get = function(pkg) {
|
||||||
var lock = Shop.load_lock()
|
var lock = Shop.load_lock()
|
||||||
|
var info = null
|
||||||
|
var commit = null
|
||||||
|
|
||||||
if (!lock[pkg]) {
|
if (!lock[pkg]) {
|
||||||
var info = Shop.resolve_package_info(pkg)
|
info = Shop.resolve_package_info(pkg)
|
||||||
if (!info) {
|
if (!info) {
|
||||||
print("Invalid package: " + pkg); disrupt
|
print("Invalid package: " + pkg); disrupt
|
||||||
}
|
}
|
||||||
|
|
||||||
var commit = null
|
commit = null
|
||||||
if (info != 'local') {
|
if (info != 'local') {
|
||||||
commit = fetch_remote_hash(pkg)
|
commit = fetch_remote_hash(pkg)
|
||||||
if (!commit) {
|
if (!commit) {
|
||||||
@@ -1216,9 +1281,11 @@ function get_package_scripts(package)
|
|||||||
{
|
{
|
||||||
var files = pkg_tools.list_files(package)
|
var files = pkg_tools.list_files(package)
|
||||||
var scripts = []
|
var scripts = []
|
||||||
|
|
||||||
for (var i = 0; i < length(files); i++) {
|
var i = 0
|
||||||
var file = files[i]
|
var file = null
|
||||||
|
for (i = 0; i < length(files); i++) {
|
||||||
|
file = files[i]
|
||||||
if (ends_with(file, '.cm') || ends_with(file, '.ce')) {
|
if (ends_with(file, '.cm') || ends_with(file, '.ce')) {
|
||||||
push(scripts, file)
|
push(scripts, file)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,19 +4,21 @@ var pkg = use('package')
|
|||||||
|
|
||||||
// Check if current directory is a valid cell package
|
// Check if current directory is a valid cell package
|
||||||
function is_valid_package(dir) {
|
function is_valid_package(dir) {
|
||||||
if (!dir) dir = '.'
|
var _dir = dir == null ? '.' : dir
|
||||||
return fd.is_file(dir + '/cell.toml')
|
if (!_dir) _dir = '.'
|
||||||
|
return fd.is_file(_dir + '/cell.toml')
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get current package name from cell.toml or null
|
// Get current package name from cell.toml or null
|
||||||
function get_current_package_name() {
|
function get_current_package_name() {
|
||||||
if (!is_valid_package('.')) return null
|
if (!is_valid_package('.')) return null
|
||||||
try {
|
var _load = function() {
|
||||||
var config = pkg.load_config(null)
|
var config = pkg.load_config(null)
|
||||||
return config.package || 'local'
|
return config.package || 'local'
|
||||||
} catch (e) {
|
} disruption {
|
||||||
return 'local'
|
return 'local'
|
||||||
}
|
}
|
||||||
|
return _load()
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get the directory for a package
|
// Get the directory for a package
|
||||||
@@ -37,9 +39,10 @@ function ensure_dir(path) {
|
|||||||
|
|
||||||
var parts = array(path, '/')
|
var parts = array(path, '/')
|
||||||
var current = starts_with(path, '/') ? '/' : ''
|
var current = starts_with(path, '/') ? '/' : ''
|
||||||
for (var i = 0; i < length(parts); i++) {
|
var i = 0
|
||||||
|
for (i = 0; i < length(parts); i++) {
|
||||||
if (parts[i] == '') continue
|
if (parts[i] == '') continue
|
||||||
current += parts[i] + '/'
|
current = current + parts[i] + '/'
|
||||||
if (!fd.is_dir(current)) {
|
if (!fd.is_dir(current)) {
|
||||||
fd.mkdir(current)
|
fd.mkdir(current)
|
||||||
}
|
}
|
||||||
|
|||||||
6
link.cm
6
link.cm
@@ -34,7 +34,8 @@ function ensure_dir(path) {
|
|||||||
if (fd.stat(path).isDirectory) return
|
if (fd.stat(path).isDirectory) return
|
||||||
var parts = array(path, '/')
|
var parts = array(path, '/')
|
||||||
var current = starts_with(path, '/') ? '/' : ''
|
var current = starts_with(path, '/') ? '/' : ''
|
||||||
for (var i = 0; i < length(parts); i++) {
|
var i = 0
|
||||||
|
for (i = 0; i < length(parts); i++) {
|
||||||
if (parts[i] == '') continue
|
if (parts[i] == '') continue
|
||||||
current = current + parts[i] + '/'
|
current = current + parts[i] + '/'
|
||||||
if (!fd.stat(current).isDirectory) {
|
if (!fd.stat(current).isDirectory) {
|
||||||
@@ -119,8 +120,9 @@ Link.add = function(canonical, target, shop) {
|
|||||||
// Read the target's cell.toml to find its dependencies
|
// Read the target's cell.toml to find its dependencies
|
||||||
var target_path = starts_with(target, '/') ? target : get_package_abs_dir(target)
|
var target_path = starts_with(target, '/') ? target : get_package_abs_dir(target)
|
||||||
var toml_path = target_path + '/cell.toml'
|
var toml_path = target_path + '/cell.toml'
|
||||||
|
var _install_deps = null
|
||||||
if (fd.is_file(toml_path)) {
|
if (fd.is_file(toml_path)) {
|
||||||
var _install_deps = function() {
|
_install_deps = function() {
|
||||||
var content = text(fd.slurp(toml_path))
|
var content = text(fd.slurp(toml_path))
|
||||||
var cfg = toml.decode(content)
|
var cfg = toml.decode(content)
|
||||||
if (cfg && cfg.dependencies) {
|
if (cfg && cfg.dependencies) {
|
||||||
|
|||||||
106
package.cm
106
package.cm
@@ -101,11 +101,12 @@ package.alias_to_package = function(name, alias)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// alias is optional
|
// alias is optional
|
||||||
package.add_dependency = function(name, locator, alias = locator)
|
package.add_dependency = function(name, locator, alias)
|
||||||
{
|
{
|
||||||
|
var _alias = alias == null ? locator : alias
|
||||||
var config = package.load_config(name)
|
var config = package.load_config(name)
|
||||||
if (!config.dependencies) config.dependencies = {}
|
if (!config.dependencies) config.dependencies = {}
|
||||||
config.dependencies[alias] = locator
|
config.dependencies[_alias] = locator
|
||||||
package.save_config(name, config)
|
package.save_config(name, config)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -115,10 +116,11 @@ package.remove_dependency = function(name, locator)
|
|||||||
var config = package.load_config(name)
|
var config = package.load_config(name)
|
||||||
if (!config.dependencies) return
|
if (!config.dependencies) return
|
||||||
|
|
||||||
|
var alias = null
|
||||||
if (config.dependencies[locator])
|
if (config.dependencies[locator])
|
||||||
delete config.dependencies[locator]
|
delete config.dependencies[locator]
|
||||||
else {
|
else {
|
||||||
var alias = package.find_alias(name, locator)
|
alias = package.find_alias(name, locator)
|
||||||
if (alias)
|
if (alias)
|
||||||
delete config.dependencies[alias]
|
delete config.dependencies[alias]
|
||||||
}
|
}
|
||||||
@@ -133,8 +135,9 @@ package.find_package_dir = function(file)
|
|||||||
if (fd.is_file(dir))
|
if (fd.is_file(dir))
|
||||||
dir = fd.dirname(dir)
|
dir = fd.dirname(dir)
|
||||||
|
|
||||||
|
var toml_path = null
|
||||||
while (dir && length(dir) > 0) {
|
while (dir && length(dir) > 0) {
|
||||||
var toml_path = dir + '/cell.toml'
|
toml_path = dir + '/cell.toml'
|
||||||
if (fd.is_file(toml_path)) {
|
if (fd.is_file(toml_path)) {
|
||||||
return dir
|
return dir
|
||||||
}
|
}
|
||||||
@@ -163,9 +166,11 @@ package.split_alias = function(name, path)
|
|||||||
if (!config) return null
|
if (!config) return null
|
||||||
|
|
||||||
var deps = config.dependencies
|
var deps = config.dependencies
|
||||||
|
var dep_locator = null
|
||||||
|
var remaining_path = null
|
||||||
if (deps && deps[first_part]) {
|
if (deps && deps[first_part]) {
|
||||||
var dep_locator = deps[first_part]
|
dep_locator = deps[first_part]
|
||||||
var remaining_path = text(array(parts, 1), '/')
|
remaining_path = text(array(parts, 1), '/')
|
||||||
return { package: dep_locator, path: remaining_path }
|
return { package: dep_locator, path: remaining_path }
|
||||||
}
|
}
|
||||||
return null
|
return null
|
||||||
@@ -208,18 +213,23 @@ package.list_files = function(pkg) {
|
|||||||
var walk = function(current_dir, current_prefix) {
|
var walk = function(current_dir, current_prefix) {
|
||||||
var list = fd.readdir(current_dir)
|
var list = fd.readdir(current_dir)
|
||||||
if (!list) return
|
if (!list) return
|
||||||
|
|
||||||
for (var i = 0; i < length(list); i++) {
|
var i = 0
|
||||||
var item = list[i]
|
var item = null
|
||||||
|
var full_path = null
|
||||||
|
var rel_path = null
|
||||||
|
var st = null
|
||||||
|
for (i = 0; i < length(list); i++) {
|
||||||
|
item = list[i]
|
||||||
if (item == '.' || item == '..') continue
|
if (item == '.' || item == '..') continue
|
||||||
if (starts_with(item, '.')) continue
|
if (starts_with(item, '.')) continue
|
||||||
|
|
||||||
// Skip build directories in root
|
// Skip build directories in root
|
||||||
|
|
||||||
var full_path = current_dir + "/" + item
|
full_path = current_dir + "/" + item
|
||||||
var rel_path = current_prefix ? current_prefix + "/" + item : item
|
rel_path = current_prefix ? current_prefix + "/" + item : item
|
||||||
|
|
||||||
var st = fd.stat(full_path)
|
st = fd.stat(full_path)
|
||||||
if (st.isDirectory) {
|
if (st.isDirectory) {
|
||||||
walk(full_path, rel_path)
|
walk(full_path, rel_path)
|
||||||
} else {
|
} else {
|
||||||
@@ -237,7 +247,8 @@ package.list_files = function(pkg) {
|
|||||||
package.list_modules = function(name) {
|
package.list_modules = function(name) {
|
||||||
var files = package.list_files(name)
|
var files = package.list_files(name)
|
||||||
var modules = []
|
var modules = []
|
||||||
for (var i = 0; i < length(files); i++) {
|
var i = 0
|
||||||
|
for (i = 0; i < length(files); i++) {
|
||||||
if (ends_with(files[i], '.cm')) {
|
if (ends_with(files[i], '.cm')) {
|
||||||
push(modules, text(files[i], 0, -3))
|
push(modules, text(files[i], 0, -3))
|
||||||
}
|
}
|
||||||
@@ -248,7 +259,8 @@ package.list_modules = function(name) {
|
|||||||
package.list_programs = function(name) {
|
package.list_programs = function(name) {
|
||||||
var files = package.list_files(name)
|
var files = package.list_files(name)
|
||||||
var programs = []
|
var programs = []
|
||||||
for (var i = 0; i < length(files); i++) {
|
var i = 0
|
||||||
|
for (i = 0; i < length(files); i++) {
|
||||||
if (ends_with(files[i], '.ce')) {
|
if (ends_with(files[i], '.ce')) {
|
||||||
push(programs, text(files[i], 0, -3))
|
push(programs, text(files[i], 0, -3))
|
||||||
}
|
}
|
||||||
@@ -265,14 +277,16 @@ package.get_flags = function(name, flag_type, target) {
|
|||||||
var flags = []
|
var flags = []
|
||||||
|
|
||||||
// Base flags
|
// Base flags
|
||||||
|
var base = null
|
||||||
|
var target_flags = null
|
||||||
if (config.compilation && config.compilation[flag_type]) {
|
if (config.compilation && config.compilation[flag_type]) {
|
||||||
var base = config.compilation[flag_type]
|
base = config.compilation[flag_type]
|
||||||
flags = array(flags, filter(array(base, /\s+/), function(f) { return length(f) > 0 }))
|
flags = array(flags, filter(array(base, /\s+/), function(f) { return length(f) > 0 }))
|
||||||
}
|
}
|
||||||
|
|
||||||
// Target-specific flags
|
// Target-specific flags
|
||||||
if (target && config.compilation && config.compilation[target] && config.compilation[target][flag_type]) {
|
if (target && config.compilation && config.compilation[target] && config.compilation[target][flag_type]) {
|
||||||
var target_flags = config.compilation[target][flag_type]
|
target_flags = config.compilation[target][flag_type]
|
||||||
flags = array(flags, filter(array(target_flags, /\s+/), function(f) { return length(f) > 0 }))
|
flags = array(flags, filter(array(target_flags, /\s+/), function(f) { return length(f) > 0 }))
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -290,23 +304,36 @@ package.get_c_files = function(name, target, exclude_main) {
|
|||||||
// Group files by their base name (without target suffix)
|
// Group files by their base name (without target suffix)
|
||||||
var groups = {} // base_key -> { generic: file, variants: { target: file } }
|
var groups = {} // base_key -> { generic: file, variants: { target: file } }
|
||||||
|
|
||||||
for (var i = 0; i < length(files); i++) {
|
var i = 0
|
||||||
var file = files[i]
|
var file = null
|
||||||
|
var ext = null
|
||||||
|
var base = null
|
||||||
|
var name_part = null
|
||||||
|
var dir_part = null
|
||||||
|
var dir = null
|
||||||
|
var is_variant = null
|
||||||
|
var variant_target = null
|
||||||
|
var generic_name = null
|
||||||
|
var t = 0
|
||||||
|
var suffix = null
|
||||||
|
var group_key = null
|
||||||
|
for (i = 0; i < length(files); i++) {
|
||||||
|
file = files[i]
|
||||||
if (!ends_with(file, '.c') && !ends_with(file, '.cpp')) continue
|
if (!ends_with(file, '.c') && !ends_with(file, '.cpp')) continue
|
||||||
|
|
||||||
var ext = ends_with(file, '.cpp') ? '.cpp' : '.c'
|
ext = ends_with(file, '.cpp') ? '.cpp' : '.c'
|
||||||
var base = text(file, 0, -length(ext))
|
base = text(file, 0, -length(ext))
|
||||||
var name_part = fd.basename(base)
|
name_part = fd.basename(base)
|
||||||
var dir_part = fd.dirname(base)
|
dir_part = fd.dirname(base)
|
||||||
var dir = (dir_part && dir_part != '.') ? dir_part + '/' : ''
|
dir = (dir_part && dir_part != '.') ? dir_part + '/' : ''
|
||||||
|
|
||||||
// Check for target suffix
|
// Check for target suffix
|
||||||
var is_variant = false
|
is_variant = false
|
||||||
var variant_target = null
|
variant_target = null
|
||||||
var generic_name = name_part
|
generic_name = name_part
|
||||||
|
|
||||||
for (var t = 0; t < length(known_targets); t++) {
|
for (t = 0; t < length(known_targets); t++) {
|
||||||
var suffix = '_' + known_targets[t]
|
suffix = '_' + known_targets[t]
|
||||||
if (ends_with(name_part, suffix)) {
|
if (ends_with(name_part, suffix)) {
|
||||||
is_variant = true
|
is_variant = true
|
||||||
variant_target = known_targets[t]
|
variant_target = known_targets[t]
|
||||||
@@ -315,7 +342,7 @@ package.get_c_files = function(name, target, exclude_main) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var group_key = dir + generic_name + ext
|
group_key = dir + generic_name + ext
|
||||||
if (!groups[group_key]) {
|
if (!groups[group_key]) {
|
||||||
groups[group_key] = { generic: null, variants: {} }
|
groups[group_key] = { generic: null, variants: {} }
|
||||||
}
|
}
|
||||||
@@ -332,18 +359,19 @@ package.get_c_files = function(name, target, exclude_main) {
|
|||||||
arrfor(array(groups), function(key) {
|
arrfor(array(groups), function(key) {
|
||||||
var group = groups[key]
|
var group = groups[key]
|
||||||
var selected = null
|
var selected = null
|
||||||
|
var basename = null
|
||||||
|
|
||||||
// Prefer target-specific variant if available
|
// Prefer target-specific variant if available
|
||||||
if (target && group.variants[target]) {
|
if (target && group.variants[target]) {
|
||||||
selected = group.variants[target]
|
selected = group.variants[target]
|
||||||
} else if (group.generic) {
|
} else if (group.generic) {
|
||||||
selected = group.generic
|
selected = group.generic
|
||||||
}
|
}
|
||||||
|
|
||||||
if (selected) {
|
if (selected) {
|
||||||
// Skip main.c if requested
|
// Skip main.c if requested
|
||||||
if (exclude_main) {
|
if (exclude_main) {
|
||||||
var basename = fd.basename(selected)
|
basename = fd.basename(selected)
|
||||||
if (basename == 'main.c' || starts_with(basename, 'main_')) return
|
if (basename == 'main.c' || starts_with(basename, 'main_')) return
|
||||||
}
|
}
|
||||||
push(result, selected)
|
push(result, selected)
|
||||||
|
|||||||
301
test.ce
301
test.ce
@@ -8,7 +8,7 @@ var dbg = use('js')
|
|||||||
|
|
||||||
// run gc with dbg.gc()
|
// run gc with dbg.gc()
|
||||||
|
|
||||||
if (!args) args = []
|
var _args = args == null ? [] : args
|
||||||
|
|
||||||
var target_pkg = null // null = current package
|
var target_pkg = null // null = current package
|
||||||
var target_test = null // null = all tests, otherwise specific test file
|
var target_test = null // null = all tests, otherwise specific test file
|
||||||
@@ -22,19 +22,20 @@ var actor_test_results = []
|
|||||||
|
|
||||||
// Check if current directory is a valid cell package
|
// Check if current directory is a valid cell package
|
||||||
function is_valid_package(dir) {
|
function is_valid_package(dir) {
|
||||||
if (!dir) dir = '.'
|
var _dir = dir == null ? '.' : dir
|
||||||
return fd.is_file(dir + '/cell.toml')
|
return fd.is_file(_dir + '/cell.toml')
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get current package name from cell.toml or null
|
// Get current package name from cell.toml or null
|
||||||
function get_current_package_name() {
|
function get_current_package_name() {
|
||||||
if (!is_valid_package('.')) return null
|
if (!is_valid_package('.')) return null
|
||||||
try {
|
var _load = function() {
|
||||||
var config = pkg.load_config(null)
|
var config = pkg.load_config(null)
|
||||||
return config.package || 'local'
|
return config.package || 'local'
|
||||||
} catch (e) {
|
} disruption {
|
||||||
return 'local'
|
return 'local'
|
||||||
}
|
}
|
||||||
|
return _load()
|
||||||
}
|
}
|
||||||
|
|
||||||
// Parse arguments
|
// Parse arguments
|
||||||
@@ -48,16 +49,21 @@ function get_current_package_name() {
|
|||||||
|
|
||||||
function parse_args() {
|
function parse_args() {
|
||||||
var cleaned_args = []
|
var cleaned_args = []
|
||||||
for (var i = 0; i < length(args); i++) {
|
var i = 0
|
||||||
if (args[i] == '-g') {
|
var name = null
|
||||||
|
var lock = null
|
||||||
|
var resolved = null
|
||||||
|
var test_path = null
|
||||||
|
for (i = 0; i < length(_args); i++) {
|
||||||
|
if (_args[i] == '-g') {
|
||||||
gc_after_each_test = true
|
gc_after_each_test = true
|
||||||
} else {
|
} else {
|
||||||
push(cleaned_args, args[i])
|
push(cleaned_args, _args[i])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
args = cleaned_args
|
_args = cleaned_args
|
||||||
|
|
||||||
if (length(args) == 0) {
|
if (length(_args) == 0) {
|
||||||
// cell test - run all tests for current package
|
// cell test - run all tests for current package
|
||||||
if (!is_valid_package('.')) {
|
if (!is_valid_package('.')) {
|
||||||
log.console('No cell.toml found in current directory')
|
log.console('No cell.toml found in current directory')
|
||||||
@@ -67,7 +73,7 @@ function parse_args() {
|
|||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
if (args[0] == 'all') {
|
if (_args[0] == 'all') {
|
||||||
// cell test all - run all tests for current package
|
// cell test all - run all tests for current package
|
||||||
if (!is_valid_package('.')) {
|
if (!is_valid_package('.')) {
|
||||||
log.console('No cell.toml found in current directory')
|
log.console('No cell.toml found in current directory')
|
||||||
@@ -77,14 +83,14 @@ function parse_args() {
|
|||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
if (args[0] == 'package') {
|
if (_args[0] == 'package') {
|
||||||
if (length(args) < 2) {
|
if (length(_args) < 2) {
|
||||||
log.console('Usage: cell test package <name> [test]')
|
log.console('Usage: cell test package <name> [test]')
|
||||||
log.console(' cell test package all')
|
log.console(' cell test package all')
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
if (args[1] == 'all') {
|
if (_args[1] == 'all') {
|
||||||
// cell test package all - run tests from all packages
|
// cell test package all - run tests from all packages
|
||||||
all_pkgs = true
|
all_pkgs = true
|
||||||
log.console('Testing all packages...')
|
log.console('Testing all packages...')
|
||||||
@@ -92,18 +98,19 @@ function parse_args() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// cell test package <name> [test]
|
// cell test package <name> [test]
|
||||||
var name = args[1]
|
name = _args[1]
|
||||||
|
|
||||||
// Check if package exists in lock or is a local path
|
// Check if package exists in lock or is a local path
|
||||||
var lock = shop.load_lock()
|
lock = shop.load_lock()
|
||||||
if (lock[name]) {
|
if (lock[name]) {
|
||||||
target_pkg = name
|
target_pkg = name
|
||||||
} else if (starts_with(name, '/') && is_valid_package(name)) {
|
} else if (starts_with(name, '/') && is_valid_package(name)) {
|
||||||
target_pkg = name
|
target_pkg = name
|
||||||
} else {
|
} else {
|
||||||
// Try to resolve as dependency alias from current package
|
// Try to resolve as dependency alias from current package
|
||||||
|
resolved = null
|
||||||
if (is_valid_package('.')) {
|
if (is_valid_package('.')) {
|
||||||
var resolved = pkg.alias_to_package(null, name)
|
resolved = pkg.alias_to_package(null, name)
|
||||||
if (resolved) {
|
if (resolved) {
|
||||||
target_pkg = resolved
|
target_pkg = resolved
|
||||||
} else {
|
} else {
|
||||||
@@ -116,9 +123,9 @@ function parse_args() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (length(args) >= 3) {
|
if (length(_args) >= 3) {
|
||||||
// cell test package <name> <test>
|
// cell test package <name> <test>
|
||||||
target_test = args[2]
|
target_test = _args[2]
|
||||||
}
|
}
|
||||||
|
|
||||||
log.console(`Testing package: ${target_pkg}`)
|
log.console(`Testing package: ${target_pkg}`)
|
||||||
@@ -126,7 +133,7 @@ function parse_args() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// cell test tests/suite or cell test <path> - specific test file
|
// cell test tests/suite or cell test <path> - specific test file
|
||||||
var test_path = args[0]
|
test_path = _args[0]
|
||||||
|
|
||||||
// Normalize path - add tests/ prefix if not present and doesn't start with /
|
// Normalize path - add tests/ prefix if not present and doesn't start with /
|
||||||
if (!starts_with(test_path, 'tests/') && !starts_with(test_path, '/')) {
|
if (!starts_with(test_path, 'tests/') && !starts_with(test_path, '/')) {
|
||||||
@@ -160,9 +167,10 @@ function ensure_dir(path) {
|
|||||||
|
|
||||||
var parts = array(path, '/')
|
var parts = array(path, '/')
|
||||||
var current = starts_with(path, '/') ? '/' : ''
|
var current = starts_with(path, '/') ? '/' : ''
|
||||||
for (var i = 0; i < length(parts); i++) {
|
var i = 0
|
||||||
|
for (i = 0; i < length(parts); i++) {
|
||||||
if (parts[i] == '') continue
|
if (parts[i] == '') continue
|
||||||
current += parts[i] + '/'
|
current = current + parts[i] + '/'
|
||||||
if (!fd.is_dir(current))
|
if (!fd.is_dir(current))
|
||||||
fd.mkdir(current)
|
fd.mkdir(current)
|
||||||
}
|
}
|
||||||
@@ -189,23 +197,29 @@ function collect_actor_tests(package_name, specific_test) {
|
|||||||
|
|
||||||
var files = pkg.list_files(package_name)
|
var files = pkg.list_files(package_name)
|
||||||
var actor_tests = []
|
var actor_tests = []
|
||||||
for (var i = 0; i < length(files); i++) {
|
var i = 0
|
||||||
var f = files[i]
|
var f = null
|
||||||
|
var test_name = null
|
||||||
|
var match_name = null
|
||||||
|
var test_base = null
|
||||||
|
var match_base = null
|
||||||
|
for (i = 0; i < length(files); i++) {
|
||||||
|
f = files[i]
|
||||||
// Check if file is in tests/ folder and is a .ce actor
|
// Check if file is in tests/ folder and is a .ce actor
|
||||||
if (starts_with(f, "tests/") && ends_with(f, ".ce")) {
|
if (starts_with(f, "tests/") && ends_with(f, ".ce")) {
|
||||||
// If specific test requested, filter
|
// If specific test requested, filter
|
||||||
if (specific_test) {
|
if (specific_test) {
|
||||||
var test_name = text(f, 0, -3) // remove .ce
|
test_name = text(f, 0, -3) // remove .ce
|
||||||
var match_name = specific_test
|
match_name = specific_test
|
||||||
if (!starts_with(match_name, 'tests/')) match_name = 'tests/' + match_name
|
if (!starts_with(match_name, 'tests/')) match_name = 'tests/' + match_name
|
||||||
if (!ends_with(match_name, '.ce')) match_name = match_name
|
if (!ends_with(match_name, '.ce')) match_name = match_name
|
||||||
// Match without extension
|
// Match without extension
|
||||||
var test_base = test_name
|
test_base = test_name
|
||||||
var match_base = ends_with(match_name, '.ce') ? text(match_name, 0, -3) : match_name
|
match_base = ends_with(match_name, '.ce') ? text(match_name, 0, -3) : match_name
|
||||||
if (test_base != match_base) continue
|
if (test_base != match_base) continue
|
||||||
}
|
}
|
||||||
|
|
||||||
push(actor_tests,{
|
push(actor_tests, {
|
||||||
package: package_name || "local",
|
package: package_name || "local",
|
||||||
file: f,
|
file: f,
|
||||||
path: prefix + '/' + f
|
path: prefix + '/' + f
|
||||||
@@ -229,19 +243,19 @@ function spawn_actor_test(test_info) {
|
|||||||
actor: null
|
actor: null
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
var _spawn = function() {
|
||||||
// Spawn the actor test - it should send back results
|
|
||||||
var actor_path = text(test_info.path, 0, -3) // remove .ce
|
var actor_path = text(test_info.path, 0, -3) // remove .ce
|
||||||
entry.actor = $start(actor_path)
|
entry.actor = $start(actor_path)
|
||||||
push(pending_actor_tests, entry)
|
push(pending_actor_tests, entry)
|
||||||
} catch (e) {
|
} disruption {
|
||||||
entry.status = "failed"
|
entry.status = "failed"
|
||||||
entry.error = { message: `Failed to spawn actor: ${e}` }
|
entry.error = { message: `Failed to spawn actor` }
|
||||||
entry.duration_ns = 0
|
entry.duration_ns = 0
|
||||||
push(actor_test_results, entry)
|
push(actor_test_results, entry)
|
||||||
log.console(` FAIL ${test_name}: `)
|
log.console(` FAIL ${test_name}: `)
|
||||||
log.error(e)
|
log.error()
|
||||||
}
|
}
|
||||||
|
_spawn()
|
||||||
}
|
}
|
||||||
|
|
||||||
function run_tests(package_name, specific_test) {
|
function run_tests(package_name, specific_test) {
|
||||||
@@ -260,17 +274,24 @@ function run_tests(package_name, specific_test) {
|
|||||||
|
|
||||||
var files = pkg.list_files(package_name)
|
var files = pkg.list_files(package_name)
|
||||||
var test_files = []
|
var test_files = []
|
||||||
for (var i = 0; i < length(files); i++) {
|
var i = 0
|
||||||
var f = files[i]
|
var f = null
|
||||||
|
var test_name = null
|
||||||
|
var match_name = null
|
||||||
|
var match_base = null
|
||||||
|
var mod_path = null
|
||||||
|
var file_result = null
|
||||||
|
for (i = 0; i < length(files); i++) {
|
||||||
|
f = files[i]
|
||||||
// Check if file is in tests/ folder and is a .cm module (not .ce - those are actor tests)
|
// Check if file is in tests/ folder and is a .cm module (not .ce - those are actor tests)
|
||||||
if (starts_with(f, "tests/") && ends_with(f, ".cm")) {
|
if (starts_with(f, "tests/") && ends_with(f, ".cm")) {
|
||||||
// If specific test requested, filter
|
// If specific test requested, filter
|
||||||
if (specific_test) {
|
if (specific_test) {
|
||||||
var test_name = text(f, 0, -3) // remove .cm
|
test_name = text(f, 0, -3) // remove .cm
|
||||||
var match_name = specific_test
|
match_name = specific_test
|
||||||
if (!starts_with(match_name, 'tests/')) match_name = 'tests/' + match_name
|
if (!starts_with(match_name, 'tests/')) match_name = 'tests/' + match_name
|
||||||
// Match without extension
|
// Match without extension
|
||||||
var match_base = ends_with(match_name, '.cm') ? text(match_name, 0, -3) : match_name
|
match_base = ends_with(match_name, '.cm') ? text(match_name, 0, -3) : match_name
|
||||||
if (test_name != match_base) continue
|
if (test_name != match_base) continue
|
||||||
}
|
}
|
||||||
push(test_files, f)
|
push(test_files, f)
|
||||||
@@ -282,24 +303,31 @@ function run_tests(package_name, specific_test) {
|
|||||||
else log.console(`Running tests for local package`)
|
else log.console(`Running tests for local package`)
|
||||||
}
|
}
|
||||||
|
|
||||||
for (var i = 0; i < length(test_files); i++) {
|
var _load_file = null
|
||||||
var f = test_files[i]
|
for (i = 0; i < length(test_files); i++) {
|
||||||
var mod_path = text(f, 0, -3) // remove .cm
|
f = test_files[i]
|
||||||
|
mod_path = text(f, 0, -3) // remove .cm
|
||||||
|
|
||||||
var file_result = {
|
file_result = {
|
||||||
name: f,
|
name: f,
|
||||||
tests: [],
|
tests: [],
|
||||||
passed: 0,
|
passed: 0,
|
||||||
failed: 0
|
failed: 0
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
_load_file = function() {
|
||||||
var test_mod
|
var test_mod = null
|
||||||
// For local packages (null), use the current directory as package context
|
|
||||||
var use_pkg = package_name ? package_name : fd.realpath('.')
|
var use_pkg = package_name ? package_name : fd.realpath('.')
|
||||||
test_mod = shop.use(mod_path, use_pkg)
|
test_mod = shop.use(mod_path, use_pkg)
|
||||||
|
|
||||||
var tests = []
|
var tests = []
|
||||||
|
var j = 0
|
||||||
|
var t = null
|
||||||
|
var test_entry = null
|
||||||
|
var start_time = null
|
||||||
|
var _test_error = null
|
||||||
|
var end_time = null
|
||||||
|
var _run_one = null
|
||||||
if (is_function(test_mod)) {
|
if (is_function(test_mod)) {
|
||||||
push(tests, {name: 'main', fn: test_mod})
|
push(tests, {name: 'main', fn: test_mod})
|
||||||
} else if (is_object(test_mod)) {
|
} else if (is_object(test_mod)) {
|
||||||
@@ -312,50 +340,55 @@ function run_tests(package_name, specific_test) {
|
|||||||
|
|
||||||
if (length(tests) > 0) {
|
if (length(tests) > 0) {
|
||||||
log.console(` ${f}`)
|
log.console(` ${f}`)
|
||||||
for (var j = 0; j < length(tests); j++) {
|
for (j = 0; j < length(tests); j++) {
|
||||||
var t = tests[j]
|
t = tests[j]
|
||||||
var test_entry = {
|
test_entry = {
|
||||||
package: pkg_result.package,
|
package: pkg_result.package,
|
||||||
test: t.name,
|
test: t.name,
|
||||||
status: "pending",
|
status: "pending",
|
||||||
duration_ns: 0
|
duration_ns: 0
|
||||||
}
|
}
|
||||||
|
|
||||||
var start_time = time.number()
|
start_time = time.number()
|
||||||
try {
|
_test_error = null
|
||||||
|
_run_one = function() {
|
||||||
var ret = t.fn()
|
var ret = t.fn()
|
||||||
|
|
||||||
if (is_text(ret)) {
|
if (is_text(ret)) {
|
||||||
throw Error(ret)
|
_test_error = Error(ret)
|
||||||
|
disrupt
|
||||||
} else if (ret && (is_text(ret.message) || is_proto(ret, Error))) {
|
} else if (ret && (is_text(ret.message) || is_proto(ret, Error))) {
|
||||||
throw ret
|
_test_error = ret
|
||||||
|
disrupt
|
||||||
}
|
}
|
||||||
|
|
||||||
test_entry.status = "passed"
|
test_entry.status = "passed"
|
||||||
log.console(` PASS ${t.name}`)
|
log.console(` PASS ${t.name}`)
|
||||||
pkg_result.passed++
|
pkg_result.passed++
|
||||||
file_result.passed++
|
file_result.passed++
|
||||||
} catch (e) {
|
} disruption {
|
||||||
|
var e = _test_error
|
||||||
test_entry.status = "failed"
|
test_entry.status = "failed"
|
||||||
test_entry.error = {
|
test_entry.error = {
|
||||||
message: e,
|
message: e,
|
||||||
stack: e.stack || ""
|
stack: (e && e.stack) ? e.stack : ""
|
||||||
}
|
}
|
||||||
if (e.name) test_entry.error.name = e.name
|
if (e && e.name) test_entry.error.name = e.name
|
||||||
|
|
||||||
if (is_object(e) && e.message) {
|
if (is_object(e) && e.message) {
|
||||||
test_entry.error.message = e.message
|
test_entry.error.message = e.message
|
||||||
}
|
}
|
||||||
|
|
||||||
log.console(` FAIL ${t.name} ${test_entry.error.message}`)
|
log.console(` FAIL ${t.name} ${test_entry.error.message}`)
|
||||||
if (test_entry.error.stack) {
|
if (test_entry.error.stack) {
|
||||||
log.console(` ${text(array(test_entry.error.stack, '\n'), '\n ')}`)
|
log.console(` ${text(array(test_entry.error.stack, '\n'), '\n ')}`)
|
||||||
}
|
}
|
||||||
|
|
||||||
pkg_result.failed++
|
pkg_result.failed++
|
||||||
file_result.failed++
|
file_result.failed++
|
||||||
}
|
}
|
||||||
var end_time = time.number()
|
_run_one()
|
||||||
|
end_time = time.number()
|
||||||
test_entry.duration_ns = round((end_time - start_time) * 1000000000)
|
test_entry.duration_ns = round((end_time - start_time) * 1000000000)
|
||||||
|
|
||||||
push(file_result.tests, test_entry)
|
push(file_result.tests, test_entry)
|
||||||
@@ -366,15 +399,15 @@ function run_tests(package_name, specific_test) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
} catch (e) {
|
} disruption {
|
||||||
log.console(` Error loading ${f}: ${e}`)
|
var test_entry = {
|
||||||
var test_entry = {
|
|
||||||
package: pkg_result.package,
|
package: pkg_result.package,
|
||||||
test: "load_module",
|
test: "load_module",
|
||||||
status: "failed",
|
status: "failed",
|
||||||
duration_ns: 0,
|
duration_ns: 0,
|
||||||
error: { message: `Error loading module: ${e}` }
|
error: { message: `Error loading module` }
|
||||||
}
|
}
|
||||||
|
log.console(` Error loading ${f}`)
|
||||||
push(file_result.tests, test_entry)
|
push(file_result.tests, test_entry)
|
||||||
pkg_result.failed++
|
pkg_result.failed++
|
||||||
file_result.failed++
|
file_result.failed++
|
||||||
@@ -383,6 +416,7 @@ function run_tests(package_name, specific_test) {
|
|||||||
dbg.gc()
|
dbg.gc()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
_load_file()
|
||||||
push(pkg_result.files, file_result)
|
push(pkg_result.files, file_result)
|
||||||
}
|
}
|
||||||
return pkg_result
|
return pkg_result
|
||||||
@@ -390,6 +424,8 @@ function run_tests(package_name, specific_test) {
|
|||||||
|
|
||||||
var all_results = []
|
var all_results = []
|
||||||
var all_actor_tests = []
|
var all_actor_tests = []
|
||||||
|
var packages = null
|
||||||
|
var i = 0
|
||||||
|
|
||||||
if (all_pkgs) {
|
if (all_pkgs) {
|
||||||
// Run local first if we're in a valid package
|
// Run local first if we're in a valid package
|
||||||
@@ -399,8 +435,8 @@ if (all_pkgs) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Then all packages in lock
|
// Then all packages in lock
|
||||||
var packages = shop.list_packages()
|
packages = shop.list_packages()
|
||||||
for (var i = 0; i < length(packages); i++) {
|
for (i = 0; i < length(packages); i++) {
|
||||||
push(all_results, run_tests(packages[i], null))
|
push(all_results, run_tests(packages[i], null))
|
||||||
all_actor_tests = array(all_actor_tests, collect_actor_tests(packages[i], null))
|
all_actor_tests = array(all_actor_tests, collect_actor_tests(packages[i], null))
|
||||||
}
|
}
|
||||||
@@ -412,7 +448,7 @@ if (all_pkgs) {
|
|||||||
// Spawn actor tests if any
|
// Spawn actor tests if any
|
||||||
if (length(all_actor_tests) > 0) {
|
if (length(all_actor_tests) > 0) {
|
||||||
log.console(`Running ${length(all_actor_tests)} actor test(s)...`)
|
log.console(`Running ${length(all_actor_tests)} actor test(s)...`)
|
||||||
for (var i = 0; i < length(all_actor_tests); i++) {
|
for (i = 0; i < length(all_actor_tests); i++) {
|
||||||
spawn_actor_test(all_actor_tests[i])
|
spawn_actor_test(all_actor_tests[i])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -421,7 +457,10 @@ if (length(all_actor_tests) > 0) {
|
|||||||
function handle_actor_message(msg) {
|
function handle_actor_message(msg) {
|
||||||
var sender = msg.$sender
|
var sender = msg.$sender
|
||||||
var found_idx = -1
|
var found_idx = -1
|
||||||
for (var i = 0; i < length(pending_actor_tests); i++) {
|
var i = 0
|
||||||
|
var res = null
|
||||||
|
var entry = null
|
||||||
|
for (i = 0; i < length(pending_actor_tests); i++) {
|
||||||
if (pending_actor_tests[i].actor == sender) {
|
if (pending_actor_tests[i].actor == sender) {
|
||||||
found_idx = i
|
found_idx = i
|
||||||
break
|
break
|
||||||
@@ -445,9 +484,9 @@ function handle_actor_message(msg) {
|
|||||||
results = [msg]
|
results = [msg]
|
||||||
}
|
}
|
||||||
|
|
||||||
for (var i = 0; i < length(results); i++) {
|
for (i = 0; i < length(results); i++) {
|
||||||
var res = results[i] || {}
|
res = results[i] || {}
|
||||||
var entry = {
|
entry = {
|
||||||
package: base_entry.package,
|
package: base_entry.package,
|
||||||
file: base_entry.file,
|
file: base_entry.file,
|
||||||
test: res.test || base_entry.test + (length(results) > 1 ? `#${i+1}` : ""),
|
test: res.test || base_entry.test + (length(results) > 1 ? `#${i+1}` : ""),
|
||||||
@@ -481,18 +520,22 @@ function handle_actor_message(msg) {
|
|||||||
function check_timeouts() {
|
function check_timeouts() {
|
||||||
var now = time.number()
|
var now = time.number()
|
||||||
var timed_out = []
|
var timed_out = []
|
||||||
|
var i = 0
|
||||||
|
var entry = null
|
||||||
|
var elapsed_ms = null
|
||||||
|
var idx = null
|
||||||
|
|
||||||
for (var i = length(pending_actor_tests) - 1; i >= 0; i--) {
|
for (i = length(pending_actor_tests) - 1; i >= 0; i--) {
|
||||||
var entry = pending_actor_tests[i]
|
entry = pending_actor_tests[i]
|
||||||
var elapsed_ms = (now - entry.start_time) * 1000
|
elapsed_ms = (now - entry.start_time) * 1000
|
||||||
if (elapsed_ms > ACTOR_TEST_TIMEOUT) {
|
if (elapsed_ms > ACTOR_TEST_TIMEOUT) {
|
||||||
push(timed_out, i)
|
push(timed_out, i)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (var i = 0; i < length(timed_out); i++) {
|
for (i = 0; i < length(timed_out); i++) {
|
||||||
var idx = timed_out[i]
|
idx = timed_out[i]
|
||||||
var entry = pending_actor_tests[idx]
|
entry = pending_actor_tests[idx]
|
||||||
pending_actor_tests = array(array(pending_actor_tests, 0, idx), array(pending_actor_tests, idx + 1))
|
pending_actor_tests = array(array(pending_actor_tests, 0, idx), array(pending_actor_tests, idx + 1))
|
||||||
|
|
||||||
entry.status = "failed"
|
entry.status = "failed"
|
||||||
@@ -519,11 +562,17 @@ function check_completion() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function finalize_results() {
|
function finalize_results() {
|
||||||
|
var i = 0
|
||||||
|
var j = 0
|
||||||
|
var r = null
|
||||||
|
var pkg_result = null
|
||||||
|
var file_result = null
|
||||||
|
|
||||||
// Add actor test results to all_results
|
// Add actor test results to all_results
|
||||||
for (var i = 0; i < length(actor_test_results); i++) {
|
for (i = 0; i < length(actor_test_results); i++) {
|
||||||
var r = actor_test_results[i]
|
r = actor_test_results[i]
|
||||||
var pkg_result = null
|
pkg_result = null
|
||||||
for (var j = 0; j < length(all_results); j++) {
|
for (j = 0; j < length(all_results); j++) {
|
||||||
if (all_results[j].package == r.package) {
|
if (all_results[j].package == r.package) {
|
||||||
pkg_result = all_results[j]
|
pkg_result = all_results[j]
|
||||||
break
|
break
|
||||||
@@ -534,8 +583,8 @@ function finalize_results() {
|
|||||||
push(all_results, pkg_result)
|
push(all_results, pkg_result)
|
||||||
}
|
}
|
||||||
|
|
||||||
var file_result = null
|
file_result = null
|
||||||
for (var j = 0; j < length(pkg_result.files); j++) {
|
for (j = 0; j < length(pkg_result.files); j++) {
|
||||||
if (pkg_result.files[j].name == r.file) {
|
if (pkg_result.files[j].name == r.file) {
|
||||||
file_result = pkg_result.files[j]
|
file_result = pkg_result.files[j]
|
||||||
break
|
break
|
||||||
@@ -559,7 +608,7 @@ function finalize_results() {
|
|||||||
|
|
||||||
// Calculate totals
|
// Calculate totals
|
||||||
var totals = { total: 0, passed: 0, failed: 0 }
|
var totals = { total: 0, passed: 0, failed: 0 }
|
||||||
for (var i = 0; i < length(all_results); i++) {
|
for (i = 0; i < length(all_results); i++) {
|
||||||
totals.total += all_results[i].total
|
totals.total += all_results[i].total
|
||||||
totals.passed += all_results[i].passed
|
totals.passed += all_results[i].passed
|
||||||
totals.failed += all_results[i].failed
|
totals.failed += all_results[i].failed
|
||||||
@@ -573,10 +622,10 @@ function finalize_results() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// If no actor tests, finalize immediately
|
// If no actor tests, finalize immediately
|
||||||
var totals
|
var totals = null
|
||||||
if (length(all_actor_tests) == 0) {
|
if (length(all_actor_tests) == 0) {
|
||||||
totals = { total: 0, passed: 0, failed: 0 }
|
totals = { total: 0, passed: 0, failed: 0 }
|
||||||
for (var i = 0; i < length(all_results); i++) {
|
for (i = 0; i < length(all_results); i++) {
|
||||||
totals.total += all_results[i].total
|
totals.total += all_results[i].total
|
||||||
totals.passed += all_results[i].passed
|
totals.passed += all_results[i].passed
|
||||||
totals.failed += all_results[i].failed
|
totals.failed += all_results[i].failed
|
||||||
@@ -593,6 +642,16 @@ function generate_reports(totals) {
|
|||||||
var timestamp = text(floor(time.number()))
|
var timestamp = text(floor(time.number()))
|
||||||
var report_dir = shop.get_reports_dir() + '/test_' + timestamp
|
var report_dir = shop.get_reports_dir() + '/test_' + timestamp
|
||||||
ensure_dir(report_dir)
|
ensure_dir(report_dir)
|
||||||
|
var i = 0
|
||||||
|
var j = 0
|
||||||
|
var k = 0
|
||||||
|
var pkg_res = null
|
||||||
|
var f = null
|
||||||
|
var status = null
|
||||||
|
var t = null
|
||||||
|
var dur = null
|
||||||
|
var pkg_tests = null
|
||||||
|
var json_path = null
|
||||||
|
|
||||||
var txt_report = `TEST REPORT
|
var txt_report = `TEST REPORT
|
||||||
Date: ${time.text(time.number())}
|
Date: ${time.text(time.number())}
|
||||||
@@ -600,53 +659,53 @@ Total: ${totals.total}, Passed: ${totals.passed}, Failed: ${totals.failed}
|
|||||||
|
|
||||||
=== SUMMARY ===
|
=== SUMMARY ===
|
||||||
`
|
`
|
||||||
for (var i = 0; i < length(all_results); i++) {
|
for (i = 0; i < length(all_results); i++) {
|
||||||
var pkg_res = all_results[i]
|
pkg_res = all_results[i]
|
||||||
if (pkg_res.total == 0) continue
|
if (pkg_res.total == 0) continue
|
||||||
txt_report += `Package: ${pkg_res.package}\n`
|
txt_report = txt_report + `Package: ${pkg_res.package}\n`
|
||||||
for (var j = 0; j < length(pkg_res.files); j++) {
|
for (j = 0; j < length(pkg_res.files); j++) {
|
||||||
var f = pkg_res.files[j]
|
f = pkg_res.files[j]
|
||||||
var status = f.failed == 0 ? "PASS" : "FAIL"
|
status = f.failed == 0 ? "PASS" : "FAIL"
|
||||||
txt_report += ` [${status}] ${f.name} (${f.passed}/${length(f.tests)})\n`
|
txt_report = txt_report + ` [${status}] ${f.name} (${f.passed}/${length(f.tests)})\n`
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
txt_report += `\n=== FAILURES ===\n`
|
txt_report = txt_report + `\n=== FAILURES ===\n`
|
||||||
var has_failures = false
|
var has_failures = false
|
||||||
for (var i = 0; i < length(all_results); i++) {
|
for (i = 0; i < length(all_results); i++) {
|
||||||
var pkg_res = all_results[i]
|
pkg_res = all_results[i]
|
||||||
for (var j = 0; j < length(pkg_res.files); j++) {
|
for (j = 0; j < length(pkg_res.files); j++) {
|
||||||
var f = pkg_res.files[j]
|
f = pkg_res.files[j]
|
||||||
for (var k = 0; k < length(f.tests); k++) {
|
for (k = 0; k < length(f.tests); k++) {
|
||||||
var t = f.tests[k]
|
t = f.tests[k]
|
||||||
if (t.status == "failed") {
|
if (t.status == "failed") {
|
||||||
has_failures = true
|
has_failures = true
|
||||||
txt_report += `FAIL: ${pkg_res.package} :: ${f.name} :: ${t.test}\n`
|
txt_report = txt_report + `FAIL: ${pkg_res.package} :: ${f.name} :: ${t.test}\n`
|
||||||
if (t.error) {
|
if (t.error) {
|
||||||
txt_report += ` Message: ${t.error.message}\n`
|
txt_report = txt_report + ` Message: ${t.error.message}\n`
|
||||||
if (t.error.stack) {
|
if (t.error.stack) {
|
||||||
txt_report += ` Stack:\n${text(array(array(t.error.stack, '\n'), l => ` ${l}`), '\n')}\n`
|
txt_report = txt_report + ` Stack:\n${text(array(array(t.error.stack, '\n'), l => ` ${l}`), '\n')}\n`
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
txt_report += `\n`
|
txt_report = txt_report + `\n`
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!has_failures) txt_report += `None\n`
|
if (!has_failures) txt_report = txt_report + `None\n`
|
||||||
|
|
||||||
txt_report += `\n=== DETAILED RESULTS ===\n`
|
txt_report = txt_report + `\n=== DETAILED RESULTS ===\n`
|
||||||
for (var i = 0; i < length(all_results); i++) {
|
for (i = 0; i < length(all_results); i++) {
|
||||||
var pkg_res = all_results[i]
|
pkg_res = all_results[i]
|
||||||
if (pkg_res.total == 0) continue
|
if (pkg_res.total == 0) continue
|
||||||
|
|
||||||
for (var j = 0; j < length(pkg_res.files); j++) {
|
for (j = 0; j < length(pkg_res.files); j++) {
|
||||||
var f = pkg_res.files[j]
|
f = pkg_res.files[j]
|
||||||
for (var k = 0; k < length(f.tests); k++) {
|
for (k = 0; k < length(f.tests); k++) {
|
||||||
var t = f.tests[k]
|
t = f.tests[k]
|
||||||
var dur = `${t.duration_ns || 0}ns`
|
dur = `${t.duration_ns || 0}ns`
|
||||||
var status = t.status == "passed" ? "PASS" : "FAIL"
|
status = t.status == "passed" ? "PASS" : "FAIL"
|
||||||
txt_report += `[${status}] ${pkg_res.package} ${t.test} (${dur})\n`
|
txt_report = txt_report + `[${status}] ${pkg_res.package} ${t.test} (${dur})\n`
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -655,19 +714,19 @@ Total: ${totals.total}, Passed: ${totals.passed}, Failed: ${totals.failed}
|
|||||||
log.console(`Report written to ${report_dir}/test.txt`)
|
log.console(`Report written to ${report_dir}/test.txt`)
|
||||||
|
|
||||||
// Generate JSON per package
|
// Generate JSON per package
|
||||||
for (var i = 0; i < length(all_results); i++) {
|
for (i = 0; i < length(all_results); i++) {
|
||||||
var pkg_res = all_results[i]
|
pkg_res = all_results[i]
|
||||||
if (pkg_res.total == 0) continue
|
if (pkg_res.total == 0) continue
|
||||||
|
|
||||||
var pkg_tests = []
|
pkg_tests = []
|
||||||
for (var j = 0; j < length(pkg_res.files); j++) {
|
for (j = 0; j < length(pkg_res.files); j++) {
|
||||||
var f = pkg_res.files[j]
|
f = pkg_res.files[j]
|
||||||
for (var k = 0; k < length(f.tests); k++) {
|
for (k = 0; k < length(f.tests); k++) {
|
||||||
push(pkg_tests, f.tests[k])
|
push(pkg_tests, f.tests[k])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var json_path = `${report_dir}/${replace(pkg_res.package, /\//, '_')}.json`
|
json_path = `${report_dir}/${replace(pkg_res.package, /\//, '_')}.json`
|
||||||
fd.slurpwrite(json_path, stone(blob(json.encode(pkg_tests))))
|
fd.slurpwrite(json_path, stone(blob(json.encode(pkg_tests))))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
5
time.cm
5
time.cm
@@ -124,14 +124,15 @@ function time_number(_rec) {
|
|||||||
var dst = r.dst ? 1 : 0
|
var dst = r.dst ? 1 : 0
|
||||||
var yday = r.yday || 0
|
var yday = r.yday || 0
|
||||||
|
|
||||||
|
var i = 0
|
||||||
if (year > time.epoch) {
|
if (year > time.epoch) {
|
||||||
var i = time.epoch
|
i = time.epoch
|
||||||
while (i < year) {
|
while (i < year) {
|
||||||
c = c + time.day * time.yearsize(i)
|
c = c + time.day * time.yearsize(i)
|
||||||
i = i + 1
|
i = i + 1
|
||||||
}
|
}
|
||||||
} else if (year < time.epoch) {
|
} else if (year < time.epoch) {
|
||||||
var i = time.epoch - 1
|
i = time.epoch - 1
|
||||||
while (i > year) {
|
while (i > year) {
|
||||||
c = c + time.day * time.yearsize(i)
|
c = c + time.day * time.yearsize(i)
|
||||||
i = i - 1
|
i = i - 1
|
||||||
|
|||||||
96
toml.cm
96
toml.cm
@@ -26,23 +26,33 @@ function parse_toml(toml_text) {
|
|||||||
var current_section = result
|
var current_section = result
|
||||||
var current_section_name = ''
|
var current_section_name = ''
|
||||||
|
|
||||||
for (var i = 0; i < length(lines); i++) {
|
var i = 0
|
||||||
var line = trim(lines[i])
|
var line = null
|
||||||
|
var inner = null
|
||||||
|
var section_path = null
|
||||||
|
var j = 0
|
||||||
|
var key = null
|
||||||
|
var eq_index = null
|
||||||
|
var key_part = null
|
||||||
|
var value = null
|
||||||
|
var unquoted = null
|
||||||
|
for (i = 0; i < length(lines); i++) {
|
||||||
|
line = trim(lines[i])
|
||||||
if (line == null) line = lines[i]
|
if (line == null) line = lines[i]
|
||||||
// Skip empty lines and comments
|
// Skip empty lines and comments
|
||||||
if (!line || starts_with(line, '#')) continue
|
if (!line || starts_with(line, '#')) continue
|
||||||
|
|
||||||
// Section header
|
// Section header
|
||||||
if (starts_with(line, '[') && ends_with(line, ']')) {
|
if (starts_with(line, '[') && ends_with(line, ']')) {
|
||||||
var inner = text(line, 1, -1)
|
inner = text(line, 1, -1)
|
||||||
var section_path = parse_key_path(inner)
|
section_path = parse_key_path(inner)
|
||||||
if (section_path == null) return null
|
if (section_path == null) return null
|
||||||
|
|
||||||
current_section = result
|
current_section = result
|
||||||
current_section_name = text(section_path, '.')
|
current_section_name = text(section_path, '.')
|
||||||
|
|
||||||
for (var j = 0; j < length(section_path); j++) {
|
for (j = 0; j < length(section_path); j++) {
|
||||||
var key = section_path[j]
|
key = section_path[j]
|
||||||
|
|
||||||
// Only treat null as "missing"; do not clobber false/0/""
|
// Only treat null as "missing"; do not clobber false/0/""
|
||||||
if (current_section[key] == null) {
|
if (current_section[key] == null) {
|
||||||
@@ -58,18 +68,18 @@ function parse_toml(toml_text) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Key-value pair
|
// Key-value pair
|
||||||
var eq_index = search(line, '=')
|
eq_index = search(line, '=')
|
||||||
if (eq_index != null && eq_index > 0) {
|
if (eq_index != null && eq_index > 0) {
|
||||||
var key_part = trim(text(line, 0, eq_index))
|
key_part = trim(text(line, 0, eq_index))
|
||||||
var value = trim(text(line, eq_index + 1))
|
value = trim(text(line, eq_index + 1))
|
||||||
if (key_part == null) key_part = trim(text(line, 0, eq_index))
|
if (key_part == null) key_part = trim(text(line, 0, eq_index))
|
||||||
if (value == null) value = trim(text(line, eq_index + 1))
|
if (value == null) value = trim(text(line, eq_index + 1))
|
||||||
|
|
||||||
var key = parse_key(key_part)
|
key = parse_key(key_part)
|
||||||
if (key == null) return null
|
if (key == null) return null
|
||||||
|
|
||||||
if (starts_with(value, '"') && ends_with(value, '"')) {
|
if (starts_with(value, '"') && ends_with(value, '"')) {
|
||||||
var unquoted = text(value, 1, -1)
|
unquoted = text(value, 1, -1)
|
||||||
current_section[key] = toml_unescape(unquoted)
|
current_section[key] = toml_unescape(unquoted)
|
||||||
if (current_section[key] == null) return null
|
if (current_section[key] == null) return null
|
||||||
} else if (starts_with(value, '[') && ends_with(value, ']')) {
|
} else if (starts_with(value, '[') && ends_with(value, ']')) {
|
||||||
@@ -91,9 +101,9 @@ function parse_toml(toml_text) {
|
|||||||
|
|
||||||
function parse_key(str) {
|
function parse_key(str) {
|
||||||
if (!is_text(str)) return null
|
if (!is_text(str)) return null
|
||||||
|
var inner = null
|
||||||
if (starts_with(str, '"') && ends_with(str, '"')) {
|
if (starts_with(str, '"') && ends_with(str, '"')) {
|
||||||
var inner = text(str, 1, -1)
|
inner = text(str, 1, -1)
|
||||||
return toml_unescape(inner)
|
return toml_unescape(inner)
|
||||||
}
|
}
|
||||||
return str
|
return str
|
||||||
@@ -107,12 +117,15 @@ function parse_key_path(str) {
|
|||||||
var current = ''
|
var current = ''
|
||||||
var in_quote = false
|
var in_quote = false
|
||||||
|
|
||||||
for (var i = 0; i < length(str); i++) {
|
var i = 0
|
||||||
var c = str[i]
|
var c = null
|
||||||
|
var piece = null
|
||||||
|
for (i = 0; i < length(str); i++) {
|
||||||
|
c = str[i]
|
||||||
if (c == '"' && (i == 0 || str[i - 1] != '\\')) {
|
if (c == '"' && (i == 0 || str[i - 1] != '\\')) {
|
||||||
in_quote = !in_quote
|
in_quote = !in_quote
|
||||||
} else if (c == '.' && !in_quote) {
|
} else if (c == '.' && !in_quote) {
|
||||||
var piece = trim(current)
|
piece = trim(current)
|
||||||
if (piece == null) piece = trim(current)
|
if (piece == null) piece = trim(current)
|
||||||
push(parts, parse_key(piece))
|
push(parts, parse_key(piece))
|
||||||
current = ''
|
current = ''
|
||||||
@@ -140,14 +153,17 @@ function parse_array(str) {
|
|||||||
var current = ''
|
var current = ''
|
||||||
var in_quotes = false
|
var in_quotes = false
|
||||||
|
|
||||||
for (var i = 0; i < length(s); i++) {
|
var i = 0
|
||||||
var ch = s[i]
|
var ch = null
|
||||||
|
var piece = null
|
||||||
|
for (i = 0; i < length(s); i++) {
|
||||||
|
ch = s[i]
|
||||||
|
|
||||||
if (ch == '"' && (i == 0 || s[i - 1] != '\\')) {
|
if (ch == '"' && (i == 0 || s[i - 1] != '\\')) {
|
||||||
in_quotes = !in_quotes
|
in_quotes = !in_quotes
|
||||||
current = current + ch
|
current = current + ch
|
||||||
} else if (ch == ',' && !in_quotes) {
|
} else if (ch == ',' && !in_quotes) {
|
||||||
var piece = trim(current)
|
piece = trim(current)
|
||||||
if (piece == null) piece = trim(current)
|
if (piece == null) piece = trim(current)
|
||||||
push(items, parse_value(piece))
|
push(items, parse_value(piece))
|
||||||
current = ''
|
current = ''
|
||||||
@@ -181,12 +197,14 @@ function encode_toml(obj) {
|
|||||||
var result = []
|
var result = []
|
||||||
|
|
||||||
function encode_value(value) {
|
function encode_value(value) {
|
||||||
|
var items = null
|
||||||
|
var i = 0
|
||||||
if (is_text(value)) return '"' + toml_escape(value) + '"'
|
if (is_text(value)) return '"' + toml_escape(value) + '"'
|
||||||
if (is_logical(value)) return value ? 'true' : 'false'
|
if (is_logical(value)) return value ? 'true' : 'false'
|
||||||
if (is_number(value)) return text(value)
|
if (is_number(value)) return text(value)
|
||||||
if (is_array(value)) {
|
if (is_array(value)) {
|
||||||
var items = []
|
items = []
|
||||||
for (var i = 0; i < length(value); i++) push(items, encode_value(value[i]))
|
for (i = 0; i < length(value); i++) push(items, encode_value(value[i]))
|
||||||
return '[' + text(items, ', ') + ']'
|
return '[' + text(items, ', ') + ']'
|
||||||
}
|
}
|
||||||
return text(value)
|
return text(value)
|
||||||
@@ -201,29 +219,41 @@ function encode_toml(obj) {
|
|||||||
|
|
||||||
// First pass: encode top-level simple values
|
// First pass: encode top-level simple values
|
||||||
var keys = array(obj)
|
var keys = array(obj)
|
||||||
for (var i = 0; i < length(keys); i++) {
|
var i = 0
|
||||||
var key = keys[i]
|
var key = null
|
||||||
var value = obj[key]
|
var value = null
|
||||||
|
for (i = 0; i < length(keys); i++) {
|
||||||
|
key = keys[i]
|
||||||
|
value = obj[key]
|
||||||
if (!is_object(value)) push(result, quote_key(key) + ' = ' + encode_value(value))
|
if (!is_object(value)) push(result, quote_key(key) + ' = ' + encode_value(value))
|
||||||
}
|
}
|
||||||
|
|
||||||
// Second pass: encode nested objects
|
// Second pass: encode nested objects
|
||||||
function encode_section(o, path) {
|
function encode_section(o, path) {
|
||||||
var keys = array(o)
|
var keys = array(o)
|
||||||
for (var i = 0; i < length(keys); i++) {
|
var i = 0
|
||||||
var key = keys[i]
|
var key = null
|
||||||
var value = o[key]
|
var value = null
|
||||||
|
var quoted = null
|
||||||
|
var section_path = null
|
||||||
|
var section_keys = null
|
||||||
|
var j = 0
|
||||||
|
var sk = null
|
||||||
|
var sv = null
|
||||||
|
for (i = 0; i < length(keys); i++) {
|
||||||
|
key = keys[i]
|
||||||
|
value = o[key]
|
||||||
|
|
||||||
if (is_object(value)) {
|
if (is_object(value)) {
|
||||||
var quoted = quote_key(key)
|
quoted = quote_key(key)
|
||||||
var section_path = path ? path + '.' + quoted : quoted
|
section_path = path ? path + '.' + quoted : quoted
|
||||||
push(result, '[' + section_path + ']')
|
push(result, '[' + section_path + ']')
|
||||||
|
|
||||||
// Direct properties
|
// Direct properties
|
||||||
var section_keys = array(value)
|
section_keys = array(value)
|
||||||
for (var j = 0; j < length(section_keys); j++) {
|
for (j = 0; j < length(section_keys); j++) {
|
||||||
var sk = section_keys[j]
|
sk = section_keys[j]
|
||||||
var sv = value[sk]
|
sv = value[sk]
|
||||||
if (!is_object(sv)) push(result, quote_key(sk) + ' = ' + encode_value(sv))
|
if (!is_object(sv)) push(result, quote_key(sk) + ' = ' + encode_value(sv))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user