@patterkit/core 0.2.5 → 0.3.0
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/dist/index.cjs +74 -0
- package/dist/index.d.cts +49 -1
- package/dist/index.d.ts +49 -1
- package/dist/index.js +72 -0
- package/package.json +2 -2
package/dist/index.cjs
CHANGED
|
@@ -29,6 +29,8 @@ __export(index_exports, {
|
|
|
29
29
|
isValidGameId: () => import_model4.isValidGameId,
|
|
30
30
|
newId: () => import_toolkit.newId,
|
|
31
31
|
parseSource: () => import_toolkit3.parseSource,
|
|
32
|
+
planProject: () => planProject,
|
|
33
|
+
planScene: () => planScene,
|
|
32
34
|
slug: () => slug,
|
|
33
35
|
validateProject: () => validateProject
|
|
34
36
|
});
|
|
@@ -472,6 +474,76 @@ function defaultMatchesType(value, decl) {
|
|
|
472
474
|
return typeof value === "string" && (decl.stages?.includes(value) ?? true);
|
|
473
475
|
}
|
|
474
476
|
}
|
|
477
|
+
|
|
478
|
+
// src/scene-scaffold.ts
|
|
479
|
+
var trimSlash = (p) => p.replace(/\/+$/, "");
|
|
480
|
+
function planProject(opts) {
|
|
481
|
+
const locale = opts.locale ?? "en";
|
|
482
|
+
const project = {
|
|
483
|
+
schema: "patter/project@0",
|
|
484
|
+
project: { id: (0, import_toolkit.newId)("proj"), name: opts.name },
|
|
485
|
+
locales: { default: locale, all: [locale] },
|
|
486
|
+
voiced: true
|
|
487
|
+
};
|
|
488
|
+
return { path: `${slug(opts.name) || "project"}.patterproj`, content: canonicalStringify(project) };
|
|
489
|
+
}
|
|
490
|
+
function planScene(target, scaffold) {
|
|
491
|
+
const base = slug(scaffold.gameId) || slug(scaffold.name) || "scene";
|
|
492
|
+
let stem = base;
|
|
493
|
+
for (let n = 2; target.takenStems.has(stem); n++) stem = `${base}-${n}`;
|
|
494
|
+
const strings = {};
|
|
495
|
+
const say = (prefix, text) => {
|
|
496
|
+
const id = (0, import_toolkit.newId)(prefix);
|
|
497
|
+
strings[id] = text;
|
|
498
|
+
return { id, kind: "text" };
|
|
499
|
+
};
|
|
500
|
+
const opening = {
|
|
501
|
+
id: (0, import_toolkit.newId)("sn"),
|
|
502
|
+
type: "snippet",
|
|
503
|
+
beats: [say("T", scaffold.opening?.trim() || `Write the scene for "${scaffold.name}" here.`)]
|
|
504
|
+
};
|
|
505
|
+
const children = [opening];
|
|
506
|
+
if (scaffold.outcomes.length <= 1) {
|
|
507
|
+
opening.jump = { to: "END" };
|
|
508
|
+
} else {
|
|
509
|
+
children.push({
|
|
510
|
+
id: (0, import_toolkit.newId)("g"),
|
|
511
|
+
type: "group",
|
|
512
|
+
selector: "choice",
|
|
513
|
+
children: scaffold.outcomes.map((o) => ({
|
|
514
|
+
id: (0, import_toolkit.newId)("opt"),
|
|
515
|
+
type: "group",
|
|
516
|
+
prompt: say("L", o.title?.trim() || o.gameId),
|
|
517
|
+
gameData: { outcome: o.gameId },
|
|
518
|
+
children: [{
|
|
519
|
+
id: (0, import_toolkit.newId)("sn"),
|
|
520
|
+
type: "snippet",
|
|
521
|
+
beats: [say("T", "What happens next.")],
|
|
522
|
+
jump: { to: "END" }
|
|
523
|
+
}]
|
|
524
|
+
}))
|
|
525
|
+
});
|
|
526
|
+
}
|
|
527
|
+
const sceneId = (0, import_toolkit.newId)("scn");
|
|
528
|
+
const scene = {
|
|
529
|
+
id: sceneId,
|
|
530
|
+
type: "scene",
|
|
531
|
+
name: scaffold.name,
|
|
532
|
+
gameId: scaffold.gameId,
|
|
533
|
+
blocks: [{ id: (0, import_toolkit.newId)("blk"), type: "block", name: "Main", children }]
|
|
534
|
+
};
|
|
535
|
+
const flow = { schema: "patter/flow@0", scene };
|
|
536
|
+
const locale = { schema: "patter/strings@0", scene: sceneId, locale: target.locale, default: true, strings };
|
|
537
|
+
const flowDir = trimSlash(target.layout?.flow ?? "scenes/");
|
|
538
|
+
const stringsDir = trimSlash(target.layout?.strings ?? "loc/");
|
|
539
|
+
return {
|
|
540
|
+
sceneId,
|
|
541
|
+
writes: [
|
|
542
|
+
{ path: `${flowDir}/${stem}.patterflow`, content: canonicalStringify(flow) },
|
|
543
|
+
{ path: `${stringsDir}/${target.locale}/${stem}.patterloc`, content: canonicalStringify(locale) }
|
|
544
|
+
]
|
|
545
|
+
};
|
|
546
|
+
}
|
|
475
547
|
// Annotate the CommonJS export names for ESM import in node:
|
|
476
548
|
0 && (module.exports = {
|
|
477
549
|
canonicalStringify,
|
|
@@ -483,6 +555,8 @@ function defaultMatchesType(value, decl) {
|
|
|
483
555
|
isValidGameId,
|
|
484
556
|
newId,
|
|
485
557
|
parseSource,
|
|
558
|
+
planProject,
|
|
559
|
+
planScene,
|
|
486
560
|
slug,
|
|
487
561
|
validateProject
|
|
488
562
|
});
|
package/dist/index.d.cts
CHANGED
|
@@ -40,4 +40,52 @@ interface ProjectInput {
|
|
|
40
40
|
/** Validate a project's structural invariants. Returns an empty array when valid. */
|
|
41
41
|
declare function validateProject(input: ProjectInput): ValidationIssue[];
|
|
42
42
|
|
|
43
|
-
|
|
43
|
+
interface SceneScaffold {
|
|
44
|
+
/** The scene's name: the card's title. */
|
|
45
|
+
name: string;
|
|
46
|
+
/** The scene's address, pinned: the card's gameId, so the pairing never depends on the name. */
|
|
47
|
+
gameId: string;
|
|
48
|
+
/** The opening narration: the card's purpose, say. A prompt to write the scene when absent. */
|
|
49
|
+
opening?: string;
|
|
50
|
+
/** The card's outcomes: `gameId` labels an option, `title` is its words. */
|
|
51
|
+
outcomes: ReadonlyArray<{
|
|
52
|
+
gameId: string;
|
|
53
|
+
title?: string;
|
|
54
|
+
}>;
|
|
55
|
+
}
|
|
56
|
+
interface ScenePlanTarget {
|
|
57
|
+
/** The project's layout (`ProjectFile.layout`); Patter's defaults when absent. */
|
|
58
|
+
layout?: {
|
|
59
|
+
flow?: string;
|
|
60
|
+
strings?: string;
|
|
61
|
+
};
|
|
62
|
+
/** The project's default locale: the strings go there. */
|
|
63
|
+
locale: string;
|
|
64
|
+
/** File stems already taken in the flow folder, so the new one doesn't collide. */
|
|
65
|
+
takenStems: ReadonlySet<string>;
|
|
66
|
+
}
|
|
67
|
+
interface ScenePlan {
|
|
68
|
+
sceneId: string;
|
|
69
|
+
/** Project-relative paths and canonical content: the flow shard, then its strings. */
|
|
70
|
+
writes: {
|
|
71
|
+
path: string;
|
|
72
|
+
content: string;
|
|
73
|
+
}[];
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* Plan a new, empty Patter project for another tool to create beside its own (Storyletter's
|
|
77
|
+
* "Starter project with Patter"): the project file as Patter's own init writes it, named after
|
|
78
|
+
* the project, in one locale. Scenes are added with `planScene`. Returns the project file's path
|
|
79
|
+
* relative to the new project folder, and its canonical content.
|
|
80
|
+
*/
|
|
81
|
+
declare function planProject(opts: {
|
|
82
|
+
name: string;
|
|
83
|
+
locale?: string;
|
|
84
|
+
}): {
|
|
85
|
+
path: string;
|
|
86
|
+
content: string;
|
|
87
|
+
};
|
|
88
|
+
/** Plan a stub scene for a card. Pure: nothing is read or written. */
|
|
89
|
+
declare function planScene(target: ScenePlanTarget, scaffold: SceneScaffold): ScenePlan;
|
|
90
|
+
|
|
91
|
+
export { type ProjectInput, type ScenePlan, type ScenePlanTarget, type SceneScaffold, type StringifyOptions, type ValidationIssue, canonicalStringify, hash32, hash4, humanizeNodeRefs, planProject, planScene, slug, validateProject };
|
package/dist/index.d.ts
CHANGED
|
@@ -40,4 +40,52 @@ interface ProjectInput {
|
|
|
40
40
|
/** Validate a project's structural invariants. Returns an empty array when valid. */
|
|
41
41
|
declare function validateProject(input: ProjectInput): ValidationIssue[];
|
|
42
42
|
|
|
43
|
-
|
|
43
|
+
interface SceneScaffold {
|
|
44
|
+
/** The scene's name: the card's title. */
|
|
45
|
+
name: string;
|
|
46
|
+
/** The scene's address, pinned: the card's gameId, so the pairing never depends on the name. */
|
|
47
|
+
gameId: string;
|
|
48
|
+
/** The opening narration: the card's purpose, say. A prompt to write the scene when absent. */
|
|
49
|
+
opening?: string;
|
|
50
|
+
/** The card's outcomes: `gameId` labels an option, `title` is its words. */
|
|
51
|
+
outcomes: ReadonlyArray<{
|
|
52
|
+
gameId: string;
|
|
53
|
+
title?: string;
|
|
54
|
+
}>;
|
|
55
|
+
}
|
|
56
|
+
interface ScenePlanTarget {
|
|
57
|
+
/** The project's layout (`ProjectFile.layout`); Patter's defaults when absent. */
|
|
58
|
+
layout?: {
|
|
59
|
+
flow?: string;
|
|
60
|
+
strings?: string;
|
|
61
|
+
};
|
|
62
|
+
/** The project's default locale: the strings go there. */
|
|
63
|
+
locale: string;
|
|
64
|
+
/** File stems already taken in the flow folder, so the new one doesn't collide. */
|
|
65
|
+
takenStems: ReadonlySet<string>;
|
|
66
|
+
}
|
|
67
|
+
interface ScenePlan {
|
|
68
|
+
sceneId: string;
|
|
69
|
+
/** Project-relative paths and canonical content: the flow shard, then its strings. */
|
|
70
|
+
writes: {
|
|
71
|
+
path: string;
|
|
72
|
+
content: string;
|
|
73
|
+
}[];
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* Plan a new, empty Patter project for another tool to create beside its own (Storyletter's
|
|
77
|
+
* "Starter project with Patter"): the project file as Patter's own init writes it, named after
|
|
78
|
+
* the project, in one locale. Scenes are added with `planScene`. Returns the project file's path
|
|
79
|
+
* relative to the new project folder, and its canonical content.
|
|
80
|
+
*/
|
|
81
|
+
declare function planProject(opts: {
|
|
82
|
+
name: string;
|
|
83
|
+
locale?: string;
|
|
84
|
+
}): {
|
|
85
|
+
path: string;
|
|
86
|
+
content: string;
|
|
87
|
+
};
|
|
88
|
+
/** Plan a stub scene for a card. Pure: nothing is read or written. */
|
|
89
|
+
declare function planScene(target: ScenePlanTarget, scaffold: SceneScaffold): ScenePlan;
|
|
90
|
+
|
|
91
|
+
export { type ProjectInput, type ScenePlan, type ScenePlanTarget, type SceneScaffold, type StringifyOptions, type ValidationIssue, canonicalStringify, hash32, hash4, humanizeNodeRefs, planProject, planScene, slug, validateProject };
|
package/dist/index.js
CHANGED
|
@@ -436,6 +436,76 @@ function defaultMatchesType(value, decl) {
|
|
|
436
436
|
return typeof value === "string" && (decl.stages?.includes(value) ?? true);
|
|
437
437
|
}
|
|
438
438
|
}
|
|
439
|
+
|
|
440
|
+
// src/scene-scaffold.ts
|
|
441
|
+
var trimSlash = (p) => p.replace(/\/+$/, "");
|
|
442
|
+
function planProject(opts) {
|
|
443
|
+
const locale = opts.locale ?? "en";
|
|
444
|
+
const project = {
|
|
445
|
+
schema: "patter/project@0",
|
|
446
|
+
project: { id: newId("proj"), name: opts.name },
|
|
447
|
+
locales: { default: locale, all: [locale] },
|
|
448
|
+
voiced: true
|
|
449
|
+
};
|
|
450
|
+
return { path: `${slug(opts.name) || "project"}.patterproj`, content: canonicalStringify(project) };
|
|
451
|
+
}
|
|
452
|
+
function planScene(target, scaffold) {
|
|
453
|
+
const base = slug(scaffold.gameId) || slug(scaffold.name) || "scene";
|
|
454
|
+
let stem = base;
|
|
455
|
+
for (let n = 2; target.takenStems.has(stem); n++) stem = `${base}-${n}`;
|
|
456
|
+
const strings = {};
|
|
457
|
+
const say = (prefix, text) => {
|
|
458
|
+
const id = newId(prefix);
|
|
459
|
+
strings[id] = text;
|
|
460
|
+
return { id, kind: "text" };
|
|
461
|
+
};
|
|
462
|
+
const opening = {
|
|
463
|
+
id: newId("sn"),
|
|
464
|
+
type: "snippet",
|
|
465
|
+
beats: [say("T", scaffold.opening?.trim() || `Write the scene for "${scaffold.name}" here.`)]
|
|
466
|
+
};
|
|
467
|
+
const children = [opening];
|
|
468
|
+
if (scaffold.outcomes.length <= 1) {
|
|
469
|
+
opening.jump = { to: "END" };
|
|
470
|
+
} else {
|
|
471
|
+
children.push({
|
|
472
|
+
id: newId("g"),
|
|
473
|
+
type: "group",
|
|
474
|
+
selector: "choice",
|
|
475
|
+
children: scaffold.outcomes.map((o) => ({
|
|
476
|
+
id: newId("opt"),
|
|
477
|
+
type: "group",
|
|
478
|
+
prompt: say("L", o.title?.trim() || o.gameId),
|
|
479
|
+
gameData: { outcome: o.gameId },
|
|
480
|
+
children: [{
|
|
481
|
+
id: newId("sn"),
|
|
482
|
+
type: "snippet",
|
|
483
|
+
beats: [say("T", "What happens next.")],
|
|
484
|
+
jump: { to: "END" }
|
|
485
|
+
}]
|
|
486
|
+
}))
|
|
487
|
+
});
|
|
488
|
+
}
|
|
489
|
+
const sceneId = newId("scn");
|
|
490
|
+
const scene = {
|
|
491
|
+
id: sceneId,
|
|
492
|
+
type: "scene",
|
|
493
|
+
name: scaffold.name,
|
|
494
|
+
gameId: scaffold.gameId,
|
|
495
|
+
blocks: [{ id: newId("blk"), type: "block", name: "Main", children }]
|
|
496
|
+
};
|
|
497
|
+
const flow = { schema: "patter/flow@0", scene };
|
|
498
|
+
const locale = { schema: "patter/strings@0", scene: sceneId, locale: target.locale, default: true, strings };
|
|
499
|
+
const flowDir = trimSlash(target.layout?.flow ?? "scenes/");
|
|
500
|
+
const stringsDir = trimSlash(target.layout?.strings ?? "loc/");
|
|
501
|
+
return {
|
|
502
|
+
sceneId,
|
|
503
|
+
writes: [
|
|
504
|
+
{ path: `${flowDir}/${stem}.patterflow`, content: canonicalStringify(flow) },
|
|
505
|
+
{ path: `${stringsDir}/${target.locale}/${stem}.patterloc`, content: canonicalStringify(locale) }
|
|
506
|
+
]
|
|
507
|
+
};
|
|
508
|
+
}
|
|
439
509
|
export {
|
|
440
510
|
canonicalStringify,
|
|
441
511
|
effectiveGameId2 as effectiveGameId,
|
|
@@ -446,6 +516,8 @@ export {
|
|
|
446
516
|
isValidGameId2 as isValidGameId,
|
|
447
517
|
newId,
|
|
448
518
|
parseSource,
|
|
519
|
+
planProject,
|
|
520
|
+
planScene,
|
|
449
521
|
slug,
|
|
450
522
|
validateProject
|
|
451
523
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@patterkit/core",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.0",
|
|
4
4
|
"description": "Patter core: stable id generation, readable-handle computation, canonical (de)serialisation, and the structural validator.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
@@ -34,7 +34,7 @@
|
|
|
34
34
|
"build": "tsup src/index.ts --format esm,cjs --dts --clean"
|
|
35
35
|
},
|
|
36
36
|
"dependencies": {
|
|
37
|
-
"@patterkit/model": "0.
|
|
37
|
+
"@patterkit/model": "0.7.0",
|
|
38
38
|
"@wildwinter/toolkit": "^0.1.0",
|
|
39
39
|
"json5": "^2.2.3"
|
|
40
40
|
}
|