@crombolo/transfer 0.9.1 → 0.10.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@crombolo/transfer",
3
- "version": "0.9.1",
3
+ "version": "0.10.0",
4
4
  "description": "Content transfer for crombolo: bundles of content moved between environments.",
5
5
  "license": "MIT",
6
6
  "author": "Crombolo",
@@ -28,7 +28,7 @@
28
28
  "access": "public"
29
29
  },
30
30
  "dependencies": {
31
- "@crombolo/core": "0.9.1",
32
- "@crombolo/data": "0.9.1"
31
+ "@crombolo/core": "0.10.0",
32
+ "@crombolo/data": "0.10.0"
33
33
  }
34
34
  }
package/src/check.ts CHANGED
@@ -3,7 +3,7 @@
3
3
  * from someone first.
4
4
  *
5
5
  * Read-only, and it runs before every import rather than only when asked
6
- * (`13-content-transfer.md`). The point is that nothing is written until the
6
+ * (`content-transfer.md`). The point is that nothing is written until the
7
7
  * conflicts are named and answered, so a transfer is never a surprise.
8
8
  *
9
9
  * Findings share the shape, table, endpoint and dashboard of the pre-upgrade
package/src/import.ts CHANGED
@@ -59,6 +59,8 @@ export interface ImportOptions extends CheckOptions {
59
59
  nodeId?: string
60
60
  /** A human label for the run listing. */
61
61
  label?: string | undefined
62
+ /** The npm package the bundle arrived in, recorded on the run. */
63
+ package?: { name: string; version: string } | undefined
62
64
  }
63
65
 
