Import kabelsalat, update transpiler to handle K and S, add worklet control
This commit is contained in:
parent
fd472a64d9
commit
5caaf423ff
8 changed files with 311 additions and 8 deletions
|
|
@ -31,6 +31,7 @@
|
||||||
},
|
},
|
||||||
"homepage": "https://strudel.cc",
|
"homepage": "https://strudel.cc",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"@kabelsalat/web": "^0.4.0",
|
||||||
"fraction.js": "^5.2.1"
|
"fraction.js": "^5.2.1"
|
||||||
},
|
},
|
||||||
"gitHead": "0e26d4e741500f5bae35b023608f062a794905c2",
|
"gitHead": "0e26d4e741500f5bae35b023608f062a794905c2",
|
||||||
|
|
|
||||||
|
|
@ -3753,3 +3753,32 @@ Pattern.prototype.FX = function (...effects) {
|
||||||
return { ...v, FX: currFX.concat(vEff) };
|
return { ...v, FX: currFX.concat(vEff) };
|
||||||
}).appLeft(parray(effects));
|
}).appLeft(parray(effects));
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const _asArrayPattern = (pats) => {
|
||||||
|
const pack = (...xs) => xs;
|
||||||
|
let acc = pure(curry(pack, null, pats.length));
|
||||||
|
for (const p of pats) acc = acc.appLeft(p);
|
||||||
|
return acc;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a worklet effect. Typically derived by writing K(...) in the REPL which will parse
|
||||||
|
* Kabelsalat code.
|
||||||
|
*
|
||||||
|
* @name worklet
|
||||||
|
* @param {string} src Source code of the worklet update function
|
||||||
|
* @param {...number | ...Pattern} inputs Worklet inputs
|
||||||
|
* @memberof Pattern
|
||||||
|
* @returns Pattern
|
||||||
|
*/
|
||||||
|
Pattern.prototype.worklet = function (src, ...inputs) {
|
||||||
|
inputs = inputs.map(reify);
|
||||||
|
return this.outerBind((v) => {
|
||||||
|
return _asArrayPattern(inputs).withValue((vInput) => {
|
||||||
|
const currInputs = v.workletInputs ?? [];
|
||||||
|
return { ...v, workletSrc: src, workletInputs: currInputs.concat(vInput) };
|
||||||
|
});
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
export const worklet = (...args) => pure(0).worklet(...args);
|
||||||
|
|
|
||||||
|
|
@ -6,6 +6,7 @@ import { setTime } from './time.mjs';
|
||||||
import { evalScope } from './evaluate.mjs';
|
import { evalScope } from './evaluate.mjs';
|
||||||
import { register, Pattern, isPattern, silence, stack } from './pattern.mjs';
|
import { register, Pattern, isPattern, silence, stack } from './pattern.mjs';
|
||||||
import { reset_state } from './impure.mjs';
|
import { reset_state } from './impure.mjs';
|
||||||
|
import { SalatRepl } from '@kabelsalat/web';
|
||||||
|
|
||||||
export function repl({
|
export function repl({
|
||||||
defaultOutput,
|
defaultOutput,
|
||||||
|
|
@ -24,6 +25,7 @@ export function repl({
|
||||||
id,
|
id,
|
||||||
mondo = false,
|
mondo = false,
|
||||||
}) {
|
}) {
|
||||||
|
const kabel = new SalatRepl({ localScope: true });
|
||||||
const state = {
|
const state = {
|
||||||
schedulerError: undefined,
|
schedulerError: undefined,
|
||||||
evalError: undefined,
|
evalError: undefined,
|
||||||
|
|
@ -78,6 +80,11 @@ export function repl({
|
||||||
return silence;
|
return silence;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const compileKabel = (code) => {
|
||||||
|
const node = kabel.evaluate(code);
|
||||||
|
return node.compile({ log: false });
|
||||||
|
};
|
||||||
|
|
||||||
// helper to get a patternified pure value out
|
// helper to get a patternified pure value out
|
||||||
function unpure(pat) {
|
function unpure(pat) {
|
||||||
if (pat._Pattern) {
|
if (pat._Pattern) {
|
||||||
|
|
@ -198,6 +205,7 @@ export function repl({
|
||||||
setcps: setCps,
|
setcps: setCps,
|
||||||
setCpm,
|
setCpm,
|
||||||
setcpm: setCpm,
|
setcpm: setCpm,
|
||||||
|
compileKabel,
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -36,6 +36,7 @@
|
||||||
"vite-plugin-bundle-audioworklet": "workspace:*"
|
"vite-plugin-bundle-audioworklet": "workspace:*"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"@kabelsalat/lib": "^0.4.0",
|
||||||
"nanostores": "^0.11.3"
|
"nanostores": "^0.11.3"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
|
|
|
||||||
|
|
@ -15,6 +15,7 @@ import {
|
||||||
gainNode,
|
gainNode,
|
||||||
getCompressor,
|
getCompressor,
|
||||||
getDistortion,
|
getDistortion,
|
||||||
|
getFrequencyFromValue,
|
||||||
getLfo,
|
getLfo,
|
||||||
getWorklet,
|
getWorklet,
|
||||||
releaseAudioNode,
|
releaseAudioNode,
|
||||||
|
|
@ -407,9 +408,9 @@ function mapChannelNumbers(channels) {
|
||||||
}
|
}
|
||||||
|
|
||||||
class Chain {
|
class Chain {
|
||||||
constructor(head) {
|
constructor() {
|
||||||
this.audioNodes = [head];
|
this.audioNodes = [];
|
||||||
this.tails = [head];
|
this.tails = [];
|
||||||
}
|
}
|
||||||
connect(...nodes) {
|
connect(...nodes) {
|
||||||
nodes.forEach((node) => {
|
nodes.forEach((node) => {
|
||||||
|
|
@ -538,6 +539,8 @@ export const superdough = async (value, t, hapDuration, cps = 0.5, cycle = 0.5)
|
||||||
value.s = s;
|
value.s = s;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const chain = new Chain(); // connection manager which tracks audio nodes for releasing
|
||||||
|
|
||||||
// get source AudioNode
|
// get source AudioNode
|
||||||
let sourceNode;
|
let sourceNode;
|
||||||
if (source) {
|
if (source) {
|
||||||
|
|
@ -578,7 +581,8 @@ export const superdough = async (value, t, hapDuration, cps = 0.5, cycle = 0.5)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const chain = new Chain(sourceNode); // connection manager which tracks audio nodes for releasing
|
chain.connect(sourceNode);
|
||||||
|
|
||||||
FX = [...FX, value]; // run through the FX chain and then run through all FX outside of it as well
|
FX = [...FX, value]; // run through the FX chain and then run through all FX outside of it as well
|
||||||
for (let [idx, fx] of Object.entries(FX)) {
|
for (let [idx, fx] of Object.entries(FX)) {
|
||||||
const key = idx == FX.length - 1 ? 'main' : idx;
|
const key = idx == FX.length - 1 ? 'main' : idx;
|
||||||
|
|
@ -596,7 +600,6 @@ export const superdough = async (value, t, hapDuration, cps = 0.5, cycle = 0.5)
|
||||||
delayfeedback = getDefaultValue('delayfeedback'),
|
delayfeedback = getDefaultValue('delayfeedback'),
|
||||||
delaysync = getDefaultValue('delaysync'),
|
delaysync = getDefaultValue('delaysync'),
|
||||||
delaytime,
|
delaytime,
|
||||||
stretch = getDefaultValue('stretch'),
|
|
||||||
i = getDefaultValue('i'),
|
i = getDefaultValue('i'),
|
||||||
} = fx;
|
} = fx;
|
||||||
gain = applyGainCurve(nanFallback(gain, 1));
|
gain = applyGainCurve(nanFallback(gain, 1));
|
||||||
|
|
@ -607,8 +610,8 @@ export const superdough = async (value, t, hapDuration, cps = 0.5, cycle = 0.5)
|
||||||
gain *= velocity; // velocity currently only multiplies with gain. it might do other things in the future
|
gain *= velocity; // velocity currently only multiplies with gain. it might do other things in the future
|
||||||
delaytime = delaytime ?? cycleToSeconds(delaysync, cps);
|
delaytime = delaytime ?? cycleToSeconds(delaysync, cps);
|
||||||
|
|
||||||
if (stretch !== undefined) {
|
if (fx.stretch !== undefined) {
|
||||||
const phaseVocoder = getWorklet(ac, 'phase-vocoder-processor', { pitchFactor: stretch });
|
const phaseVocoder = getWorklet(ac, 'phase-vocoder-processor', { pitchFactor: fx.stretch });
|
||||||
chain.connect(phaseVocoder);
|
chain.connect(phaseVocoder);
|
||||||
fxNodes['stretch'] = [phaseVocoder];
|
fxNodes['stretch'] = [phaseVocoder];
|
||||||
}
|
}
|
||||||
|
|
@ -844,6 +847,17 @@ export const superdough = async (value, t, hapDuration, cps = 0.5, cycle = 0.5)
|
||||||
filterChain.forEach((f) => chain.connect(f));
|
filterChain.forEach((f) => chain.connect(f));
|
||||||
chain.audioNodes.push(lfo);
|
chain.audioNodes.push(lfo);
|
||||||
}
|
}
|
||||||
|
if (fx.workletSrc !== undefined) {
|
||||||
|
const workletNode = getWorklet(ac, 'generic-processor', {});
|
||||||
|
chain.connect(workletNode);
|
||||||
|
const workletSrc = fx.workletSrc
|
||||||
|
.replace(/\bpat\[(\d+)\]/g, (_, i) => fx.workletInputs[i])
|
||||||
|
.replaceAll('sFreq', getFrequencyFromValue(value))
|
||||||
|
.replaceAll('sGate', `cc('strudel-gate-${chainID}')`);
|
||||||
|
/* global compileKabel */
|
||||||
|
const { src, ugens, registers } = compileKabel(workletSrc);
|
||||||
|
workletNode.port.postMessage({ src, schema: { ugens, registers }, start: t, end });
|
||||||
|
}
|
||||||
// delay
|
// delay
|
||||||
if (key !== 'main' && delay > 0 && delaytime > 0 && delayfeedback > 0) {
|
if (key !== 'main' && delay > 0 && delaytime > 0 && delayfeedback > 0) {
|
||||||
const dry = gainNode(1);
|
const dry = gainNode(1);
|
||||||
|
|
|
||||||
|
|
@ -5,6 +5,9 @@
|
||||||
import OLAProcessor from './ola-processor';
|
import OLAProcessor from './ola-processor';
|
||||||
import FFT from './fft.js';
|
import FFT from './fft.js';
|
||||||
import { getDistortionAlgorithm } from './helpers.mjs';
|
import { getDistortionAlgorithm } from './helpers.mjs';
|
||||||
|
import * as ugens from '@kabelsalat/lib/src/ugens.js';
|
||||||
|
|
||||||
|
const UGENS = new Map(Object.entries(ugens));
|
||||||
|
|
||||||
const blockSize = 128;
|
const blockSize = 128;
|
||||||
const PI = Math.PI;
|
const PI = Math.PI;
|
||||||
|
|
@ -1478,3 +1481,73 @@ class TransientProcessor extends AudioWorkletProcessor {
|
||||||
}
|
}
|
||||||
|
|
||||||
registerProcessor('transient-processor', TransientProcessor);
|
registerProcessor('transient-processor', TransientProcessor);
|
||||||
|
|
||||||
|
class GenericProcessor extends AudioWorkletProcessor {
|
||||||
|
constructor() {
|
||||||
|
super();
|
||||||
|
this.playPos = 0;
|
||||||
|
const channels = 16;
|
||||||
|
this.outputs = new Array(channels).fill(0);
|
||||||
|
this.sources = new Array(channels).fill(0);
|
||||||
|
this.gateEnded = false;
|
||||||
|
this.started = false;
|
||||||
|
this.port.onmessage = (event) => {
|
||||||
|
let {
|
||||||
|
src,
|
||||||
|
schema: { ugens, registers },
|
||||||
|
start,
|
||||||
|
end,
|
||||||
|
} = event.data;
|
||||||
|
this.start = start;
|
||||||
|
this.end = end;
|
||||||
|
this.registers = new Array(registers).fill(0);
|
||||||
|
this.src = `o.fill(0); // reset outputs\n${src}`;
|
||||||
|
this.nodes = [];
|
||||||
|
for (let i = 0; i < ugens.length; i++) {
|
||||||
|
const ugen = ugens[i];
|
||||||
|
const nodeClass = UGENS.get(ugen.type);
|
||||||
|
const node = new nodeClass(i, ugen, sampleRate);
|
||||||
|
if (node.type === 'cc' && ugen.inputs?.[0]?.includes('strudel-gate')) {
|
||||||
|
node.setValue(1);
|
||||||
|
this.gateNode = node;
|
||||||
|
}
|
||||||
|
this.nodes[i] = node;
|
||||||
|
}
|
||||||
|
this.genSample = new Function(
|
||||||
|
'time',
|
||||||
|
'nodes',
|
||||||
|
'input',
|
||||||
|
'r', // registers
|
||||||
|
'o', // outputs
|
||||||
|
's', // sources
|
||||||
|
this.src,
|
||||||
|
);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
process(inputs, outputs) {
|
||||||
|
const input = inputs[0]?.[0];
|
||||||
|
if (this.genSample === undefined || currentTime < this.start) {
|
||||||
|
// pending
|
||||||
|
return true;
|
||||||
|
} else if (input === undefined) {
|
||||||
|
// if no input and started, return false and close worklet
|
||||||
|
// else just keep waiting (true)
|
||||||
|
return !this.started;
|
||||||
|
}
|
||||||
|
this.started = true;
|
||||||
|
if (!this.gateEnded && currentTime > this.end) {
|
||||||
|
this.gateNode?.setValue(0);
|
||||||
|
this.gateEnded = true;
|
||||||
|
}
|
||||||
|
const outL = outputs[0][0];
|
||||||
|
const outR = outputs[0][1] ?? outputs[0][0];
|
||||||
|
for (let n = 0; n < blockSize; n++) {
|
||||||
|
this.genSample(this.playPos, this.nodes, input ? input[n] : 0, this.registers, this.outputs, this.sources);
|
||||||
|
outL[n] = this.outputs[0];
|
||||||
|
outR[n] = this.outputs[1];
|
||||||
|
this.playPos += 1 / sampleRate;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
registerProcessor('generic-processor', GenericProcessor);
|
||||||
|
|
|
||||||
|
|
@ -110,7 +110,55 @@ export function transpiler(input, options = {}) {
|
||||||
return this.replace(labelToP(node));
|
return this.replace(labelToP(node));
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
leave(node, parent, prop, index) {},
|
|
||||||
|
leave(node, parent, prop, index) {
|
||||||
|
if (!isKabelCall(node)) return;
|
||||||
|
|
||||||
|
const [expr, ...rest] = node.arguments;
|
||||||
|
if (!expr) throw new Error('K(...) requires an expression');
|
||||||
|
|
||||||
|
const { template, patternExprs } = extractPatternPlaceholders(expr);
|
||||||
|
if (patternExprs.length) {
|
||||||
|
const workletArgs = [{ type: 'Literal', value: template }, ...patternExprs, ...rest];
|
||||||
|
|
||||||
|
let callee = node.callee;
|
||||||
|
if (callee.type === 'ChainExpression') callee = callee.expression;
|
||||||
|
if (callee.type === 'MemberExpression') {
|
||||||
|
return this.replace({
|
||||||
|
type: 'CallExpression',
|
||||||
|
callee: workletMemberAst(callee.object),
|
||||||
|
arguments: workletArgs,
|
||||||
|
optional: false,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return this.replace({
|
||||||
|
type: 'CallExpression',
|
||||||
|
callee: { type: 'Identifier', name: 'worklet' },
|
||||||
|
arguments: workletArgs,
|
||||||
|
optional: false,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
const kabelSrc = genExprSource(expr);
|
||||||
|
const workletArgs = [{ type: 'Literal', value: kabelSrc }, ...rest];
|
||||||
|
|
||||||
|
let callee = node.callee;
|
||||||
|
if (callee.type === 'ChainExpression') callee = callee.expression;
|
||||||
|
if (callee.type === 'MemberExpression') {
|
||||||
|
return this.replace({
|
||||||
|
type: 'CallExpression',
|
||||||
|
callee: workletMemberAst(callee.object),
|
||||||
|
arguments: workletArgs,
|
||||||
|
optional: false,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return this.replace({
|
||||||
|
type: 'CallExpression',
|
||||||
|
callee: { type: 'Identifier', name: 'worklet' },
|
||||||
|
arguments: workletArgs,
|
||||||
|
optional: false,
|
||||||
|
});
|
||||||
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
let { body } = ast;
|
let { body } = ast;
|
||||||
|
|
@ -146,6 +194,109 @@ export function transpiler(input, options = {}) {
|
||||||
return { output, miniLocations, widgets };
|
return { output, miniLocations, widgets };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function isKabelCall(node) {
|
||||||
|
if (node.type !== 'CallExpression') return false;
|
||||||
|
let callee = node.callee;
|
||||||
|
if (callee.type === 'ChainExpression') callee = callee.expression;
|
||||||
|
if (callee.type === 'MemberExpression') return !callee.computed && callee.property?.name === 'K';
|
||||||
|
return callee.type === 'Identifier' && callee.name === 'K';
|
||||||
|
}
|
||||||
|
|
||||||
|
function genExprSource(expr) {
|
||||||
|
return escodegen.generate(expr, { format: { semicolons: false } });
|
||||||
|
}
|
||||||
|
|
||||||
|
function extractPatternPlaceholders(expr) {
|
||||||
|
const templateExpr = cloneNode(expr);
|
||||||
|
const parents = new Map();
|
||||||
|
const targets = [];
|
||||||
|
|
||||||
|
walk(templateExpr, {
|
||||||
|
enter(node, parent, prop, index) {
|
||||||
|
parents.set(node, { parent, prop, index });
|
||||||
|
if (isStrudelPatternCall(node)) {
|
||||||
|
targets.push(node);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!targets.length) {
|
||||||
|
return { template: genExprSource(templateExpr), patternExprs: [] };
|
||||||
|
}
|
||||||
|
|
||||||
|
targets.sort((a, b) => (a.start ?? 0) - (b.start ?? 0));
|
||||||
|
|
||||||
|
const patternExprs = targets.map((node) => {
|
||||||
|
const arg = node.arguments?.[0];
|
||||||
|
if (!arg) {
|
||||||
|
throw new Error('S(...) requires an argument');
|
||||||
|
}
|
||||||
|
return cloneNode(arg);
|
||||||
|
});
|
||||||
|
|
||||||
|
let currentExpr = templateExpr;
|
||||||
|
targets.forEach((node, index) => {
|
||||||
|
currentExpr = replaceNode(node, placeholderAst(index), parents, currentExpr);
|
||||||
|
});
|
||||||
|
|
||||||
|
const template = genExprSource(currentExpr);
|
||||||
|
return { template, patternExprs };
|
||||||
|
}
|
||||||
|
|
||||||
|
function isStrudelPatternCall(node) {
|
||||||
|
if (node.type !== 'CallExpression') {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
const callee = node.callee;
|
||||||
|
if (callee.type === 'Identifier') {
|
||||||
|
return callee.name === 'S';
|
||||||
|
}
|
||||||
|
if (callee.type === 'MemberExpression' && !callee.computed) {
|
||||||
|
return callee.property?.name === 'S';
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
function placeholderAst(index) {
|
||||||
|
return {
|
||||||
|
type: 'MemberExpression',
|
||||||
|
object: { type: 'Identifier', name: 'pat' },
|
||||||
|
property: { type: 'Literal', value: index },
|
||||||
|
computed: true,
|
||||||
|
optional: false,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function replaceNode(node, replacement, parents, currentRoot) {
|
||||||
|
const info = parents.get(node);
|
||||||
|
if (!info || !info.parent) {
|
||||||
|
return replacement;
|
||||||
|
}
|
||||||
|
|
||||||
|
const { parent, prop, index } = info;
|
||||||
|
if (Array.isArray(parent[prop])) {
|
||||||
|
parent[prop][index] = replacement;
|
||||||
|
} else {
|
||||||
|
parent[prop] = replacement;
|
||||||
|
}
|
||||||
|
parents.set(replacement, { parent, prop, index });
|
||||||
|
return currentRoot;
|
||||||
|
}
|
||||||
|
|
||||||
|
function cloneNode(node) {
|
||||||
|
return JSON.parse(JSON.stringify(node));
|
||||||
|
}
|
||||||
|
|
||||||
|
function workletMemberAst(objectExpr) {
|
||||||
|
return {
|
||||||
|
type: 'MemberExpression',
|
||||||
|
object: objectExpr,
|
||||||
|
property: { type: 'Identifier', name: 'worklet' },
|
||||||
|
computed: false,
|
||||||
|
optional: false,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
function isStringWithDoubleQuotes(node, locations, code) {
|
function isStringWithDoubleQuotes(node, locations, code) {
|
||||||
if (node.type !== 'Literal') {
|
if (node.type !== 'Literal') {
|
||||||
return false;
|
return false;
|
||||||
|
|
|
||||||
26
pnpm-lock.yaml
generated
26
pnpm-lock.yaml
generated
|
|
@ -234,6 +234,9 @@ importers:
|
||||||
|
|
||||||
packages/core:
|
packages/core:
|
||||||
dependencies:
|
dependencies:
|
||||||
|
'@kabelsalat/web':
|
||||||
|
specifier: ^0.4.0
|
||||||
|
version: 0.4.0
|
||||||
fraction.js:
|
fraction.js:
|
||||||
specifier: ^5.2.1
|
specifier: ^5.2.1
|
||||||
version: 5.2.1
|
version: 5.2.1
|
||||||
|
|
@ -518,6 +521,9 @@ importers:
|
||||||
|
|
||||||
packages/superdough:
|
packages/superdough:
|
||||||
dependencies:
|
dependencies:
|
||||||
|
'@kabelsalat/lib':
|
||||||
|
specifier: ^0.4.0
|
||||||
|
version: 0.4.0
|
||||||
nanostores:
|
nanostores:
|
||||||
specifier: ^0.11.3
|
specifier: ^0.11.3
|
||||||
version: 0.11.3
|
version: 0.11.3
|
||||||
|
|
@ -1969,6 +1975,15 @@ packages:
|
||||||
resolution: {integrity: sha512-yYxMVH7Dqw6nO0d5NIV8OQWnitU8k6vXH8NtgqAfIa/IUqRMxRv/NUJJ08VEKbAakwxlgBl5PJdrU0dMPStsnw==}
|
resolution: {integrity: sha512-yYxMVH7Dqw6nO0d5NIV8OQWnitU8k6vXH8NtgqAfIa/IUqRMxRv/NUJJ08VEKbAakwxlgBl5PJdrU0dMPStsnw==}
|
||||||
engines: {node: '>=v12.0.0'}
|
engines: {node: '>=v12.0.0'}
|
||||||
|
|
||||||
|
'@kabelsalat/core@0.3.1':
|
||||||
|
resolution: {integrity: sha512-y2wHZyKnwbhJdGuwXvkaIb5vqbNTW6rMDnBslHGxQHTFX5xYyxJLOcuF2/EOB698t09kOVhmmpLXKbyokf3pOA==}
|
||||||
|
|
||||||
|
'@kabelsalat/lib@0.4.0':
|
||||||
|
resolution: {integrity: sha512-UoOUhYOFShDjYCTne1edevCHHxSC07FsxG9tQ5GGOOzNoKMUpGVY8Ecq9X1GVyseQFvQBgz3aqAC6K8FPZp4ZQ==}
|
||||||
|
|
||||||
|
'@kabelsalat/web@0.4.0':
|
||||||
|
resolution: {integrity: sha512-uvcOJjpKf8PG6KrgY0QEpoV4IAbIPDXh73bPtFSdDcXApbkSyEEyeNE8IoqIlqfcjIX926IOCAx9nM6FsFp6DA==}
|
||||||
|
|
||||||
'@lerna/create@8.1.9':
|
'@lerna/create@8.1.9':
|
||||||
resolution: {integrity: sha512-DPnl5lPX4v49eVxEbJnAizrpMdMTBz1qykZrAbBul9rfgk531v8oAt+Pm6O/rpAleRombNM7FJb5rYGzBJatOQ==}
|
resolution: {integrity: sha512-DPnl5lPX4v49eVxEbJnAizrpMdMTBz1qykZrAbBul9rfgk531v8oAt+Pm6O/rpAleRombNM7FJb5rYGzBJatOQ==}
|
||||||
engines: {node: '>=18.0.0'}
|
engines: {node: '>=18.0.0'}
|
||||||
|
|
@ -9261,6 +9276,17 @@ snapshots:
|
||||||
dependencies:
|
dependencies:
|
||||||
lodash: 4.17.21
|
lodash: 4.17.21
|
||||||
|
|
||||||
|
'@kabelsalat/core@0.3.1': {}
|
||||||
|
|
||||||
|
'@kabelsalat/lib@0.4.0':
|
||||||
|
dependencies:
|
||||||
|
'@kabelsalat/core': 0.3.1
|
||||||
|
|
||||||
|
'@kabelsalat/web@0.4.0':
|
||||||
|
dependencies:
|
||||||
|
'@kabelsalat/core': 0.3.1
|
||||||
|
'@kabelsalat/lib': 0.4.0
|
||||||
|
|
||||||
'@lerna/create@8.1.9(encoding@0.1.13)(typescript@5.7.3)':
|
'@lerna/create@8.1.9(encoding@0.1.13)(typescript@5.7.3)':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@npmcli/arborist': 7.5.4
|
'@npmcli/arborist': 7.5.4
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue