Add provide/context/emit!/emitted — render-time dynamic scope
Four new primitives for scoped downward value passing and upward accumulation through the render tree. Specced in .sx, bootstrapped to Python and JS across all adapters (eval, html, sx, dom, async). Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -868,6 +868,7 @@ PREAMBLE = '''\
|
||||
SxSpread.prototype._spread = true;
|
||||
|
||||
var _collectBuckets = {};
|
||||
var _provideStacks = {};
|
||||
|
||||
function isSym(x) { return x != null && x._sym === true; }
|
||||
function isKw(x) { return x != null && x._kw === true; }
|
||||
@@ -1087,6 +1088,12 @@ PRIMITIVES_JS_MODULES: dict[str, str] = {
|
||||
PRIMITIVES["collect!"] = sxCollect;
|
||||
PRIMITIVES["collected"] = sxCollected;
|
||||
PRIMITIVES["clear-collected!"] = sxClearCollected;
|
||||
// provide/context/emit! — render-time dynamic scope
|
||||
PRIMITIVES["provide-push!"] = providePush;
|
||||
PRIMITIVES["provide-pop!"] = providePop;
|
||||
PRIMITIVES["context"] = sxContext;
|
||||
PRIMITIVES["emit!"] = sxEmit;
|
||||
PRIMITIVES["emitted"] = sxEmitted;
|
||||
''',
|
||||
}
|
||||
# Modules to include by default (all)
|
||||
@@ -1162,6 +1169,35 @@ PLATFORM_JS_PRE = '''
|
||||
if (_collectBuckets[bucket]) _collectBuckets[bucket] = [];
|
||||
}
|
||||
|
||||
function providePush(name, value) {
|
||||
if (!_provideStacks[name]) _provideStacks[name] = [];
|
||||
_provideStacks[name].push({value: value !== undefined ? value : NIL, emitted: []});
|
||||
}
|
||||
function providePop(name) {
|
||||
if (_provideStacks[name] && _provideStacks[name].length) _provideStacks[name].pop();
|
||||
}
|
||||
function sxContext(name) {
|
||||
if (_provideStacks[name] && _provideStacks[name].length) {
|
||||
return _provideStacks[name][_provideStacks[name].length - 1].value;
|
||||
}
|
||||
if (arguments.length > 1) return arguments[1];
|
||||
throw new Error("No provider for: " + name);
|
||||
}
|
||||
function sxEmit(name, value) {
|
||||
if (_provideStacks[name] && _provideStacks[name].length) {
|
||||
_provideStacks[name][_provideStacks[name].length - 1].emitted.push(value);
|
||||
} else {
|
||||
throw new Error("No provider for emit!: " + name);
|
||||
}
|
||||
return NIL;
|
||||
}
|
||||
function sxEmitted(name) {
|
||||
if (_provideStacks[name] && _provideStacks[name].length) {
|
||||
return _provideStacks[name][_provideStacks[name].length - 1].emitted.slice();
|
||||
}
|
||||
return [];
|
||||
}
|
||||
|
||||
function lambdaParams(f) { return f.params; }
|
||||
function lambdaBody(f) { return f.body; }
|
||||
function lambdaClosure(f) { return f.closure; }
|
||||
@@ -3192,6 +3228,11 @@ def public_api_js(has_html, has_sx, has_dom, has_engine, has_orch, has_boot, has
|
||||
api_lines.append(' collect: sxCollect,')
|
||||
api_lines.append(' collected: sxCollected,')
|
||||
api_lines.append(' clearCollected: sxClearCollected,')
|
||||
api_lines.append(' providePush: providePush,')
|
||||
api_lines.append(' providePop: providePop,')
|
||||
api_lines.append(' context: sxContext,')
|
||||
api_lines.append(' emit: sxEmit,')
|
||||
api_lines.append(' emitted: sxEmitted,')
|
||||
api_lines.append(f' _version: "{version}"')
|
||||
api_lines.append(' };')
|
||||
api_lines.append('')
|
||||
|
||||
Reference in New Issue
Block a user