laymos 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +740 -0
- package/dist/cli/cli.d.ts +3 -0
- package/dist/cli/cli.d.ts.map +1 -0
- package/dist/cli/cli.js +6 -0
- package/dist/cli/index.d.ts +2 -0
- package/dist/cli/index.d.ts.map +1 -0
- package/dist/cli/index.js +1 -0
- package/dist/cli/run.d.ts +11 -0
- package/dist/cli/run.d.ts.map +1 -0
- package/dist/cli/run.js +242 -0
- package/dist/config/define-config.d.ts +3 -0
- package/dist/config/define-config.d.ts.map +1 -0
- package/dist/config/define-config.js +228 -0
- package/dist/config/index.d.ts +5 -0
- package/dist/config/index.d.ts.map +1 -0
- package/dist/config/index.js +4 -0
- package/dist/config/layer-graph.d.ts +7 -0
- package/dist/config/layer-graph.d.ts.map +1 -0
- package/dist/config/layer-graph.js +53 -0
- package/dist/config/layer.d.ts +5 -0
- package/dist/config/layer.d.ts.map +1 -0
- package/dist/config/layer.js +21 -0
- package/dist/config/module.d.ts +9 -0
- package/dist/config/module.d.ts.map +1 -0
- package/dist/config/module.js +29 -0
- package/dist/config/path.d.ts +4 -0
- package/dist/config/path.d.ts.map +1 -0
- package/dist/config/path.js +32 -0
- package/dist/config/types.d.ts +36 -0
- package/dist/config/types.d.ts.map +1 -0
- package/dist/config/types.js +1 -0
- package/dist/engine/1-extract/extract.d.ts +12 -0
- package/dist/engine/1-extract/extract.d.ts.map +1 -0
- package/dist/engine/1-extract/extract.js +160 -0
- package/dist/engine/1-extract/index.d.ts +3 -0
- package/dist/engine/1-extract/index.d.ts.map +1 -0
- package/dist/engine/1-extract/index.js +1 -0
- package/dist/engine/2-resolve/index.d.ts +3 -0
- package/dist/engine/2-resolve/index.d.ts.map +1 -0
- package/dist/engine/2-resolve/index.js +1 -0
- package/dist/engine/2-resolve/resolve.d.ts +24 -0
- package/dist/engine/2-resolve/resolve.d.ts.map +1 -0
- package/dist/engine/2-resolve/resolve.js +74 -0
- package/dist/engine/3-evaluate/evaluate.d.ts +10 -0
- package/dist/engine/3-evaluate/evaluate.d.ts.map +1 -0
- package/dist/engine/3-evaluate/evaluate.js +80 -0
- package/dist/engine/3-evaluate/index.d.ts +3 -0
- package/dist/engine/3-evaluate/index.d.ts.map +1 -0
- package/dist/engine/3-evaluate/index.js +1 -0
- package/dist/engine/4-emit/emit.d.ts +7 -0
- package/dist/engine/4-emit/emit.d.ts.map +1 -0
- package/dist/engine/4-emit/emit.js +77 -0
- package/dist/engine/4-emit/index.d.ts +2 -0
- package/dist/engine/4-emit/index.d.ts.map +1 -0
- package/dist/engine/4-emit/index.js +1 -0
- package/dist/engine/errors.d.ts +19 -0
- package/dist/engine/errors.d.ts.map +1 -0
- package/dist/engine/errors.js +5 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +1 -0
- package/dist/node.d.ts +24 -0
- package/dist/node.d.ts.map +1 -0
- package/dist/node.js +139 -0
- package/dist/report/architecture.d.ts +104 -0
- package/dist/report/architecture.d.ts.map +1 -0
- package/dist/report/architecture.js +1 -0
- package/dist/report/index.d.ts +3 -0
- package/dist/report/index.d.ts.map +1 -0
- package/dist/report/index.js +2 -0
- package/dist/report/stories.d.ts +22 -0
- package/dist/report/stories.d.ts.map +1 -0
- package/dist/report/stories.js +1 -0
- package/dist/story/artifact/artifact.d.ts +57 -0
- package/dist/story/artifact/artifact.d.ts.map +1 -0
- package/dist/story/artifact/artifact.js +234 -0
- package/dist/story/artifact/index.d.ts +2 -0
- package/dist/story/artifact/index.d.ts.map +1 -0
- package/dist/story/artifact/index.js +1 -0
- package/dist/story/artifact/storage.d.ts +10 -0
- package/dist/story/artifact/storage.d.ts.map +1 -0
- package/dist/story/artifact/storage.js +162 -0
- package/dist/story/artifact/types.d.ts +74 -0
- package/dist/story/artifact/types.d.ts.map +1 -0
- package/dist/story/artifact/types.js +1 -0
- package/dist/story/core/blocks.d.ts +20 -0
- package/dist/story/core/blocks.d.ts.map +1 -0
- package/dist/story/core/blocks.js +104 -0
- package/dist/story/core/declare.d.ts +63 -0
- package/dist/story/core/declare.d.ts.map +1 -0
- package/dist/story/core/declare.js +62 -0
- package/dist/story/core/index.d.ts +4 -0
- package/dist/story/core/index.d.ts.map +1 -0
- package/dist/story/core/index.js +1 -0
- package/dist/story/core/recorder.d.ts +38 -0
- package/dist/story/core/recorder.d.ts.map +1 -0
- package/dist/story/core/recorder.js +28 -0
- package/dist/story/core/runtime-context.d.ts +14 -0
- package/dist/story/core/runtime-context.d.ts.map +1 -0
- package/dist/story/core/runtime-context.js +19 -0
- package/dist/story/core/types.d.ts +21 -0
- package/dist/story/core/types.d.ts.map +1 -0
- package/dist/story/core/types.js +1 -0
- package/dist/story/effect/effect.d.ts +52 -0
- package/dist/story/effect/effect.d.ts.map +1 -0
- package/dist/story/effect/effect.js +99 -0
- package/dist/story/effect/index.d.ts +3 -0
- package/dist/story/effect/index.d.ts.map +1 -0
- package/dist/story/effect/index.js +1 -0
- package/dist/story/runner/index.d.ts +3 -0
- package/dist/story/runner/index.d.ts.map +1 -0
- package/dist/story/runner/index.js +1 -0
- package/dist/story/runner/runner.d.ts +44 -0
- package/dist/story/runner/runner.d.ts.map +1 -0
- package/dist/story/runner/runner.js +476 -0
- package/dist/story/story-runtime/index.d.ts +2 -0
- package/dist/story/story-runtime/index.d.ts.map +1 -0
- package/dist/story/story-runtime/index.js +1 -0
- package/dist/story/story-runtime/story-runtime.d.ts +52 -0
- package/dist/story/story-runtime/story-runtime.d.ts.map +1 -0
- package/dist/story/story-runtime/story-runtime.js +194 -0
- package/dist/story/vanilla/index.d.ts +29 -0
- package/dist/story/vanilla/index.d.ts.map +1 -0
- package/dist/story/vanilla/index.js +78 -0
- package/package.json +68 -0
|
@@ -0,0 +1,194 @@
|
|
|
1
|
+
import { Cause, Context, Effect, Exit } from 'effect';
|
|
2
|
+
import { addScenario, declareStoryGroup, declareStory, } from '../core/declare.js';
|
|
3
|
+
import { captureLocation, CurrentRecorder, resolveAttributes, } from '../core/recorder.js';
|
|
4
|
+
/** Declares the single Story owned by a Story file. */
|
|
5
|
+
export function story(name, meta) {
|
|
6
|
+
return new EffectStoryBuilderImpl(declareStory(name, meta));
|
|
7
|
+
}
|
|
8
|
+
/** Declares a reusable Story Group. */
|
|
9
|
+
export function storyGroup(name, meta) {
|
|
10
|
+
return new EffectStoryGroupImpl(declareStoryGroup(name, meta));
|
|
11
|
+
}
|
|
12
|
+
class EffectStoryGroupImpl {
|
|
13
|
+
declaration;
|
|
14
|
+
constructor(declaration) {
|
|
15
|
+
this.declaration = declaration;
|
|
16
|
+
}
|
|
17
|
+
group(name, meta) {
|
|
18
|
+
return new EffectStoryGroupImpl(declareStoryGroup(name, meta, this.declaration));
|
|
19
|
+
}
|
|
20
|
+
story(name, meta) {
|
|
21
|
+
return new EffectStoryBuilderImpl(declareStory(name, meta, this.declaration));
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
class EffectStoryBuilderImpl {
|
|
25
|
+
declaration;
|
|
26
|
+
constructor(declaration) {
|
|
27
|
+
this.declaration = declaration;
|
|
28
|
+
}
|
|
29
|
+
provide(layer) {
|
|
30
|
+
this.declaration.execution = {
|
|
31
|
+
execute: () => Effect.void,
|
|
32
|
+
layer,
|
|
33
|
+
};
|
|
34
|
+
return this;
|
|
35
|
+
}
|
|
36
|
+
execute(execute) {
|
|
37
|
+
const layer = this.declaration.execution?.layer;
|
|
38
|
+
this.declaration.execution = {
|
|
39
|
+
execute: execute,
|
|
40
|
+
...(layer === undefined ? {} : { layer }),
|
|
41
|
+
};
|
|
42
|
+
return new EffectStoryImpl(this.declaration);
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
class EffectStoryImpl {
|
|
46
|
+
declaration;
|
|
47
|
+
constructor(declaration) {
|
|
48
|
+
this.declaration = declaration;
|
|
49
|
+
}
|
|
50
|
+
scenario(name, meta, define) {
|
|
51
|
+
const builder = new EffectScenarioBuilderImpl();
|
|
52
|
+
define(builder);
|
|
53
|
+
addScenario(this.declaration, {
|
|
54
|
+
name,
|
|
55
|
+
description: meta.description,
|
|
56
|
+
mode: 'run',
|
|
57
|
+
run: builder.build(meta.timeout),
|
|
58
|
+
});
|
|
59
|
+
return this;
|
|
60
|
+
}
|
|
61
|
+
skip(name, meta) {
|
|
62
|
+
addScenario(this.declaration, {
|
|
63
|
+
name,
|
|
64
|
+
description: meta.description,
|
|
65
|
+
mode: 'skip',
|
|
66
|
+
});
|
|
67
|
+
return this;
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
class EffectScenarioBuilderImpl {
|
|
71
|
+
preparation;
|
|
72
|
+
expectation;
|
|
73
|
+
cleanupBody;
|
|
74
|
+
prepare(prepare) {
|
|
75
|
+
this.preparation = prepare;
|
|
76
|
+
return this;
|
|
77
|
+
}
|
|
78
|
+
verify(verify) {
|
|
79
|
+
this.expectation = { kind: 'success', verify };
|
|
80
|
+
return this;
|
|
81
|
+
}
|
|
82
|
+
verifyError(verify) {
|
|
83
|
+
this.expectation = { kind: 'error', verify };
|
|
84
|
+
return this;
|
|
85
|
+
}
|
|
86
|
+
cleanup(cleanup) {
|
|
87
|
+
this.cleanupBody = cleanup;
|
|
88
|
+
return this;
|
|
89
|
+
}
|
|
90
|
+
build(timeout) {
|
|
91
|
+
if (this.preparation === undefined)
|
|
92
|
+
throw new TypeError('Scenario preparation is required');
|
|
93
|
+
if (this.expectation === undefined)
|
|
94
|
+
throw new TypeError('Scenario verification is required');
|
|
95
|
+
return {
|
|
96
|
+
prepare: this.preparation,
|
|
97
|
+
expectation: this.expectation,
|
|
98
|
+
...(this.cleanupBody === undefined ? {} : { cleanup: this.cleanupBody }),
|
|
99
|
+
...(timeout === undefined ? {} : { timeout }),
|
|
100
|
+
};
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
const CurrentVisit = Context.Reference('laymos/story/current-visit', { defaultValue: () => undefined });
|
|
104
|
+
class DecisionBuilderImpl {
|
|
105
|
+
state;
|
|
106
|
+
constructor(state) {
|
|
107
|
+
this.state = state;
|
|
108
|
+
}
|
|
109
|
+
when(value, meta, body) {
|
|
110
|
+
requireDescription(meta.description, `Decision Arm "${meta.name ?? value}"`);
|
|
111
|
+
const arm = {
|
|
112
|
+
kind: 'literal',
|
|
113
|
+
value,
|
|
114
|
+
name: meta.name ?? String(value),
|
|
115
|
+
description: meta.description,
|
|
116
|
+
};
|
|
117
|
+
this.state.arms.push(arm);
|
|
118
|
+
if (!this.state.matched && Object.is(this.state.input, value)) {
|
|
119
|
+
this.state.matched = true;
|
|
120
|
+
this.state.selected = wrapEffect(this.state.block, { kind: 'literal', value }, () => resolveAttributes(this.state.attributes, [this.state.input]), body(value), this.state.arms);
|
|
121
|
+
}
|
|
122
|
+
return this;
|
|
123
|
+
}
|
|
124
|
+
otherwise(meta, body) {
|
|
125
|
+
requireDescription(meta.description, `Decision Arm "${meta.name ?? 'Otherwise'}"`);
|
|
126
|
+
const arm = {
|
|
127
|
+
kind: 'otherwise',
|
|
128
|
+
name: meta.name ?? 'Otherwise',
|
|
129
|
+
description: meta.description,
|
|
130
|
+
};
|
|
131
|
+
this.state.arms.push(arm);
|
|
132
|
+
if (!this.state.matched) {
|
|
133
|
+
this.state.matched = true;
|
|
134
|
+
this.state.selected = wrapEffect(this.state.block, { kind: 'otherwise' }, () => resolveAttributes(this.state.attributes, [this.state.input]), body(this.state.input), this.state.arms);
|
|
135
|
+
}
|
|
136
|
+
return this.state.selected;
|
|
137
|
+
}
|
|
138
|
+
exhaustive() {
|
|
139
|
+
return this.state.selected;
|
|
140
|
+
}
|
|
141
|
+
[Symbol.iterator]() {
|
|
142
|
+
return this.state.selected[Symbol.iterator]();
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
export function functionBlock(name, meta, fn) {
|
|
146
|
+
const block = makeBlock(name, meta, 'block');
|
|
147
|
+
return (...args) => wrapEffect(block, undefined, () => resolveAttributes(meta.attributes, args), fn(...args));
|
|
148
|
+
}
|
|
149
|
+
export function step(name, meta, effect) {
|
|
150
|
+
return wrapEffect(makeBlock(name, meta, 'block'), undefined, () => resolveAttributes(meta.attributes, []), effect);
|
|
151
|
+
}
|
|
152
|
+
export function decision(name, meta, input) {
|
|
153
|
+
return new DecisionBuilderImpl({
|
|
154
|
+
block: makeBlock(name, meta, 'decision'),
|
|
155
|
+
input,
|
|
156
|
+
attributes: meta.attributes,
|
|
157
|
+
arms: [],
|
|
158
|
+
matched: false,
|
|
159
|
+
selected: Effect.void,
|
|
160
|
+
});
|
|
161
|
+
}
|
|
162
|
+
function wrapEffect(block, selectedArm, attributes, effect, arms = []) {
|
|
163
|
+
return Effect.gen(function* () {
|
|
164
|
+
const recorder = yield* CurrentRecorder;
|
|
165
|
+
if (recorder === undefined)
|
|
166
|
+
return yield* effect;
|
|
167
|
+
for (const arm of arms)
|
|
168
|
+
recorder.declareArm(block, arm);
|
|
169
|
+
const parent = yield* CurrentVisit;
|
|
170
|
+
const token = recorder.start(block, selectedArm, attributes(), parent);
|
|
171
|
+
return yield* effect.pipe(Effect.onExit((exit) => Effect.sync(() => {
|
|
172
|
+
const outcome = Exit.isSuccess(exit)
|
|
173
|
+
? 'succeeded'
|
|
174
|
+
: Cause.hasInterruptsOnly(exit.cause)
|
|
175
|
+
? 'interrupted'
|
|
176
|
+
: 'failed';
|
|
177
|
+
recorder.finish(token, outcome);
|
|
178
|
+
})), Effect.provideService(CurrentVisit, token));
|
|
179
|
+
});
|
|
180
|
+
}
|
|
181
|
+
function makeBlock(name, meta, kind) {
|
|
182
|
+
requireDescription(meta.description, `${kind === 'decision' ? 'Decision' : 'Block'} "${name}"`);
|
|
183
|
+
return {
|
|
184
|
+
name,
|
|
185
|
+
kind,
|
|
186
|
+
location: captureLocation(),
|
|
187
|
+
description: meta.description,
|
|
188
|
+
};
|
|
189
|
+
}
|
|
190
|
+
function requireDescription(description, subject) {
|
|
191
|
+
if (description.trim().length === 0) {
|
|
192
|
+
throw new TypeError(`${subject} description must not be empty`);
|
|
193
|
+
}
|
|
194
|
+
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import type { StoryMeta } from '../core/types.js';
|
|
2
|
+
export { decision, functionBlock, step } from '../core/blocks.js';
|
|
3
|
+
export type { DecisionBuilder } from '../core/blocks.js';
|
|
4
|
+
export type { ArmMeta, Attributes, BlockMeta, DecisionValue, StoryMeta, } from '../core/types.js';
|
|
5
|
+
export interface ScenarioMeta {
|
|
6
|
+
readonly description: string;
|
|
7
|
+
readonly timeoutMillis?: number;
|
|
8
|
+
}
|
|
9
|
+
export interface VanillaVerifiedScenario<Prepared> {
|
|
10
|
+
cleanup(cleanup: (prepared: Prepared, signal: AbortSignal) => void | Promise<void>): VanillaVerifiedScenario<Prepared>;
|
|
11
|
+
}
|
|
12
|
+
export interface VanillaPreparedScenario<Prepared, Output> {
|
|
13
|
+
cleanup(cleanup: (prepared: Prepared, signal: AbortSignal) => void | Promise<void>): VanillaPreparedScenario<Prepared, Output>;
|
|
14
|
+
verify(verify: (output: Output, prepared: Prepared) => void | Promise<void>): VanillaVerifiedScenario<Prepared>;
|
|
15
|
+
verifyError(verify: (error: unknown, prepared: Prepared) => void | Promise<void>): VanillaVerifiedScenario<Prepared>;
|
|
16
|
+
}
|
|
17
|
+
export interface VanillaScenario<Prepared, Output> {
|
|
18
|
+
prepare(prepare: (signal: AbortSignal) => Prepared | Promise<Prepared>): VanillaPreparedScenario<Prepared, Output>;
|
|
19
|
+
}
|
|
20
|
+
export interface VanillaStory<Prepared, Output> {
|
|
21
|
+
scenario(name: string, meta: ScenarioMeta, define: (scenario: VanillaScenario<Prepared, Output>) => VanillaVerifiedScenario<Prepared>): VanillaStory<Prepared, Output>;
|
|
22
|
+
skip(name: string, meta: ScenarioMeta): VanillaStory<Prepared, Output>;
|
|
23
|
+
}
|
|
24
|
+
export interface VanillaStoryBuilder {
|
|
25
|
+
execute<Prepared, Output>(execute: (prepared: Prepared, signal: AbortSignal) => Output | Promise<Output>): VanillaStory<Prepared, Output>;
|
|
26
|
+
}
|
|
27
|
+
/** Declares the single Story owned by a Story file. */
|
|
28
|
+
export declare function story(name: string, meta: StoryMeta): VanillaStoryBuilder;
|
|
29
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/story/vanilla/index.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAElD,OAAO,EAAE,QAAQ,EAAE,aAAa,EAAE,IAAI,EAAE,MAAM,mBAAmB,CAAC;AAClE,YAAY,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AACzD,YAAY,EACV,OAAO,EACP,UAAU,EACV,SAAS,EACT,aAAa,EACb,SAAS,GACV,MAAM,kBAAkB,CAAC;AAE1B,MAAM,WAAW,YAAY;IAC3B,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,aAAa,CAAC,EAAE,MAAM,CAAC;CACjC;AAED,MAAM,WAAW,uBAAuB,CAAC,QAAQ;IAC/C,OAAO,CACL,OAAO,EAAE,CAAC,QAAQ,EAAE,QAAQ,EAAE,MAAM,EAAE,WAAW,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,GACzE,uBAAuB,CAAC,QAAQ,CAAC,CAAC;CACtC;AAED,MAAM,WAAW,uBAAuB,CAAC,QAAQ,EAAE,MAAM;IACvD,OAAO,CACL,OAAO,EAAE,CAAC,QAAQ,EAAE,QAAQ,EAAE,MAAM,EAAE,WAAW,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,GACzE,uBAAuB,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC;IAC7C,MAAM,CACJ,MAAM,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,QAAQ,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,GACnE,uBAAuB,CAAC,QAAQ,CAAC,CAAC;IACrC,WAAW,CACT,MAAM,EAAE,CAAC,KAAK,EAAE,OAAO,EAAE,QAAQ,EAAE,QAAQ,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,GACnE,uBAAuB,CAAC,QAAQ,CAAC,CAAC;CACtC;AAED,MAAM,WAAW,eAAe,CAAC,QAAQ,EAAE,MAAM;IAC/C,OAAO,CACL,OAAO,EAAE,CAAC,MAAM,EAAE,WAAW,KAAK,QAAQ,GAAG,OAAO,CAAC,QAAQ,CAAC,GAC7D,uBAAuB,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC;CAC9C;AAED,MAAM,WAAW,YAAY,CAAC,QAAQ,EAAE,MAAM;IAC5C,QAAQ,CACN,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE,YAAY,EAClB,MAAM,EAAE,CACN,QAAQ,EAAE,eAAe,CAAC,QAAQ,EAAE,MAAM,CAAC,KACxC,uBAAuB,CAAC,QAAQ,CAAC,GACrC,YAAY,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC;IAClC,IAAI,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,YAAY,GAAG,YAAY,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC;CACxE;AAED,MAAM,WAAW,mBAAmB;IAClC,OAAO,CAAC,QAAQ,EAAE,MAAM,EACtB,OAAO,EAAE,CACP,QAAQ,EAAE,QAAQ,EAClB,MAAM,EAAE,WAAW,KAChB,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,GAC5B,YAAY,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC;CACnC;AAED,uDAAuD;AACvD,wBAAgB,KAAK,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,SAAS,GAAG,mBAAmB,CAExE"}
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import { addScenario, declareStory, } from '../core/declare.js';
|
|
2
|
+
export { decision, functionBlock, step } from '../core/blocks.js';
|
|
3
|
+
/** Declares the single Story owned by a Story file. */
|
|
4
|
+
export function story(name, meta) {
|
|
5
|
+
return new VanillaStoryBuilderImpl(declareStory(name, meta));
|
|
6
|
+
}
|
|
7
|
+
class VanillaStoryBuilderImpl {
|
|
8
|
+
declaration;
|
|
9
|
+
constructor(declaration) {
|
|
10
|
+
this.declaration = declaration;
|
|
11
|
+
}
|
|
12
|
+
execute(execute) {
|
|
13
|
+
this.declaration.execution = {
|
|
14
|
+
kind: 'vanilla',
|
|
15
|
+
execute: execute,
|
|
16
|
+
};
|
|
17
|
+
return new VanillaStoryImpl(this.declaration);
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
class VanillaStoryImpl {
|
|
21
|
+
declaration;
|
|
22
|
+
constructor(declaration) {
|
|
23
|
+
this.declaration = declaration;
|
|
24
|
+
}
|
|
25
|
+
scenario(name, meta, define) {
|
|
26
|
+
const builder = new VanillaScenarioBuilderImpl();
|
|
27
|
+
define(builder);
|
|
28
|
+
addScenario(this.declaration, {
|
|
29
|
+
name,
|
|
30
|
+
description: meta.description,
|
|
31
|
+
mode: 'run',
|
|
32
|
+
run: builder.build(meta.timeoutMillis),
|
|
33
|
+
});
|
|
34
|
+
return this;
|
|
35
|
+
}
|
|
36
|
+
skip(name, meta) {
|
|
37
|
+
addScenario(this.declaration, {
|
|
38
|
+
name,
|
|
39
|
+
description: meta.description,
|
|
40
|
+
mode: 'skip',
|
|
41
|
+
});
|
|
42
|
+
return this;
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
class VanillaScenarioBuilderImpl {
|
|
46
|
+
preparation;
|
|
47
|
+
expectation;
|
|
48
|
+
cleanupBody;
|
|
49
|
+
prepare(prepare) {
|
|
50
|
+
this.preparation = prepare;
|
|
51
|
+
return this;
|
|
52
|
+
}
|
|
53
|
+
verify(verify) {
|
|
54
|
+
this.expectation = { kind: 'success', verify };
|
|
55
|
+
return this;
|
|
56
|
+
}
|
|
57
|
+
verifyError(verify) {
|
|
58
|
+
this.expectation = { kind: 'error', verify };
|
|
59
|
+
return this;
|
|
60
|
+
}
|
|
61
|
+
cleanup(cleanup) {
|
|
62
|
+
this.cleanupBody = cleanup;
|
|
63
|
+
return this;
|
|
64
|
+
}
|
|
65
|
+
build(timeoutMillis) {
|
|
66
|
+
if (this.preparation === undefined)
|
|
67
|
+
throw new TypeError('Scenario preparation is required');
|
|
68
|
+
if (this.expectation === undefined)
|
|
69
|
+
throw new TypeError('Scenario verification is required');
|
|
70
|
+
return {
|
|
71
|
+
kind: 'vanilla',
|
|
72
|
+
prepare: this.preparation,
|
|
73
|
+
expectation: this.expectation,
|
|
74
|
+
...(this.cleanupBody === undefined ? {} : { cleanup: this.cleanupBody }),
|
|
75
|
+
...(timeoutMillis === undefined ? {} : { timeoutMillis }),
|
|
76
|
+
};
|
|
77
|
+
}
|
|
78
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "laymos",
|
|
3
|
+
"version": "0.0.1",
|
|
4
|
+
"private": false,
|
|
5
|
+
"description": "Layers. Modules. Stories. Declare your architecture once; get enforcement and the diagram for free.",
|
|
6
|
+
"repository": {
|
|
7
|
+
"type": "git",
|
|
8
|
+
"url": "https://github.com/pkishorez/monorepo"
|
|
9
|
+
},
|
|
10
|
+
"license": "MIT",
|
|
11
|
+
"type": "module",
|
|
12
|
+
"exports": {
|
|
13
|
+
".": {
|
|
14
|
+
"types": "./dist/index.d.ts",
|
|
15
|
+
"import": "./dist/index.js",
|
|
16
|
+
"default": "./dist/index.js"
|
|
17
|
+
},
|
|
18
|
+
"./node": {
|
|
19
|
+
"types": "./dist/node.d.ts",
|
|
20
|
+
"import": "./dist/node.js",
|
|
21
|
+
"default": "./dist/node.js"
|
|
22
|
+
},
|
|
23
|
+
"./report": {
|
|
24
|
+
"types": "./dist/report/index.d.ts",
|
|
25
|
+
"import": "./dist/report/index.js",
|
|
26
|
+
"default": "./dist/report/index.js"
|
|
27
|
+
},
|
|
28
|
+
"./story": {
|
|
29
|
+
"types": "./dist/story/effect/index.d.ts",
|
|
30
|
+
"import": "./dist/story/effect/index.js",
|
|
31
|
+
"default": "./dist/story/effect/index.js"
|
|
32
|
+
}
|
|
33
|
+
},
|
|
34
|
+
"bin": {
|
|
35
|
+
"laymos": "dist/cli/cli.js"
|
|
36
|
+
},
|
|
37
|
+
"files": [
|
|
38
|
+
"dist",
|
|
39
|
+
"README.md",
|
|
40
|
+
"LICENSE"
|
|
41
|
+
],
|
|
42
|
+
"dependencies": {
|
|
43
|
+
"@effect/platform-node": "4.0.0-beta.98",
|
|
44
|
+
"jiti": "2.7.0",
|
|
45
|
+
"skott": "0.35.11"
|
|
46
|
+
},
|
|
47
|
+
"devDependencies": {
|
|
48
|
+
"@typescript/native": "npm:typescript@7.0.2",
|
|
49
|
+
"@types/node": "26.1.1",
|
|
50
|
+
"effect": "4.0.0-beta.98",
|
|
51
|
+
"typescript": "npm:@typescript/typescript6@6.0.2",
|
|
52
|
+
"vitest": "4.1.10"
|
|
53
|
+
},
|
|
54
|
+
"peerDependencies": {
|
|
55
|
+
"effect": "^4.0.0-beta.78"
|
|
56
|
+
},
|
|
57
|
+
"publishConfig": {
|
|
58
|
+
"access": "public"
|
|
59
|
+
},
|
|
60
|
+
"scripts": {
|
|
61
|
+
"build": "tsc",
|
|
62
|
+
"build:watch": "tsc --watch",
|
|
63
|
+
"fmt": "vp fmt",
|
|
64
|
+
"lint": "vp check && tsc --noEmit",
|
|
65
|
+
"lint:laymos": "jiti src/cli/cli.ts lint",
|
|
66
|
+
"test": "vitest run"
|
|
67
|
+
}
|
|
68
|
+
}
|