64
66
  export interface ImportResult {
@@ -158,6 +160,8 @@ export async function importBundle(
158
160
  id: runId,
159
161
  bundleId: set.manifest.id,
160
162
  bundleLabel: options.label ?? null,
163
+ packageName: options.package?.name ?? null,
164
+ packageVersion: options.package?.version ?? null,
161
165
  direction: 'import',
162
166
  revertsRunId: null,
163
167
  schemaStateId: state.id,
package/src/index.ts CHANGED
@@ -3,6 +3,7 @@ export * from './export.ts'
3
3
  export * from './import.ts'
4
4
  export * from './load.ts'
5
5
  export * from './model.ts'
6
+ export * from './package.ts'
6
7
  export * from './references.ts'
7
8
  export * from './resolutions.ts'
8
9
  export * from './revert.ts'
package/src/model.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  /**
2
2
  * The bundle: content selected out of one environment and reviewable on its way
3
- * to another. `docs/13-content-transfer.md`.
3
+ * to another. `docs/content-transfer.md`.
4
4
  *
5
5
  * Everything travels by uuid and alias, never by integer id, because the ids
6
6
  * differ between environments and the keys do not. A content type is matched by
@@ -32,7 +32,7 @@ export const CONTENT_ONLY_FORMAT_VERSION = 1
32
32
  * layout therefore installs into another's.
33
33
  *
34
34
  * There is one section for components, not two. Umbraco's split of templates
35
- * and partial views was a Razor concern (`docs/05-rendering.md`), and a bundle
35
+ * and partial views was a Razor concern (`docs/rendering.md`), and a bundle
36
36
  * that carried it would push the distinction back into every site that
37
37
  * installed one.
38
38
  */
package/src/package.ts ADDED
@@ -0,0 +1,84 @@
1
+ /**
2
+ * A written bundle as the npm package every bundle is: a `package.json` whose
3
+ * `crombolo` field declares the payload, and the payload under `content/`.
4
+ * `docs/bundles.md`.
5
+ *
6
+ * The payload is `writeBundle`'s output unchanged, so its manifest, integrity
7
+ * hash and sections mean what they always did. The package is what gives it a
8
+ * name, a version and a core it was written for.
9
+ */
10
+ import type { BundleFile } from './write.ts'
11
+
12
+ /** The directory inside a package that holds the `bundle.json` payload. */
13
+ export const PAYLOAD_DIR = 'content'
14
+
15
+ /** The npm keyword a bundle publishes so the marketplace can find it. */
16
+ export const BUNDLE_KEYWORD = 'crombolo-bundle'
17
+
18
+ export interface BundlePackageInfo {
19
+ /** The npm package name. */
20
+ name: string
21
+ version: string
22
+ /** `crombolo.id`. */
23
+ id: string
24
+ /** `crombolo.name`, what a person calls it. */
25
+ label: string
26
+ description?: string
27
+ /** A package that is never published: an environment's export. */
28
+ private?: boolean
29
+ /** The range on `@crombolo/crombolo` it is written for. */
30
+ peerRange: string
31
+ }
32
+
33
+ const NPM_NAME = /^(?:@[a-z0-9][a-z0-9._-]*\/)?[a-z0-9][a-z0-9._-]*$/
34
+
35
+ /** Lowercase words joined by hyphens, from whatever someone named a thing. */
36
+ const slug = (text: string): string =>
37
+ text
38
+ .normalize('NFKD')
39
+ .replace(/[̀-ͯ]/g, '')
40
+ .toLowerCase()
41
+ .replace(/[^a-z0-9]+/g, '-')
42
+ .replace(/^-+|-+$/g, '')
43
+
44
+ /** A name npm would accept. */
45
+ export function isPackageName(name: string): boolean {
46
+ return NPM_NAME.test(name) && name.length <= 214
47
+ }
48
+
49
+ /** A bundle id, 2–39 characters, derived from a name: what an unset definition defaults to. */
50
+ export function bundleIdFor(text: string): string {
51
+ let id = slug(text).replace(/^[^a-z]+/, '')
52
+ if (id.length < 2) id = `bundle-${id}`.replace(/-$/, '')
53
+ return id.slice(0, 39).replace(/-+$/, '')
54
+ }
55
+
56
+ /** An unscoped package name derived from a name. */
57
+ export function packageNameFor(text: string): string {
58
+ return bundleIdFor(text)
59
+ }
60
+
61
+ /** The `package.json` a bundle package is written with. */
62
+ export function bundlePackageJson(info: BundlePackageInfo): Record<string, unknown> {
63
+ return {
64
+ name: info.name,
65
+ version: info.version,
66
+ ...(info.description ? { description: info.description } : {}),
67
+ ...(info.private ? { private: true } : { keywords: [BUNDLE_KEYWORD] }),
68
+ files: [PAYLOAD_DIR],
69
+ peerDependencies: { '@crombolo/crombolo': info.peerRange },
70
+ crombolo: { id: info.id, name: info.label, content: PAYLOAD_DIR },
71
+ }
72
+ }
73
+
74
+ /** A payload's files, placed into a package under `content/` beside its `package.json`. */
75
+ export function writeBundlePackage(
76
+ payload: readonly BundleFile[],
77
+ info: BundlePackageInfo,
78
+ ): BundleFile[] {
79
+ if (!isPackageName(info.name)) throw new Error(`"${info.name}" is not a package name npm accepts`)
80
+ return [
81
+ { path: 'package.json', text: `${JSON.stringify(bundlePackageJson(info), null, 2)}\n` },
82
+ ...payload.map((file) => ({ ...file, path: `${PAYLOAD_DIR}/${file.path}` })),
83
+ ]
84
+ }
@@ -2,7 +2,7 @@
2
2
  * `resolutions.json`, beside the bundle it answers.
3
3
  *
4
4
  * A decision is committed with the bundle rather than retyped per environment,
5
- * for the reason `10-packaging-and-upgrades.md` gives for site-authored value
5
+ * for the reason `packaging-and-upgrades.md` gives for site-authored value
6
6
  * migrations: the same fix-up should not be worked out again in test and then
7
7
  * again in production, each time against more content.
8
8
  *
package/src/revert.ts CHANGED
@@ -275,6 +275,8 @@ export async function revertRun(
275
275
  id: newRunId,
276
276
  bundleId: original.bundleId,
277
277
  bundleLabel: `revert of ${runId}`,
278
+ packageName: original.packageName,
279
+ packageVersion: original.packageVersion,
278
280
  direction: 'revert',
279
281
  revertsRunId: runId,
280
282
  schemaStateId: state.id,