feat: Phase 1 — extract the client (web SPA + desktop) to dtoro/oikos-web
Problem: the hexagonal refactor churns the backend tree for nine more phases; the UI delivery stack (web/ SPA, cmd/desktop Wails wrapper, compose/web image) must move to its own repo first so doc/layout rewrites land once on a backend-only tree. Change: - New repo git.hubris.network/dtoro/oikos-web (v0.33.0): web/, desktop/ (updateURL repointed to oikos-web releases), compose/, own CI (web + desktop jobs), own deploy script (CI-green gate, TOCTOU guard, version-tagged images, prune-to-3), own webhook receiver on :9798 + launchd unit, own compose project publishing the same 8091:80. - Cutover executed on mac-mini in order: oikos stack's web service stopped+removed, oikos-web project brought up on 8091; outer Caddy untouched (targets the published port) — serving + Authentik flow + /wails 404 quirk verified post-cutover. - Stripped from oikos: web/, cmd/desktop/, compose/web/, desktop CI workflow, ci.yml web job, Makefile ui/desktop/desktop-package/install targets, the compose web service, oikos-web from deploy.sh's fallback prune list; wails + go-keyring dropped from go.mod, vendor synced. - README / CONTRIBUTING / AGENTS.md / .agents dev+operations docs now point at the new repo; mbse + mascot design docs carry a path note. Risk: production SPA serving depends on the new pipeline now; rollback is versioned-image re-up of the old web service from a pre-split checkout (port 8091). Desktop builds installed before the split still check dtoro/oikos releases — one manual reinstall, noted in the oikos-web release notes. Verification: go vet, make test (race), make generate-check, golangci (no new findings; baseline down 400→365); post-cutover curls — localhost:8091 200, /wails/runtime.js 404, outer Caddy 302 Authentik.
This commit is contained in:
290
web/node_modules/svelte-eslint-parser/lib/parser/analyze-scope.js
generated
vendored
Normal file
290
web/node_modules/svelte-eslint-parser/lib/parser/analyze-scope.js
generated
vendored
Normal file
@@ -0,0 +1,290 @@
|
||||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.analyzeScope = analyzeScope;
|
||||
exports.analyzeReactiveScope = analyzeReactiveScope;
|
||||
exports.analyzeStoreScope = analyzeStoreScope;
|
||||
exports.analyzePropsScope = analyzePropsScope;
|
||||
exports.analyzeSnippetsScope = analyzeSnippetsScope;
|
||||
const eslint_scope_1 = require("eslint-scope");
|
||||
const traverse_1 = require("../traverse");
|
||||
const scope_1 = require("../scope");
|
||||
const utils_1 = require("../utils");
|
||||
/**
|
||||
* Analyze scope
|
||||
*/
|
||||
function analyzeScope(node, parserOptions) {
|
||||
const ecmaVersion = parserOptions.ecmaVersion || 2020;
|
||||
const ecmaFeatures = parserOptions.ecmaFeatures || {};
|
||||
const sourceType = parserOptions.sourceType || "module";
|
||||
const root = node.type === "Program"
|
||||
? node
|
||||
: {
|
||||
type: "Program",
|
||||
body: [node],
|
||||
sourceType,
|
||||
};
|
||||
return (0, eslint_scope_1.analyze)(root, {
|
||||
ignoreEval: true,
|
||||
nodejsScope: false,
|
||||
impliedStrict: ecmaFeatures.impliedStrict,
|
||||
ecmaVersion: typeof ecmaVersion === "number" ? ecmaVersion : 2022,
|
||||
sourceType,
|
||||
fallback: traverse_1.getFallbackKeys,
|
||||
});
|
||||
}
|
||||
/** Analyze reactive scope */
|
||||
function analyzeReactiveScope(scopeManager) {
|
||||
for (const reference of [...scopeManager.globalScope.through]) {
|
||||
const parent = reference.writeExpr && getParent(reference.writeExpr);
|
||||
if ((parent === null || parent === void 0 ? void 0 : parent.type) === "AssignmentExpression") {
|
||||
const pp = getParent(parent);
|
||||
if ((pp === null || pp === void 0 ? void 0 : pp.type) === "ExpressionStatement") {
|
||||
const ppp = getParent(pp);
|
||||
if ((ppp === null || ppp === void 0 ? void 0 : ppp.type) === "SvelteReactiveStatement" && ppp.label.name === "$") {
|
||||
const referenceScope = reference.from;
|
||||
if (referenceScope.type === "module") {
|
||||
// It is computed
|
||||
transformComputedVariable(parent, ppp, reference);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
/** Transform ref to ComputedVariable */
|
||||
function transformComputedVariable(node, parent, reference) {
|
||||
const referenceScope = reference.from;
|
||||
const name = reference.identifier.name;
|
||||
let variable = referenceScope.set.get(name);
|
||||
if (!variable) {
|
||||
variable = new eslint_scope_1.Variable();
|
||||
variable.scope = referenceScope;
|
||||
variable.name = name;
|
||||
(0, utils_1.addElementToSortedArray)(variable.defs, {
|
||||
type: "ComputedVariable",
|
||||
node: node,
|
||||
parent: parent,
|
||||
name: reference.identifier,
|
||||
}, (a, b) => a.node.range[0] - b.node.range[0]);
|
||||
(0, scope_1.addVariable)(referenceScope.variables, variable);
|
||||
referenceScope.set.set(name, variable);
|
||||
}
|
||||
(0, utils_1.addElementToSortedArray)(variable.identifiers, reference.identifier, (a, b) => a.range[0] - b.range[0]);
|
||||
reference.resolved = variable;
|
||||
removeReferenceFromThrough(reference, referenceScope);
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Analyze store scope. e.g. $count
|
||||
*/
|
||||
function analyzeStoreScope(scopeManager) {
|
||||
const moduleScope = scopeManager.scopes.find((scope) => scope.type === "module");
|
||||
if (!moduleScope) {
|
||||
return;
|
||||
}
|
||||
const toBeMarkAsUsedReferences = [];
|
||||
for (const reference of [...scopeManager.globalScope.through]) {
|
||||
if (reference.identifier.name.startsWith("$")) {
|
||||
const realName = reference.identifier.name.slice(1);
|
||||
const variable = moduleScope.set.get(realName);
|
||||
if (variable) {
|
||||
if (reference.isWriteOnly()) {
|
||||
// Need mark as used
|
||||
toBeMarkAsUsedReferences.push(reference);
|
||||
}
|
||||
// It does not write directly to the original variable.
|
||||
// Therefore, this variable is always a reference.
|
||||
reference.isWrite = () => false;
|
||||
reference.isWriteOnly = () => false;
|
||||
reference.isReadWrite = () => false;
|
||||
reference.isReadOnly = () => true;
|
||||
reference.isRead = () => true;
|
||||
(0, scope_1.addReference)(variable.references, reference);
|
||||
reference.resolved = variable;
|
||||
removeReferenceFromThrough(reference, moduleScope);
|
||||
}
|
||||
}
|
||||
}
|
||||
for (const variable of new Set(toBeMarkAsUsedReferences.map((ref) => ref.resolved))) {
|
||||
if (variable.references.some((ref) => !toBeMarkAsUsedReferences.includes(ref) &&
|
||||
ref.identifier !== variable.identifiers[0])) {
|
||||
// It is already used.
|
||||
continue;
|
||||
}
|
||||
// Add the virtual reference for reading.
|
||||
addVirtualReference(variable.identifiers[0], variable, moduleScope, {
|
||||
read: true,
|
||||
}).svelteMarkAsUsed = true;
|
||||
}
|
||||
}
|
||||
/** Transform props exports */
|
||||
function analyzePropsScope(body, scopeManager, svelteParseContext) {
|
||||
var _a;
|
||||
const moduleScope = scopeManager.scopes.find((scope) => scope.type === "module");
|
||||
if (!moduleScope) {
|
||||
return;
|
||||
}
|
||||
for (const node of body.body) {
|
||||
if (node.type === "ExportNamedDeclaration") {
|
||||
// Process for Svelte v4 style props. e.g. `export let x`;
|
||||
if (node.declaration) {
|
||||
if (node.declaration.type === "VariableDeclaration") {
|
||||
for (const decl of node.declaration.declarations) {
|
||||
for (const pattern of extractPattern(decl.id)) {
|
||||
if (pattern.type === "Identifier") {
|
||||
addPropReference(pattern, moduleScope);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
for (const spec of node.specifiers) {
|
||||
if (spec.local.type !== "Literal") {
|
||||
addPropReference(spec.local, moduleScope);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (node.type === "VariableDeclaration") {
|
||||
if (svelteParseContext.runes) {
|
||||
// Process for Svelte v5 Runes props. e.g. `let { x = $bindable() } = $props()`;
|
||||
for (const decl of node.declarations) {
|
||||
if (((_a = decl.init) === null || _a === void 0 ? void 0 : _a.type) === "CallExpression" &&
|
||||
decl.init.callee.type === "Identifier" &&
|
||||
decl.init.callee.name === "$props" &&
|
||||
decl.id.type === "ObjectPattern") {
|
||||
for (const pattern of extractPattern(decl.id)) {
|
||||
if (pattern.type === "AssignmentPattern" &&
|
||||
pattern.left.type === "Identifier" &&
|
||||
pattern.right.type === "CallExpression" &&
|
||||
pattern.right.callee.type === "Identifier" &&
|
||||
pattern.right.callee.name === "$bindable") {
|
||||
addPropReference(pattern.left, moduleScope);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
function* extractPattern(node) {
|
||||
yield node;
|
||||
if (node.type === "Identifier") {
|
||||
return;
|
||||
}
|
||||
if (node.type === "ObjectPattern") {
|
||||
for (const prop of node.properties) {
|
||||
if (prop.type === "Property") {
|
||||
yield* extractPattern(prop.value);
|
||||
}
|
||||
else {
|
||||
yield* extractPattern(prop);
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (node.type === "ArrayPattern") {
|
||||
for (const elem of node.elements) {
|
||||
if (elem) {
|
||||
yield* extractPattern(elem);
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (node.type === "AssignmentPattern") {
|
||||
yield* extractPattern(node.left);
|
||||
return;
|
||||
}
|
||||
if (node.type === "RestElement") {
|
||||
yield* extractPattern(node.argument);
|
||||
}
|
||||
}
|
||||
/** Add virtual prop reference */
|
||||
function addPropReference(node, scope) {
|
||||
for (const variable of scope.variables) {
|
||||
if (variable.name !== node.name) {
|
||||
continue;
|
||||
}
|
||||
if (variable.references.some((ref) => ref.sveltePropReference)) {
|
||||
continue;
|
||||
}
|
||||
// Add the virtual reference for writing.
|
||||
const reference = addVirtualReference(Object.assign(Object.assign({}, node), {
|
||||
// @ts-expect-error -- ignore
|
||||
parent: body, loc: {
|
||||
start: Object.assign({}, node.loc.start),
|
||||
end: Object.assign({}, node.loc.end),
|
||||
}, range: [...node.range] }), variable, scope, {
|
||||
write: true,
|
||||
read: true,
|
||||
});
|
||||
reference.sveltePropReference = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
/** Analyze snippets in component scope */
|
||||
function analyzeSnippetsScope(snippets, scopeManager) {
|
||||
for (const snippet of snippets) {
|
||||
const parent = snippet.parent;
|
||||
if (parent.type === "SvelteElement" &&
|
||||
(parent.kind === "component" ||
|
||||
(parent.kind === "special" && parent.name.name === "svelte:component"))) {
|
||||
const scope = (0, scope_1.getScopeFromNode)(scopeManager, snippet.id);
|
||||
const upperScope = scope.upper;
|
||||
if (!upperScope)
|
||||
continue;
|
||||
const variable = upperScope.set.get(snippet.id.name);
|
||||
if (!variable)
|
||||
continue;
|
||||
// Add the virtual reference for reading.
|
||||
const reference = addVirtualReference(snippet.id, variable, upperScope, {
|
||||
read: true,
|
||||
});
|
||||
reference.svelteSnippetReference = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
/** Remove reference from through */
|
||||
function removeReferenceFromThrough(reference, baseScope) {
|
||||
const variable = reference.resolved;
|
||||
const name = reference.identifier.name;
|
||||
let scope = baseScope;
|
||||
while (scope) {
|
||||
scope.through = scope.through.filter((ref) => {
|
||||
if (reference === ref) {
|
||||
return false;
|
||||
}
|
||||
else if (ref.identifier.name === name) {
|
||||
ref.resolved = variable;
|
||||
if (!variable.references.includes(ref)) {
|
||||
(0, scope_1.addReference)(variable.references, ref);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
});
|
||||
scope = scope.upper;
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Add the virtual reference.
|
||||
*/
|
||||
function addVirtualReference(node, variable, scope, readWrite) {
|
||||
const reference = new eslint_scope_1.Reference();
|
||||
reference.svelteVirtualReference = true;
|
||||
reference.from = scope;
|
||||
reference.identifier = node;
|
||||
reference.isWrite = () => Boolean(readWrite.write);
|
||||
reference.isWriteOnly = () => Boolean(readWrite.write) && !readWrite.read;
|
||||
reference.isRead = () => Boolean(readWrite.read);
|
||||
reference.isReadOnly = () => Boolean(readWrite.read) && !readWrite.write;
|
||||
reference.isReadWrite = () => Boolean(readWrite.read && readWrite.write);
|
||||
(0, scope_1.addReference)(variable.references, reference);
|
||||
reference.resolved = variable;
|
||||
return reference;
|
||||
}
|
||||
/** Get parent node */
|
||||
function getParent(node) {
|
||||
return node.parent;
|
||||
}
|
||||
Reference in New Issue
Block a user