@projitect/blueprint 0.0.0-stage → 1.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/dist/add-sections.d.ts +87 -0
- package/dist/add-sections.d.ts.map +1 -0
- package/dist/add-sections.js +60 -0
- package/dist/add-sections.js.map +1 -0
- package/dist/constructors.d.ts +103 -0
- package/dist/constructors.d.ts.map +1 -0
- package/dist/constructors.js +88 -0
- package/dist/constructors.js.map +1 -0
- package/dist/detect.d.ts +19 -0
- package/dist/detect.d.ts.map +1 -0
- package/dist/detect.js +36 -0
- package/dist/detect.js.map +1 -0
- package/dist/directory.d.ts +17 -0
- package/dist/directory.d.ts.map +1 -0
- package/dist/directory.js +8 -0
- package/dist/directory.js.map +1 -0
- package/dist/index.d.ts +22 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +22 -0
- package/dist/index.js.map +1 -0
- package/dist/sections.d.ts +75 -0
- package/dist/sections.d.ts.map +1 -0
- package/dist/sections.js +85 -0
- package/dist/sections.js.map +1 -0
- package/dist/splice.d.ts +23 -0
- package/dist/splice.d.ts.map +1 -0
- package/dist/splice.js +78 -0
- package/dist/splice.js.map +1 -0
- package/package.json +41 -3
- package/src/add-sections.ts +140 -0
- package/src/constructors.ts +202 -0
- package/src/detect.ts +48 -0
- package/src/directory.ts +30 -0
- package/src/index.ts +21 -0
- package/src/sections.ts +99 -0
- package/src/splice.ts +99 -0
- package/README.md +0 -3
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Kapil Easwar
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
import { Effect } from "effect";
|
|
2
|
+
import { Prompt } from "effect/unstable/cli";
|
|
3
|
+
import type { Errors } from "@projitect/core";
|
|
4
|
+
/**
|
|
5
|
+
* The shape of the `"projitect"` field in a blueprint package's `package.json`. Defines how
|
|
6
|
+
* `pjt add <pkg>` should splice into the user's `.pjt.ts`.
|
|
7
|
+
*/
|
|
8
|
+
export interface ProjitectPackageMetadata {
|
|
9
|
+
/**
|
|
10
|
+
* `"blueprint"` for single-call packages (e.g. one default export). `"blueprint-set"` for
|
|
11
|
+
* packages that expose multiple sections (e.g. `gitignores.macOs()`, `gitignores.node()`).
|
|
12
|
+
*/
|
|
13
|
+
readonly type: "blueprint" | "blueprint-set";
|
|
14
|
+
/** The import statement to splice into `// pjt:imports`, e.g. `import { foo } from "foo"`. */
|
|
15
|
+
readonly import: string;
|
|
16
|
+
/** For `type: "blueprint"` only — the call template, e.g. `myBlueprint()`. */
|
|
17
|
+
readonly call?: string;
|
|
18
|
+
/** For `type: "blueprint-set"` only — substitute `{section}` with each chosen name. */
|
|
19
|
+
readonly callTemplate?: string;
|
|
20
|
+
/** For `type: "blueprint-set"` only — the list of available section names. */
|
|
21
|
+
readonly sections?: readonly string[];
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Strategy for picking which sections of a `blueprint-set` package to splice.
|
|
25
|
+
*
|
|
26
|
+
* - `"all"` — silent default; pick every section the package declares. Used when the caller
|
|
27
|
+
* wants the legacy "no --section means everything" behavior.
|
|
28
|
+
* - `{ kind: "explicit", sections }` — caller already knows. `--section macOs,node` lands here.
|
|
29
|
+
* - `{ kind: "ask", choose }` — interactive: defer to the supplied callback (typically
|
|
30
|
+
* `chooseSectionsInteractive`). The callback runs only when the installed package's metadata
|
|
31
|
+
* says `type: "blueprint-set"` and exposes sections.
|
|
32
|
+
*
|
|
33
|
+
* `R` parametrizes the callback's requirement channel so the caller can hand us an Effect
|
|
34
|
+
* that needs `Prompt.Environment` (FileSystem | Path | Terminal).
|
|
35
|
+
*/
|
|
36
|
+
export type SectionStrategy<R = never> = {
|
|
37
|
+
readonly _tag: "All";
|
|
38
|
+
} | {
|
|
39
|
+
readonly _tag: "Explicit";
|
|
40
|
+
readonly sections: readonly string[];
|
|
41
|
+
} | {
|
|
42
|
+
readonly _tag: "Ask";
|
|
43
|
+
readonly choose: (metadata: ProjitectPackageMetadata) => Effect.Effect<readonly string[], Errors.ProjitectError, R>;
|
|
44
|
+
};
|
|
45
|
+
/**
|
|
46
|
+
* What the user wants spliced from a package. Cancellation is its own case so it can never be
|
|
47
|
+
* mistaken for "all":
|
|
48
|
+
*
|
|
49
|
+
* - `All` — every declared section.
|
|
50
|
+
* - `Chosen` — exactly these sections (non-empty).
|
|
51
|
+
* - `Nothing` — the user picked no sections or quit the prompt; the host must not write.
|
|
52
|
+
*/
|
|
53
|
+
export type SectionSelection = {
|
|
54
|
+
readonly _tag: "All";
|
|
55
|
+
} | {
|
|
56
|
+
readonly _tag: "Chosen";
|
|
57
|
+
readonly sections: readonly string[];
|
|
58
|
+
} | {
|
|
59
|
+
readonly _tag: "Nothing";
|
|
60
|
+
};
|
|
61
|
+
/** Resolve which sections the user wants, per `strategy`. */
|
|
62
|
+
export declare const resolveSections: <R>(params: {
|
|
63
|
+
readonly metadata: ProjitectPackageMetadata;
|
|
64
|
+
readonly strategy: SectionStrategy<R>;
|
|
65
|
+
}) => Effect.Effect<SectionSelection, Errors.ProjitectError, R>;
|
|
66
|
+
/**
|
|
67
|
+
* Compute the import line and call lines to splice for the selection. A `Nothing` selection
|
|
68
|
+
* yields no call lines and no sections; hosts check `selection._tag` and skip the write.
|
|
69
|
+
*/
|
|
70
|
+
export declare const computeSplice: (params: {
|
|
71
|
+
readonly metadata: ProjitectPackageMetadata;
|
|
72
|
+
readonly selection: SectionSelection;
|
|
73
|
+
}) => {
|
|
74
|
+
readonly importLine: string;
|
|
75
|
+
readonly callLines: readonly string[];
|
|
76
|
+
readonly sectionsAdded: readonly string[];
|
|
77
|
+
};
|
|
78
|
+
/**
|
|
79
|
+
* Interactive section picker for a `type: "blueprint-set"` package. Ctrl-C yields an empty
|
|
80
|
+
* selection rather than crashing; `resolveSections` maps an empty `Ask` result to
|
|
81
|
+
* `Nothing`, so quitting never splices anything.
|
|
82
|
+
*
|
|
83
|
+
* Returns an empty selection if no sections are declared (defensive default — shouldn't happen
|
|
84
|
+
* for well-formed metadata, but we don't want to crash on a malformed package).
|
|
85
|
+
*/
|
|
86
|
+
export declare const chooseSectionsInteractive: (metadata: ProjitectPackageMetadata) => Effect.Effect<readonly string[], never, Prompt.Environment>;
|
|
87
|
+
//# sourceMappingURL=add-sections.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"add-sections.d.ts","sourceRoot":"","sources":["../src/add-sections.ts"],"names":[],"mappings":"AAAA,OAAO,EAAS,MAAM,EAAS,MAAM,QAAQ,CAAA;AAC7C,OAAO,EAAE,MAAM,EAAE,MAAM,qBAAqB,CAAA;AAC5C,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,iBAAiB,CAAA;AAE7C;;;GAGG;AACH,MAAM,WAAW,wBAAwB;IACvC;;;OAGG;IACH,QAAQ,CAAC,IAAI,EAAE,WAAW,GAAG,eAAe,CAAA;IAC5C,8FAA8F;IAC9F,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;IACvB,8EAA8E;IAC9E,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAA;IACtB,uFAAuF;IACvF,QAAQ,CAAC,YAAY,CAAC,EAAE,MAAM,CAAA;IAC9B,8EAA8E;IAC9E,QAAQ,CAAC,QAAQ,CAAC,EAAE,SAAS,MAAM,EAAE,CAAA;CACtC;AAED;;;;;;;;;;;;GAYG;AACH,MAAM,MAAM,eAAe,CAAC,CAAC,GAAG,KAAK,IACjC;IAAE,QAAQ,CAAC,IAAI,EAAE,KAAK,CAAA;CAAE,GACxB;IAAE,QAAQ,CAAC,IAAI,EAAE,UAAU,CAAC;IAAC,QAAQ,CAAC,QAAQ,EAAE,SAAS,MAAM,EAAE,CAAA;CAAE,GACnE;IACE,QAAQ,CAAC,IAAI,EAAE,KAAK,CAAA;IACpB,QAAQ,CAAC,MAAM,EAAE,CACf,QAAQ,EAAE,wBAAwB,KAC/B,MAAM,CAAC,MAAM,CAAC,SAAS,MAAM,EAAE,EAAE,MAAM,CAAC,cAAc,EAAE,CAAC,CAAC,CAAA;CAChE,CAAA;AAEL;;;;;;;GAOG;AACH,MAAM,MAAM,gBAAgB,GACxB;IAAE,QAAQ,CAAC,IAAI,EAAE,KAAK,CAAA;CAAE,GACxB;IAAE,QAAQ,CAAC,IAAI,EAAE,QAAQ,CAAC;IAAC,QAAQ,CAAC,QAAQ,EAAE,SAAS,MAAM,EAAE,CAAA;CAAE,GACjE;IAAE,QAAQ,CAAC,IAAI,EAAE,SAAS,CAAA;CAAE,CAAA;AAKhC,6DAA6D;AAC7D,eAAO,MAAM,eAAe,GAAI,CAAC,EAAE,QAAQ;IACzC,QAAQ,CAAC,QAAQ,EAAE,wBAAwB,CAAA;IAC3C,QAAQ,CAAC,QAAQ,EAAE,eAAe,CAAC,CAAC,CAAC,CAAA;CACtC,KAAG,MAAM,CAAC,MAAM,CAAC,gBAAgB,EAAE,MAAM,CAAC,cAAc,EAAE,CAAC,CAa3D,CAAA;AAED;;;GAGG;AACH,eAAO,MAAM,aAAa,GAAI,QAAQ;IACpC,QAAQ,CAAC,QAAQ,EAAE,wBAAwB,CAAA;IAC3C,QAAQ,CAAC,SAAS,EAAE,gBAAgB,CAAA;CACrC,KAAG;IACF,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAA;IAC3B,QAAQ,CAAC,SAAS,EAAE,SAAS,MAAM,EAAE,CAAA;IACrC,QAAQ,CAAC,aAAa,EAAE,SAAS,MAAM,EAAE,CAAA;CA0B1C,CAAA;AAED;;;;;;;GAOG;AACH,eAAO,MAAM,yBAAyB,GACpC,UAAU,wBAAwB,KACjC,MAAM,CAAC,MAAM,CAAC,SAAS,MAAM,EAAE,EAAE,KAAK,EAAE,MAAM,CAAC,WAAW,CAS5D,CAAA"}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import { Array, Effect, Match } from "effect";
|
|
2
|
+
import { Prompt } from "effect/unstable/cli";
|
|
3
|
+
const chosenOr = (sections, whenEmpty) => Array.isReadonlyArrayNonEmpty(sections) ? { _tag: "Chosen", sections } : whenEmpty;
|
|
4
|
+
/** Resolve which sections the user wants, per `strategy`. */
|
|
5
|
+
export const resolveSections = (params) => {
|
|
6
|
+
const { metadata, strategy } = params;
|
|
7
|
+
// Section strategy only matters for blueprint-sets. For `type: "blueprint"` the selection is
|
|
8
|
+
// ignored — `computeSplice` emits a single non-templated call line.
|
|
9
|
+
if (metadata.type === "blueprint") {
|
|
10
|
+
return Effect.succeed({ _tag: "All" });
|
|
11
|
+
}
|
|
12
|
+
return Match.valueTags(strategy, {
|
|
13
|
+
All: () => Effect.succeed({ _tag: "All" }),
|
|
14
|
+
Explicit: (explicit) => Effect.succeed(chosenOr(explicit.sections, { _tag: "All" })),
|
|
15
|
+
Ask: (ask) => Effect.map(ask.choose(metadata), (picked) => chosenOr(picked, { _tag: "Nothing" })),
|
|
16
|
+
});
|
|
17
|
+
};
|
|
18
|
+
/**
|
|
19
|
+
* Compute the import line and call lines to splice for the selection. A `Nothing` selection
|
|
20
|
+
* yields no call lines and no sections; hosts check `selection._tag` and skip the write.
|
|
21
|
+
*/
|
|
22
|
+
export const computeSplice = (params) => {
|
|
23
|
+
const { metadata, selection } = params;
|
|
24
|
+
if (metadata.type === "blueprint") {
|
|
25
|
+
const call = metadata.call ?? "/* TODO: replace with the blueprint call from the package's README */";
|
|
26
|
+
return {
|
|
27
|
+
importLine: metadata.import,
|
|
28
|
+
callLines: [`${call},`],
|
|
29
|
+
sectionsAdded: [],
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
// Blueprint-set
|
|
33
|
+
const allSections = metadata.sections ?? [];
|
|
34
|
+
const chosen = Match.value(selection).pipe(Match.tag("All", () => allSections), Match.tag("Chosen", (picked) => picked.sections.filter((s) => allSections.includes(s))), Match.tag("Nothing", () => []), Match.exhaustive);
|
|
35
|
+
const template = metadata.callTemplate ?? "{section}()";
|
|
36
|
+
return {
|
|
37
|
+
importLine: metadata.import,
|
|
38
|
+
callLines: chosen.map((s) => `${template.replace("{section}", s)},`),
|
|
39
|
+
sectionsAdded: chosen,
|
|
40
|
+
};
|
|
41
|
+
};
|
|
42
|
+
/**
|
|
43
|
+
* Interactive section picker for a `type: "blueprint-set"` package. Ctrl-C yields an empty
|
|
44
|
+
* selection rather than crashing; `resolveSections` maps an empty `Ask` result to
|
|
45
|
+
* `Nothing`, so quitting never splices anything.
|
|
46
|
+
*
|
|
47
|
+
* Returns an empty selection if no sections are declared (defensive default — shouldn't happen
|
|
48
|
+
* for well-formed metadata, but we don't want to crash on a malformed package).
|
|
49
|
+
*/
|
|
50
|
+
export const chooseSectionsInteractive = (metadata) => {
|
|
51
|
+
const sections = metadata.sections ?? [];
|
|
52
|
+
if (!Array.isReadonlyArrayNonEmpty(sections)) {
|
|
53
|
+
return Effect.succeed([]);
|
|
54
|
+
}
|
|
55
|
+
return Prompt.multiSelect({
|
|
56
|
+
message: "Pick sections to add (space to toggle, enter to confirm):",
|
|
57
|
+
choices: sections.map((name) => ({ title: name, value: name })),
|
|
58
|
+
}).pipe(Effect.catchTag("QuitError", () => Effect.succeed([])));
|
|
59
|
+
};
|
|
60
|
+
//# sourceMappingURL=add-sections.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"add-sections.js","sourceRoot":"","sources":["../src/add-sections.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
import { Effect } from "effect";
|
|
2
|
+
import type { Blueprint, Permission, Errors, BlueprintFileSystem } from "@projitect/core";
|
|
3
|
+
import { ChangeSet } from "@projitect/core";
|
|
4
|
+
/**
|
|
5
|
+
* Spec for a region-mode blueprint: replace or insert the marked section in a shared text file.
|
|
6
|
+
* Multiple blueprints can coexist in the same file as long as they use different `ownerId`s.
|
|
7
|
+
*/
|
|
8
|
+
export interface RegionFileSpec {
|
|
9
|
+
readonly id: string;
|
|
10
|
+
readonly version: string;
|
|
11
|
+
readonly description?: string;
|
|
12
|
+
readonly path: string;
|
|
13
|
+
readonly commentPrefix?: string;
|
|
14
|
+
/**
|
|
15
|
+
* Optional closing delimiter for prefix/suffix-pair comment styles. Set to `" -->"` for
|
|
16
|
+
* HTML/MDX. Leave undefined (default) for single-prefix styles like `#` and `//`.
|
|
17
|
+
*/
|
|
18
|
+
readonly commentSuffix?: string;
|
|
19
|
+
readonly content: string;
|
|
20
|
+
readonly extraPermissions?: readonly Permission.Permission[];
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Create a region-mode blueprint. The blueprint's `id` doubles as the region's `ownerId`.
|
|
24
|
+
* `commentPrefix` defaults to `#` (suitable for `.gitignore` / YAML / shell).
|
|
25
|
+
*
|
|
26
|
+
* For HTML / MDX / XML files, prefer the `markdownSection` helper — it sets the right
|
|
27
|
+
* prefix and suffix pair for you. For ignore-style files, prefer `ignoreSection` — same
|
|
28
|
+
* shape with a name that documents its intent.
|
|
29
|
+
*/
|
|
30
|
+
export declare const regionFile: (spec: RegionFileSpec) => Blueprint.Blueprint;
|
|
31
|
+
/**
|
|
32
|
+
* Spec for a merge-mode blueprint: deep-merge a partial value into a structured (JSON) file.
|
|
33
|
+
* The `ownedKeys` list declares which dotted-path keys this blueprint claims — two blueprints
|
|
34
|
+
* claiming the same key is a `pjt.plan.conflict-merge` error.
|
|
35
|
+
*/
|
|
36
|
+
export interface JsonMergeSpec {
|
|
37
|
+
readonly id: string;
|
|
38
|
+
readonly version: string;
|
|
39
|
+
readonly description?: string;
|
|
40
|
+
readonly path: string;
|
|
41
|
+
readonly ownedKeys: readonly string[];
|
|
42
|
+
readonly value: unknown;
|
|
43
|
+
readonly extraPermissions?: readonly Permission.Permission[];
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Create a merge-mode blueprint for a JSON file (typically `package.json` / `tsconfig.json`).
|
|
47
|
+
*/
|
|
48
|
+
export declare const jsonMerge: (spec: JsonMergeSpec) => Blueprint.Blueprint;
|
|
49
|
+
/**
|
|
50
|
+
* Spec for an owned-mode blueprint: this blueprint owns the file's entire content. Any other
|
|
51
|
+
* blueprint touching the same path is a `pjt.plan.conflict-owned` error.
|
|
52
|
+
*/
|
|
53
|
+
export interface OwnFileSpec {
|
|
54
|
+
readonly id: string;
|
|
55
|
+
readonly version: string;
|
|
56
|
+
readonly description?: string;
|
|
57
|
+
readonly path: string;
|
|
58
|
+
readonly content: string;
|
|
59
|
+
/** Directory the file's owner manages; empty directories are pruned up to it on removal. */
|
|
60
|
+
readonly ownedDir?: string;
|
|
61
|
+
readonly extraPermissions?: readonly Permission.Permission[];
|
|
62
|
+
}
|
|
63
|
+
export declare const ownFile: (spec: OwnFileSpec) => Blueprint.Blueprint;
|
|
64
|
+
/**
|
|
65
|
+
* Spec for a seed-mode blueprint: write the file at first build, never enforce it again. Useful
|
|
66
|
+
* for templates the project maintainer is expected to customize (e.g. README, initial `.pjt.ts`).
|
|
67
|
+
*/
|
|
68
|
+
export interface SeedFileSpec {
|
|
69
|
+
readonly id: string;
|
|
70
|
+
readonly version: string;
|
|
71
|
+
readonly description?: string;
|
|
72
|
+
readonly path: string;
|
|
73
|
+
readonly content: string;
|
|
74
|
+
readonly extraPermissions?: readonly Permission.Permission[];
|
|
75
|
+
}
|
|
76
|
+
export declare const seedFile: (spec: SeedFileSpec) => Blueprint.Blueprint;
|
|
77
|
+
/**
|
|
78
|
+
* Spec for a post-apply command: after every file operation has succeeded, `pjt build` and
|
|
79
|
+
* `pjt remodel` run `fix` from the project root. `check` is the command that reports whether the
|
|
80
|
+
* fix is needed. The blueprint declares an `exec` permission for each of the two command lines.
|
|
81
|
+
*/
|
|
82
|
+
export interface ExecSpec {
|
|
83
|
+
readonly id: string;
|
|
84
|
+
readonly version: string;
|
|
85
|
+
readonly description?: string;
|
|
86
|
+
readonly check: string;
|
|
87
|
+
readonly fix: string;
|
|
88
|
+
readonly extraPermissions?: readonly Permission.Permission[];
|
|
89
|
+
}
|
|
90
|
+
export declare const exec: (spec: ExecSpec) => Blueprint.Blueprint;
|
|
91
|
+
/**
|
|
92
|
+
* Build a blueprint from a user-supplied plan Effect. Use this when your plan needs to read
|
|
93
|
+
* existing files, branch on detected state, or compose multiple operations.
|
|
94
|
+
*/
|
|
95
|
+
export interface ComputedSpec {
|
|
96
|
+
readonly id: string;
|
|
97
|
+
readonly version: string;
|
|
98
|
+
readonly description?: string;
|
|
99
|
+
readonly permissions: readonly Permission.Permission[];
|
|
100
|
+
readonly plan: Effect.Effect<ChangeSet.ChangeSet, Errors.BlueprintError, BlueprintFileSystem>;
|
|
101
|
+
}
|
|
102
|
+
export declare const computed: (spec: ComputedSpec) => Blueprint.Blueprint;
|
|
103
|
+
//# sourceMappingURL=constructors.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"constructors.d.ts","sourceRoot":"","sources":["../src/constructors.ts"],"names":[],"mappings":"AAAA,OAAO,EAAS,MAAM,EAAE,MAAM,QAAQ,CAAA;AAEtC,OAAO,KAAK,EAAE,SAAS,EAAE,UAAU,EAAE,MAAM,EAAE,mBAAmB,EAAE,MAAM,iBAAiB,CAAA;AACzF,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAA;AAE3C;;;GAGG;AACH,MAAM,WAAW,cAAc;IAC7B,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAA;IACnB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAA;IACxB,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,CAAA;IAC7B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;IACrB,QAAQ,CAAC,aAAa,CAAC,EAAE,MAAM,CAAA;IAC/B;;;OAGG;IACH,QAAQ,CAAC,aAAa,CAAC,EAAE,MAAM,CAAA;IAC/B,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAA;IACxB,QAAQ,CAAC,gBAAgB,CAAC,EAAE,SAAS,UAAU,CAAC,UAAU,EAAE,CAAA;CAC7D;AAED;;;;;;;GAOG;AACH,eAAO,MAAM,UAAU,GAAI,MAAM,cAAc,KAAG,SAAS,CAAC,SAoB1D,CAAA;AAEF;;;;GAIG;AACH,MAAM,WAAW,aAAa;IAC5B,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAA;IACnB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAA;IACxB,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,CAAA;IAC7B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;IACrB,QAAQ,CAAC,SAAS,EAAE,SAAS,MAAM,EAAE,CAAA;IACrC,QAAQ,CAAC,KAAK,EAAE,OAAO,CAAA;IACvB,QAAQ,CAAC,gBAAgB,CAAC,EAAE,SAAS,UAAU,CAAC,UAAU,EAAE,CAAA;CAC7D;AAED;;GAEG;AACH,eAAO,MAAM,SAAS,GAAI,MAAM,aAAa,KAAG,SAAS,CAAC,SAmBxD,CAAA;AAEF;;;GAGG;AACH,MAAM,WAAW,WAAW;IAC1B,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAA;IACnB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAA;IACxB,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,CAAA;IAC7B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;IACrB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAA;IACxB,4FAA4F;IAC5F,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAA;IAC1B,QAAQ,CAAC,gBAAgB,CAAC,EAAE,SAAS,UAAU,CAAC,UAAU,EAAE,CAAA;CAC7D;AAED,eAAO,MAAM,OAAO,GAAI,MAAM,WAAW,KAAG,SAAS,CAAC,SAepD,CAAA;AAEF;;;GAGG;AACH,MAAM,WAAW,YAAY;IAC3B,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAA;IACnB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAA;IACxB,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,CAAA;IAC7B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;IACrB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAA;IACxB,QAAQ,CAAC,gBAAgB,CAAC,EAAE,SAAS,UAAU,CAAC,UAAU,EAAE,CAAA;CAC7D;AAED,eAAO,MAAM,QAAQ,GAAI,MAAM,YAAY,KAAG,SAAS,CAAC,SActD,CAAA;AAEF;;;;GAIG;AACH,MAAM,WAAW,QAAQ;IACvB,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAA;IACnB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAA;IACxB,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,CAAA;IAC7B,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAA;IACtB,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAA;IACpB,QAAQ,CAAC,gBAAgB,CAAC,EAAE,SAAS,UAAU,CAAC,UAAU,EAAE,CAAA;CAC7D;AAED,eAAO,MAAM,IAAI,GAAI,MAAM,QAAQ,KAAG,SAAS,CAAC,SAa9C,CAAA;AAEF;;;GAGG;AACH,MAAM,WAAW,YAAY;IAC3B,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAA;IACnB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAA;IACxB,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,CAAA;IAC7B,QAAQ,CAAC,WAAW,EAAE,SAAS,UAAU,CAAC,UAAU,EAAE,CAAA;IACtD,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC,MAAM,CAAC,SAAS,CAAC,SAAS,EAAE,MAAM,CAAC,cAAc,EAAE,mBAAmB,CAAC,CAAA;CAC9F;AAED,eAAO,MAAM,QAAQ,GAAI,MAAM,YAAY,KAAG,SAAS,CAAC,SAMtD,CAAA"}
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
import { Array, Effect } from "effect";
|
|
2
|
+
import { StructX } from "@nunofyobiz/effect-extras";
|
|
3
|
+
import { ChangeSet } from "@projitect/core";
|
|
4
|
+
/**
|
|
5
|
+
* Create a region-mode blueprint. The blueprint's `id` doubles as the region's `ownerId`.
|
|
6
|
+
* `commentPrefix` defaults to `#` (suitable for `.gitignore` / YAML / shell).
|
|
7
|
+
*
|
|
8
|
+
* For HTML / MDX / XML files, prefer the `markdownSection` helper — it sets the right
|
|
9
|
+
* prefix and suffix pair for you. For ignore-style files, prefer `ignoreSection` — same
|
|
10
|
+
* shape with a name that documents its intent.
|
|
11
|
+
*/
|
|
12
|
+
export const regionFile = (spec) => ({
|
|
13
|
+
id: spec.id,
|
|
14
|
+
version: spec.version,
|
|
15
|
+
...StructX.defined("description", spec.description),
|
|
16
|
+
permissions: [
|
|
17
|
+
{ kind: "write", glob: spec.path },
|
|
18
|
+
{ kind: "read", glob: spec.path },
|
|
19
|
+
...(spec.extraPermissions ?? []),
|
|
20
|
+
],
|
|
21
|
+
plan: Effect.succeed(ChangeSet.of(ChangeSet.RegionOp.make({
|
|
22
|
+
ownerId: spec.id,
|
|
23
|
+
path: spec.path,
|
|
24
|
+
commentPrefix: spec.commentPrefix ?? "#",
|
|
25
|
+
...StructX.defined("commentSuffix", spec.commentSuffix),
|
|
26
|
+
content: spec.content,
|
|
27
|
+
}))),
|
|
28
|
+
});
|
|
29
|
+
/**
|
|
30
|
+
* Create a merge-mode blueprint for a JSON file (typically `package.json` / `tsconfig.json`).
|
|
31
|
+
*/
|
|
32
|
+
export const jsonMerge = (spec) => ({
|
|
33
|
+
id: spec.id,
|
|
34
|
+
version: spec.version,
|
|
35
|
+
...StructX.defined("description", spec.description),
|
|
36
|
+
permissions: [
|
|
37
|
+
{ kind: "write", glob: spec.path },
|
|
38
|
+
{ kind: "read", glob: spec.path },
|
|
39
|
+
...(spec.extraPermissions ?? []),
|
|
40
|
+
],
|
|
41
|
+
plan: Effect.succeed(ChangeSet.of(ChangeSet.MergeOp.make({
|
|
42
|
+
ownerId: spec.id,
|
|
43
|
+
path: spec.path,
|
|
44
|
+
ownedKeys: spec.ownedKeys,
|
|
45
|
+
value: spec.value,
|
|
46
|
+
}))),
|
|
47
|
+
});
|
|
48
|
+
export const ownFile = (spec) => ({
|
|
49
|
+
id: spec.id,
|
|
50
|
+
version: spec.version,
|
|
51
|
+
...StructX.defined("description", spec.description),
|
|
52
|
+
permissions: [{ kind: "write", glob: spec.path }, ...(spec.extraPermissions ?? [])],
|
|
53
|
+
plan: Effect.succeed(ChangeSet.of(ChangeSet.OwnedOp.make({
|
|
54
|
+
ownerId: spec.id,
|
|
55
|
+
path: spec.path,
|
|
56
|
+
content: spec.content,
|
|
57
|
+
...StructX.defined("ownedDir", spec.ownedDir),
|
|
58
|
+
}))),
|
|
59
|
+
});
|
|
60
|
+
export const seedFile = (spec) => ({
|
|
61
|
+
id: spec.id,
|
|
62
|
+
version: spec.version,
|
|
63
|
+
...StructX.defined("description", spec.description),
|
|
64
|
+
permissions: [{ kind: "write", glob: spec.path }, ...(spec.extraPermissions ?? [])],
|
|
65
|
+
plan: Effect.succeed(ChangeSet.of(ChangeSet.SeedOp.make({
|
|
66
|
+
ownerId: spec.id,
|
|
67
|
+
path: spec.path,
|
|
68
|
+
content: spec.content,
|
|
69
|
+
}))),
|
|
70
|
+
});
|
|
71
|
+
export const exec = (spec) => ({
|
|
72
|
+
id: spec.id,
|
|
73
|
+
version: spec.version,
|
|
74
|
+
...StructX.defined("description", spec.description),
|
|
75
|
+
permissions: [
|
|
76
|
+
...Array.dedupe([spec.fix, spec.check]).map((command) => ({ kind: "exec", command })),
|
|
77
|
+
...(spec.extraPermissions ?? []),
|
|
78
|
+
],
|
|
79
|
+
plan: Effect.succeed(ChangeSet.of(ChangeSet.ExecOp.make({ ownerId: spec.id, command: spec.fix, check: spec.check }))),
|
|
80
|
+
});
|
|
81
|
+
export const computed = (spec) => ({
|
|
82
|
+
id: spec.id,
|
|
83
|
+
version: spec.version,
|
|
84
|
+
...StructX.defined("description", spec.description),
|
|
85
|
+
permissions: spec.permissions,
|
|
86
|
+
plan: spec.plan,
|
|
87
|
+
});
|
|
88
|
+
//# sourceMappingURL=constructors.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"constructors.js","sourceRoot":"","sources":["../src/constructors.ts"],"names":[],"mappings":"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"}
|
package/dist/detect.d.ts
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { Effect } from "effect";
|
|
2
|
+
import { BlueprintFileSystem } from "@projitect/core";
|
|
3
|
+
import type { Errors } from "@projitect/core";
|
|
4
|
+
export type PackageManager = "pnpm" | "npm" | "yarn" | "bun";
|
|
5
|
+
/**
|
|
6
|
+
* Inspect lockfiles to determine which package manager the project uses. Reads (in order):
|
|
7
|
+
* `pnpm-lock.yaml`, `bun.lockb`, `yarn.lock`, `package-lock.json`. Falls back to `npm` if none
|
|
8
|
+
* are present.
|
|
9
|
+
*
|
|
10
|
+
* Returns the detected manager; the blueprint must declare `read:` permission on the relevant
|
|
11
|
+
* lockfile path globs (e.g. `pnpm-lock.yaml`).
|
|
12
|
+
*/
|
|
13
|
+
export declare const detectPackageManager: Effect.Effect<PackageManager, Errors.FsPermissionDenied | Errors.FsReadFailed, BlueprintFileSystem>;
|
|
14
|
+
/**
|
|
15
|
+
* Read and parse `package.json` from the project root. Returns the parsed object as `unknown` —
|
|
16
|
+
* blueprints should decode it with a `Schema` if they need typed access to fields.
|
|
17
|
+
*/
|
|
18
|
+
export declare const readPackageJson: Effect.Effect<unknown, Errors.FsReadFailed | Errors.FsPermissionDenied, BlueprintFileSystem>;
|
|
19
|
+
//# sourceMappingURL=detect.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"detect.d.ts","sourceRoot":"","sources":["../src/detect.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAA;AAC/B,OAAO,EAAE,mBAAmB,EAAE,MAAM,iBAAiB,CAAA;AACrD,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,iBAAiB,CAAA;AAE7C,MAAM,MAAM,cAAc,GAAG,MAAM,GAAG,KAAK,GAAG,MAAM,GAAG,KAAK,CAAA;AAE5D;;;;;;;GAOG;AACH,eAAO,MAAM,oBAAoB,EAAE,MAAM,CAAC,MAAM,CAC9C,cAAc,EACd,MAAM,CAAC,kBAAkB,GAAG,MAAM,CAAC,YAAY,EAC/C,mBAAmB,CAgBnB,CAAA;AAEF;;;GAGG;AACH,eAAO,MAAM,eAAe,EAAE,MAAM,CAAC,MAAM,CACzC,OAAO,EACP,MAAM,CAAC,YAAY,GAAG,MAAM,CAAC,kBAAkB,EAC/C,mBAAmB,CAKnB,CAAA"}
|
package/dist/detect.js
ADDED
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { Effect } from "effect";
|
|
2
|
+
import { BlueprintFileSystem } from "@projitect/core";
|
|
3
|
+
/**
|
|
4
|
+
* Inspect lockfiles to determine which package manager the project uses. Reads (in order):
|
|
5
|
+
* `pnpm-lock.yaml`, `bun.lockb`, `yarn.lock`, `package-lock.json`. Falls back to `npm` if none
|
|
6
|
+
* are present.
|
|
7
|
+
*
|
|
8
|
+
* Returns the detected manager; the blueprint must declare `read:` permission on the relevant
|
|
9
|
+
* lockfile path globs (e.g. `pnpm-lock.yaml`).
|
|
10
|
+
*/
|
|
11
|
+
export const detectPackageManager = Effect.gen(function* () {
|
|
12
|
+
const fs = yield* BlueprintFileSystem;
|
|
13
|
+
if (yield* fs.exists("pnpm-lock.yaml")) {
|
|
14
|
+
return "pnpm";
|
|
15
|
+
}
|
|
16
|
+
if (yield* fs.exists("bun.lockb")) {
|
|
17
|
+
return "bun";
|
|
18
|
+
}
|
|
19
|
+
if (yield* fs.exists("yarn.lock")) {
|
|
20
|
+
return "yarn";
|
|
21
|
+
}
|
|
22
|
+
if (yield* fs.exists("package-lock.json")) {
|
|
23
|
+
return "npm";
|
|
24
|
+
}
|
|
25
|
+
return "npm";
|
|
26
|
+
});
|
|
27
|
+
/**
|
|
28
|
+
* Read and parse `package.json` from the project root. Returns the parsed object as `unknown` —
|
|
29
|
+
* blueprints should decode it with a `Schema` if they need typed access to fields.
|
|
30
|
+
*/
|
|
31
|
+
export const readPackageJson = Effect.gen(function* () {
|
|
32
|
+
const fs = yield* BlueprintFileSystem;
|
|
33
|
+
const raw = yield* fs.readFile("package.json");
|
|
34
|
+
return JSON.parse(raw);
|
|
35
|
+
});
|
|
36
|
+
//# sourceMappingURL=detect.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"detect.js","sourceRoot":"","sources":["../src/detect.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAA;AAC/B,OAAO,EAAE,mBAAmB,EAAE,MAAM,iBAAiB,CAAA;AAKrD;;;;;;;GAOG;AACH,MAAM,CAAC,MAAM,oBAAoB,GAI7B,MAAM,CAAC,GAAG,CAAC,QAAQ,CAAC;IACtB,MAAM,EAAE,GAAG,KAAK,CAAC,CAAC,mBAAmB,CAAA;IACrC,IAAI,KAAK,CAAC,CAAC,EAAE,CAAC,MAAM,CAAC,gBAAgB,CAAC,EAAE,CAAC;QACvC,OAAO,MAAe,CAAA;IACxB,CAAC;IACD,IAAI,KAAK,CAAC,CAAC,EAAE,CAAC,MAAM,CAAC,WAAW,CAAC,EAAE,CAAC;QAClC,OAAO,KAAc,CAAA;IACvB,CAAC;IACD,IAAI,KAAK,CAAC,CAAC,EAAE,CAAC,MAAM,CAAC,WAAW,CAAC,EAAE,CAAC;QAClC,OAAO,MAAe,CAAA;IACxB,CAAC;IACD,IAAI,KAAK,CAAC,CAAC,EAAE,CAAC,MAAM,CAAC,mBAAmB,CAAC,EAAE,CAAC;QAC1C,OAAO,KAAc,CAAA;IACvB,CAAC;IACD,OAAO,KAAc,CAAA;AACvB,CAAC,CAAC,CAAA;AAEF;;;GAGG;AACH,MAAM,CAAC,MAAM,eAAe,GAIxB,MAAM,CAAC,GAAG,CAAC,QAAQ,CAAC;IACtB,MAAM,EAAE,GAAG,KAAK,CAAC,CAAC,mBAAmB,CAAA;IACrC,MAAM,GAAG,GAAG,KAAK,CAAC,CAAC,EAAE,CAAC,QAAQ,CAAC,cAAc,CAAC,CAAA;IAC9C,OAAO,IAAI,CAAC,KAAK,CAAC,GAAG,CAAY,CAAA;AACnC,CAAC,CAAC,CAAA"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { Blueprint } from "@projitect/core";
|
|
2
|
+
/**
|
|
3
|
+
* Scope children to a subdirectory. Inside a `directory(name, [...])` group, every child
|
|
4
|
+
* blueprint's `path` is reinterpreted relative to `name/`, and write permissions outside the
|
|
5
|
+
* subtree are stripped from the children's declared `Permission`s.
|
|
6
|
+
*
|
|
7
|
+
* Implementation note: `directory` returns a `DirectoryBlueprint` — a tagged variant that the
|
|
8
|
+
* planner unpacks. Authors should treat the return value as opaque.
|
|
9
|
+
*/
|
|
10
|
+
export interface DirectoryBlueprint {
|
|
11
|
+
readonly _tag: "Directory";
|
|
12
|
+
readonly name: string;
|
|
13
|
+
readonly children: readonly (Blueprint.Blueprint | DirectoryBlueprint)[];
|
|
14
|
+
}
|
|
15
|
+
export declare const directory: (name: string, children: readonly (Blueprint.Blueprint | DirectoryBlueprint)[]) => DirectoryBlueprint;
|
|
16
|
+
export declare const isDirectoryBlueprint: (v: Blueprint.Blueprint | DirectoryBlueprint) => v is DirectoryBlueprint;
|
|
17
|
+
//# sourceMappingURL=directory.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"directory.d.ts","sourceRoot":"","sources":["../src/directory.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAA;AAEhD;;;;;;;GAOG;AACH,MAAM,WAAW,kBAAkB;IACjC,QAAQ,CAAC,IAAI,EAAE,WAAW,CAAA;IAC1B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;IACrB,QAAQ,CAAC,QAAQ,EAAE,SAAS,CAAC,SAAS,CAAC,SAAS,GAAG,kBAAkB,CAAC,EAAE,CAAA;CACzE;AAED,eAAO,MAAM,SAAS,GACpB,MAAM,MAAM,EACZ,UAAU,SAAS,CAAC,SAAS,CAAC,SAAS,GAAG,kBAAkB,CAAC,EAAE,KAC9D,kBAID,CAAA;AAEF,eAAO,MAAM,oBAAoB,GAC/B,GAAG,SAAS,CAAC,SAAS,GAAG,kBAAkB,KAE1C,CAAC,IAAI,kBAAsD,CAAA"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"directory.js","sourceRoot":"","sources":["../src/directory.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,QAAQ,CAAA;AAiBlC,MAAM,CAAC,MAAM,SAAS,GAAG,CACvB,IAAY,EACZ,QAA+D,EAC3C,EAAE,CAAC,CAAC;IACxB,IAAI,EAAE,WAAW;IACjB,IAAI;IACJ,QAAQ;CACT,CAAC,CAAA;AAEF,MAAM,CAAC,MAAM,oBAAoB,GAAG,CAClC,CAA2C,EAElB,EAAE,CAAC,SAAS,CAAC,WAAW,CAAC,CAAC,EAAE,MAAM,CAAC,CAAA"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @projitect/blueprint
|
|
3
|
+
*
|
|
4
|
+
* Authoring SDK for blueprint packages. Blueprint authors compose these primitives — the
|
|
5
|
+
* `BlueprintFileSystem` service for FS access, the four ownership-mode constructors
|
|
6
|
+
* (`regionFile` / `jsonMerge` / `ownFile` / `seedFile`), the post-apply `exec` constructor, the section helpers
|
|
7
|
+
* (`markdownSection`, `ignoreSection`), the `directory` scope transform, and detectors for
|
|
8
|
+
* common project introspection.
|
|
9
|
+
*
|
|
10
|
+
* Authors use Effect's own control-flow combinators (`Effect.gen`, `Effect.all`, `Effect.if`,
|
|
11
|
+
* `Effect.when`, `Effect.unless`, `Effect.forEach`) for sequencing and conditionals — we do
|
|
12
|
+
* not ship duplicates.
|
|
13
|
+
*/
|
|
14
|
+
export * from "./constructors.js";
|
|
15
|
+
export * from "./sections.js";
|
|
16
|
+
export * from "./directory.js";
|
|
17
|
+
export * from "./detect.js";
|
|
18
|
+
export * from "./splice.js";
|
|
19
|
+
export * from "./add-sections.js";
|
|
20
|
+
export { BlueprintFileSystem } from "@projitect/core";
|
|
21
|
+
export { Blueprint, ChangeSet, Permission, Errors } from "@projitect/core";
|
|
22
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AACH,cAAc,mBAAmB,CAAA;AACjC,cAAc,eAAe,CAAA;AAC7B,cAAc,gBAAgB,CAAA;AAC9B,cAAc,aAAa,CAAA;AAC3B,cAAc,aAAa,CAAA;AAC3B,cAAc,mBAAmB,CAAA;AACjC,OAAO,EAAE,mBAAmB,EAAE,MAAM,iBAAiB,CAAA;AACrD,OAAO,EAAE,SAAS,EAAE,SAAS,EAAE,UAAU,EAAE,MAAM,EAAE,MAAM,iBAAiB,CAAA"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @projitect/blueprint
|
|
3
|
+
*
|
|
4
|
+
* Authoring SDK for blueprint packages. Blueprint authors compose these primitives — the
|
|
5
|
+
* `BlueprintFileSystem` service for FS access, the four ownership-mode constructors
|
|
6
|
+
* (`regionFile` / `jsonMerge` / `ownFile` / `seedFile`), the post-apply `exec` constructor, the section helpers
|
|
7
|
+
* (`markdownSection`, `ignoreSection`), the `directory` scope transform, and detectors for
|
|
8
|
+
* common project introspection.
|
|
9
|
+
*
|
|
10
|
+
* Authors use Effect's own control-flow combinators (`Effect.gen`, `Effect.all`, `Effect.if`,
|
|
11
|
+
* `Effect.when`, `Effect.unless`, `Effect.forEach`) for sequencing and conditionals — we do
|
|
12
|
+
* not ship duplicates.
|
|
13
|
+
*/
|
|
14
|
+
export * from "./constructors.js";
|
|
15
|
+
export * from "./sections.js";
|
|
16
|
+
export * from "./directory.js";
|
|
17
|
+
export * from "./detect.js";
|
|
18
|
+
export * from "./splice.js";
|
|
19
|
+
export * from "./add-sections.js";
|
|
20
|
+
export { BlueprintFileSystem } from "@projitect/core";
|
|
21
|
+
export { Blueprint, ChangeSet, Permission, Errors } from "@projitect/core";
|
|
22
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AACH,cAAc,mBAAmB,CAAA;AACjC,cAAc,eAAe,CAAA;AAC7B,cAAc,gBAAgB,CAAA;AAC9B,cAAc,aAAa,CAAA;AAC3B,cAAc,aAAa,CAAA;AAC3B,cAAc,mBAAmB,CAAA;AACjC,OAAO,EAAE,mBAAmB,EAAE,MAAM,iBAAiB,CAAA;AACrD,OAAO,EAAE,SAAS,EAAE,SAAS,EAAE,UAAU,EAAE,MAAM,EAAE,MAAM,iBAAiB,CAAA"}
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Section helpers — thin wrappers around `regionFile` that bake in the right comment
|
|
3
|
+
* delimiters for two common file shapes:
|
|
4
|
+
*
|
|
5
|
+
* - **`markdownSection`** for HTML/MDX/XML files where comments need a closing `-->`.
|
|
6
|
+
* The fenced region renders invisible in markdown output — readers never see the markers.
|
|
7
|
+
* Useful for README.md, AGENTS.md, CONTRIBUTING.md, generated MDX docs, etc.
|
|
8
|
+
*
|
|
9
|
+
* - **`ignoreSection`** for `#`-comment "ignore"-style files. Same shape as the gitignore
|
|
10
|
+
* convention; the helper exists because the name documents intent better than a bare
|
|
11
|
+
* `regionFile({ commentPrefix: "#" })` does, and the surface guides authors toward the
|
|
12
|
+
* right primitive when they're scaffolding a `.eslintignore` / `.prettierignore` /
|
|
13
|
+
* `.dockerignore` / `.npmignore` blueprint.
|
|
14
|
+
*
|
|
15
|
+
* Both helpers re-emit the underlying `RegionFileSpec`-shaped result of `regionFile`, so
|
|
16
|
+
* everything that works for `regionFile` works for these (extra permissions, descriptions,
|
|
17
|
+
* etc.). They aren't shipped as separate npm packages because there's no opinionated content
|
|
18
|
+
* to bundle — the blueprint author always provides their own.
|
|
19
|
+
*/
|
|
20
|
+
import type { Blueprint, Permission } from "@projitect/core";
|
|
21
|
+
export interface SectionSpec {
|
|
22
|
+
readonly id: string;
|
|
23
|
+
readonly version: string;
|
|
24
|
+
readonly description?: string;
|
|
25
|
+
readonly path: string;
|
|
26
|
+
readonly content: string;
|
|
27
|
+
readonly extraPermissions?: readonly Permission.Permission[];
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Region-mode blueprint for HTML / MDX / XML files. The fence is rendered as two HTML
|
|
31
|
+
* comments on their own lines:
|
|
32
|
+
*
|
|
33
|
+
* <!-- pjt:<owner-id> start -->
|
|
34
|
+
* <body>
|
|
35
|
+
* <!-- pjt:<owner-id> end -->
|
|
36
|
+
*
|
|
37
|
+
* The markers don't render in HTML output (they're comments), so readers of the published
|
|
38
|
+
* file never see them. `pjt inspect` flags hand-edits between the markers; lines outside
|
|
39
|
+
* the fence belong to the user.
|
|
40
|
+
*
|
|
41
|
+
* @example
|
|
42
|
+
* ```ts
|
|
43
|
+
* markdownSection({
|
|
44
|
+
* id: "my-org:readme:badges",
|
|
45
|
+
* version: "1.0.0",
|
|
46
|
+
* path: "README.md",
|
|
47
|
+
* content: "\n",
|
|
48
|
+
* })
|
|
49
|
+
* ```
|
|
50
|
+
*/
|
|
51
|
+
export declare const markdownSection: (spec: SectionSpec) => Blueprint.Blueprint;
|
|
52
|
+
/**
|
|
53
|
+
* Region-mode blueprint for `#`-comment ignore-style files: `.gitignore`, `.eslintignore`,
|
|
54
|
+
* `.prettierignore`, `.dockerignore`, `.npmignore`, etc. The fence is two `#`-prefixed lines
|
|
55
|
+
* on either side of the section content:
|
|
56
|
+
*
|
|
57
|
+
* # pjt:<owner-id> start
|
|
58
|
+
* <body>
|
|
59
|
+
* # pjt:<owner-id> end
|
|
60
|
+
*
|
|
61
|
+
* Equivalent to `regionFile({ commentPrefix: "#", ... })`, but the name documents the
|
|
62
|
+
* intent and makes the right primitive easy to find.
|
|
63
|
+
*
|
|
64
|
+
* @example
|
|
65
|
+
* ```ts
|
|
66
|
+
* ignoreSection({
|
|
67
|
+
* id: "my-org:eslintignore:generated",
|
|
68
|
+
* version: "1.0.0",
|
|
69
|
+
* path: ".eslintignore",
|
|
70
|
+
* content: "dist/\nbuild/\ncoverage/\n",
|
|
71
|
+
* })
|
|
72
|
+
* ```
|
|
73
|
+
*/
|
|
74
|
+
export declare const ignoreSection: (spec: SectionSpec) => Blueprint.Blueprint;
|
|
75
|
+
//# sourceMappingURL=sections.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sections.d.ts","sourceRoot":"","sources":["../src/sections.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAGH,OAAO,KAAK,EAAE,SAAS,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAA;AAG5D,MAAM,WAAW,WAAW;IAC1B,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAA;IACnB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAA;IACxB,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,CAAA;IAC7B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;IACrB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAA;IACxB,QAAQ,CAAC,gBAAgB,CAAC,EAAE,SAAS,UAAU,CAAC,UAAU,EAAE,CAAA;CAC7D;AAED;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,eAAO,MAAM,eAAe,GAAI,MAAM,WAAW,KAAG,SAAS,CAAC,SAU1D,CAAA;AAEJ;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,eAAO,MAAM,aAAa,GAAI,MAAM,WAAW,KAAG,SAAS,CAAC,SASxD,CAAA"}
|