@sanoma-ai/workflows 0.9.1 → 0.10.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.
Files changed (207) hide show
  1. package/README.md +193 -50
  2. package/SECRET-SUPPORT.md +33 -0
  3. package/dist/apply-steps.js +5 -2
  4. package/dist/apply-steps.js.map +1 -1
  5. package/dist/apply.d.ts +3 -0
  6. package/dist/apply.js +27 -13
  7. package/dist/apply.js.map +1 -1
  8. package/dist/approvals.d.ts +1 -0
  9. package/dist/approvals.js +6 -1
  10. package/dist/approvals.js.map +1 -1
  11. package/dist/apps.d.ts +13 -24
  12. package/dist/apps.js +69 -68
  13. package/dist/apps.js.map +1 -1
  14. package/dist/ast.d.ts +9 -7
  15. package/dist/ast.js +2 -0
  16. package/dist/ast.js.map +1 -1
  17. package/dist/authentication.d.ts +54 -0
  18. package/dist/authentication.js +138 -0
  19. package/dist/authentication.js.map +1 -0
  20. package/dist/call-workflow.d.ts +5 -0
  21. package/dist/call-workflow.js +4 -3
  22. package/dist/call-workflow.js.map +1 -1
  23. package/dist/call.d.ts +3 -2
  24. package/dist/call.js +36 -7
  25. package/dist/call.js.map +1 -1
  26. package/dist/cedar.js +14 -1
  27. package/dist/cedar.js.map +1 -1
  28. package/dist/change-steps.js +7 -5
  29. package/dist/change-steps.js.map +1 -1
  30. package/dist/change.d.ts +7 -0
  31. package/dist/change.js +7 -0
  32. package/dist/change.js.map +1 -1
  33. package/dist/client.d.ts +62 -10
  34. package/dist/client.js +272 -47
  35. package/dist/client.js.map +1 -1
  36. package/dist/collection.d.ts +7 -0
  37. package/dist/collection.js +5 -2
  38. package/dist/collection.js.map +1 -1
  39. package/dist/config.d.ts +16 -4
  40. package/dist/config.js +89 -21
  41. package/dist/config.js.map +1 -1
  42. package/dist/connection.d.ts +389 -0
  43. package/dist/connection.js +657 -0
  44. package/dist/connection.js.map +1 -0
  45. package/dist/credentials.d.ts +7 -53
  46. package/dist/credentials.js +84 -247
  47. package/dist/credentials.js.map +1 -1
  48. package/dist/db.js +34 -2
  49. package/dist/db.js.map +1 -1
  50. package/dist/define.d.ts +9 -2
  51. package/dist/define.js.map +1 -1
  52. package/dist/definitions.d.ts +20 -0
  53. package/dist/definitions.js +16 -0
  54. package/dist/definitions.js.map +1 -0
  55. package/dist/deployment-key.d.ts +2 -0
  56. package/dist/deployment-key.js +22 -0
  57. package/dist/deployment-key.js.map +1 -0
  58. package/dist/describe.d.ts +15 -175
  59. package/dist/describe.js +122 -35
  60. package/dist/describe.js.map +1 -1
  61. package/dist/description.d.ts +532 -0
  62. package/dist/description.js +381 -0
  63. package/dist/description.js.map +1 -0
  64. package/dist/direct.js +7 -0
  65. package/dist/direct.js.map +1 -1
  66. package/dist/drift.d.ts +1 -1
  67. package/dist/drift.js +1 -1
  68. package/dist/drift.js.map +1 -1
  69. package/dist/env.d.ts +2 -0
  70. package/dist/env.js +2 -2
  71. package/dist/env.js.map +1 -1
  72. package/dist/fake.d.ts +13 -1
  73. package/dist/fake.js +70 -0
  74. package/dist/fake.js.map +1 -1
  75. package/dist/index.d.ts +11 -3
  76. package/dist/index.js +10 -2
  77. package/dist/index.js.map +1 -1
  78. package/dist/ledger.d.ts +2 -0
  79. package/dist/ledger.js +1 -1
  80. package/dist/ledger.js.map +1 -1
  81. package/dist/lint.d.ts +0 -9
  82. package/dist/lint.js +2 -17
  83. package/dist/lint.js.map +1 -1
  84. package/dist/load.d.ts +85 -0
  85. package/dist/load.js +391 -0
  86. package/dist/load.js.map +1 -0
  87. package/dist/lockfile.d.ts +2 -0
  88. package/dist/lockfile.js +8 -3
  89. package/dist/lockfile.js.map +1 -1
  90. package/dist/op.d.ts +22 -5
  91. package/dist/op.js +20 -2
  92. package/dist/op.js.map +1 -1
  93. package/dist/outline.d.ts +5 -0
  94. package/dist/outline.js +46 -5
  95. package/dist/outline.js.map +1 -1
  96. package/dist/paths.d.ts +18 -2
  97. package/dist/paths.js +19 -7
  98. package/dist/paths.js.map +1 -1
  99. package/dist/plugin.d.ts +0 -11
  100. package/dist/plugin.js +3 -18
  101. package/dist/plugin.js.map +1 -1
  102. package/dist/policy.d.ts +2 -0
  103. package/dist/policy.js.map +1 -1
  104. package/dist/resource.d.ts +10 -4
  105. package/dist/resource.js +11 -4
  106. package/dist/resource.js.map +1 -1
  107. package/dist/resources.d.ts +33 -76
  108. package/dist/resources.js +219 -227
  109. package/dist/resources.js.map +1 -1
  110. package/dist/run.d.ts +4 -0
  111. package/dist/run.js.map +1 -1
  112. package/dist/sandbox.d.ts +5 -2
  113. package/dist/sandbox.js +56 -7
  114. package/dist/sandbox.js.map +1 -1
  115. package/dist/scenario.d.ts +5 -0
  116. package/dist/scenario.js +3 -2
  117. package/dist/scenario.js.map +1 -1
  118. package/dist/scenarios.js +7 -1
  119. package/dist/scenarios.js.map +1 -1
  120. package/dist/schema.js +8 -0
  121. package/dist/schema.js.map +1 -1
  122. package/dist/secret-store-check.d.ts +11 -0
  123. package/dist/secret-store-check.js +76 -0
  124. package/dist/secret-store-check.js.map +1 -0
  125. package/dist/secret-store.d.ts +106 -0
  126. package/dist/secret-store.js +228 -0
  127. package/dist/secret-store.js.map +1 -0
  128. package/dist/secret.d.ts +2 -0
  129. package/dist/secret.js +32 -0
  130. package/dist/secret.js.map +1 -1
  131. package/dist/shared.d.ts +21 -11
  132. package/dist/shared.js +41 -7
  133. package/dist/shared.js.map +1 -1
  134. package/dist/sites.d.ts +4 -93
  135. package/dist/sites.js +76 -84
  136. package/dist/sites.js.map +1 -1
  137. package/dist/steps.d.ts +3 -0
  138. package/dist/steps.js.map +1 -1
  139. package/dist/version.d.ts +2 -1
  140. package/dist/version.js +2 -1
  141. package/dist/version.js.map +1 -1
  142. package/dist/wakeup-driver.js +15 -6
  143. package/dist/wakeup-driver.js.map +1 -1
  144. package/dist/worker.js +12 -8
  145. package/dist/worker.js.map +1 -1
  146. package/dist/writer.d.ts +53 -14
  147. package/dist/writer.js +113 -43
  148. package/dist/writer.js.map +1 -1
  149. package/oxlint.json +1 -5
  150. package/package.json +6 -1
  151. package/src/apply-steps.ts +5 -2
  152. package/src/apply.ts +54 -21
  153. package/src/approvals.ts +7 -1
  154. package/src/apps.ts +71 -86
  155. package/src/ast.ts +6 -6
  156. package/src/authentication.ts +191 -0
  157. package/src/call-workflow.ts +5 -4
  158. package/src/call.ts +52 -9
  159. package/src/cedar.ts +14 -1
  160. package/src/change-steps.ts +7 -4
  161. package/src/change.ts +10 -0
  162. package/src/client.ts +346 -45
  163. package/src/collection.ts +10 -2
  164. package/src/config.ts +107 -19
  165. package/src/connection.ts +912 -0
  166. package/src/credentials.ts +94 -281
  167. package/src/db.ts +34 -2
  168. package/src/define.ts +7 -2
  169. package/src/definitions.ts +31 -0
  170. package/src/deployment-key.ts +23 -0
  171. package/src/describe.ts +150 -227
  172. package/src/description.ts +426 -0
  173. package/src/direct.ts +7 -0
  174. package/src/drift.ts +10 -2
  175. package/src/env.ts +4 -2
  176. package/src/fake.ts +71 -0
  177. package/src/index.ts +53 -1
  178. package/src/ledger.ts +3 -1
  179. package/src/lint.ts +2 -17
  180. package/src/load.ts +466 -0
  181. package/src/lockfile.ts +10 -3
  182. package/src/op.ts +41 -7
  183. package/src/outline.ts +53 -7
  184. package/src/paths.ts +21 -6
  185. package/src/plugin.ts +3 -24
  186. package/src/policy.ts +2 -0
  187. package/src/resource.ts +24 -6
  188. package/src/resources.ts +246 -301
  189. package/src/run.ts +4 -0
  190. package/src/sandbox.ts +61 -7
  191. package/src/scenario.ts +24 -6
  192. package/src/scenarios.ts +7 -1
  193. package/src/schema.ts +10 -0
  194. package/src/secret-store-check.ts +93 -0
  195. package/src/secret-store.ts +314 -0
  196. package/src/secret.ts +29 -0
  197. package/src/shared.ts +44 -10
  198. package/src/sites.ts +85 -179
  199. package/src/steps.ts +3 -2
  200. package/src/version.ts +2 -1
  201. package/src/wakeup-driver.ts +22 -6
  202. package/src/worker.ts +12 -8
  203. package/src/writer.ts +145 -56
  204. package/dist/datafile.d.ts +0 -97
  205. package/dist/datafile.js +0 -479
  206. package/dist/datafile.js.map +0 -1
  207. package/src/datafile.ts +0 -601
package/src/writer.ts CHANGED
@@ -1,27 +1,72 @@
1
1
  import { readFileSync } from "node:fs";
2
2
  import { join } from "node:path";
3
3
  import type { FormatConfig } from "oxfmt";
4
- import { type Node, parse } from "./ast.ts";
5
- import {
6
- type DataFileExport,
7
- type DataFileImport,
8
- type DataValue,
9
- isReference,
10
- keyName,
11
- readDataFile,
12
- SECRET_ENTRIES,
13
- } from "./datafile.ts";
14
- import { isSecret } from "./secret.ts";
15
-
16
- // The data-file writer: what the app's Adopt, and setting up a company, write into the files
17
- // `datafile.ts` reads. A file is changed in place, one declaration at a time, and everything
4
+ import { keyName, type Node, parse } from "./ast.ts";
5
+ import type { ConnectionRef } from "./connection.ts";
6
+ import { SECRET_ENTRIES } from "./paths.ts";
7
+ import { isSecret, type Secret } from "./secret.ts";
8
+
9
+ // The data-file writer: what the app's Adopt and its forms' Save, and setting up a company, write
10
+ // into a company's files. A file is changed in place, one declaration at a time, and everything
18
11
  // outside that declaration is kept byte for byte; what is written is formatted with oxfmt, under
19
- // the repository's own options, so it reads as if a person had written it and formatted it.
12
+ // the repository's own options, so it reads as if a person had written it and formatted it. Files
13
+ // are read by loading them; the writer parses, and changes only what is written out as a literal.
14
+
15
+ /** A name in a data file that refers to a declared resource: one imported from a data file, or exported by this one. */
16
+ export class Reference {
17
+ readonly name: string;
18
+ constructor(name: string) {
19
+ this.name = name;
20
+ }
21
+ }
22
+
23
+ const REFERENCE = Symbol.for("sanoma.reference");
24
+ Object.defineProperty(Reference.prototype, REFERENCE, { value: true });
25
+
26
+ /** True for a `Reference`, made by any copy of this package: read by a registered symbol, not `instanceof`. */
27
+ export const isReference = (value: unknown): value is Reference =>
28
+ typeof value === "object" && value !== null && REFERENCE in value;
29
+
30
+ /** A value the writer writes: a literal, a reference to a declared resource, or a secret's marker (`secret("NAME")`). */
31
+ export type DataValue =
32
+ | null
33
+ | boolean
34
+ | number
35
+ | string
36
+ | Reference
37
+ | Secret
38
+ | DataValue[]
39
+ | { [field: string]: DataValue };
40
+
41
+ /**
42
+ * Why `setFields` will not write a field: the file computes what is there (a name, a call, a
43
+ * spread), or the declaration is not an object literal, so only a person editing the code can
44
+ * change it. `reason` says which, for the form that asked.
45
+ */
46
+ export class NotLiteral extends Error {
47
+ readonly reason: string;
48
+ /** The field the file computes, by dotted path; absent when the declaration itself is no object literal. */
49
+ readonly field: string | undefined;
50
+ constructor(reason: string, field?: string) {
51
+ super(reason);
52
+ this.name = "NotLiteral";
53
+ this.reason = reason;
54
+ this.field = field;
55
+ }
56
+ }
20
57
 
21
58
  /** A whole data file to render: its imports and its resources, in order. */
22
59
  export interface DataFileContent {
23
- imports: readonly Pick<DataFileImport, "source" | "imported" | "local">[];
24
- exports: readonly Pick<DataFileExport, "name" | "vendor" | "type" | "desired">[];
60
+ /** Each `import { imported as local } from "source"`. */
61
+ imports: readonly { source: string; imported: string; local: string }[];
62
+ /** Each `export const name = vendor.type({ ...desired }, { connection })`. */
63
+ exports: readonly {
64
+ name: string;
65
+ vendor: string;
66
+ type: string;
67
+ desired: { [field: string]: DataValue };
68
+ connection?: ConnectionRef;
69
+ }[];
25
70
  }
26
71
 
27
72
  /**
@@ -41,19 +86,22 @@ export function formatOptions(root: string): FormatConfig {
41
86
  }
42
87
 
43
88
  /**
44
- * `source`, a data file's text, with fields of its resource `exportName` set to new values:
89
+ * `source`, a company file's text, with fields of its declaration `exportName` set to new values:
45
90
  * `fields` by dotted path, a list item's with its index, as a drift report names them
46
- * (`required_pull_request_reviews.0.dismiss_stale_reviews`). A field the declaration does not
47
- * have is added at the end of the object that should hold it. Only that `export const` changes:
48
- * it is formatted with oxfmt under `options` (`formatOptions`), and every other byte of the file
49
- * stays as it was.
91
+ * (`required_pull_request_reviews.0.dismiss_stale_reviews`). The declaration is the object
92
+ * literal of `export const <exportName> = …` (or `export default …` for `"default"`): the object
93
+ * itself, or the first argument of the call it is (`github.repository({ … })`,
94
+ * `defineSite({ … })`). A field the declaration does not have is added at the end of the object
95
+ * that should hold it. Only that statement changes: it is formatted with oxfmt under `options`
96
+ * (`formatOptions`), and every other byte of the file stays as it was.
50
97
  *
51
98
  * A value naming a secret adds `import { secret } from "sanoma/resources"` after the file's
52
99
  * imports when it has none.
53
100
  *
54
- * Throws when the file does not parse, declares no such resource, or a path cannot be set: it
55
- * runs through a value that is not an object or a list, or ends at a reference to another
56
- * resource (a person changes a reference; a vendor's value never replaces one).
101
+ * Throws `NotLiteral` when the declaration is not an object literal, or a path reaches a value the
102
+ * file computes (a name, such as a reference to another resource, a call, a spread): a person
103
+ * changes those in the code. Throws an `Error` when the file does not parse, has no such export,
104
+ * or a path runs through a literal that is not an object or a list.
57
105
  */
58
106
  export async function setFields(
59
107
  source: string,
@@ -74,14 +122,13 @@ export async function setFields(
74
122
  return text.slice(0, start) + formatted.trimEnd() + text.slice(end);
75
123
  }
76
124
 
77
- /** What a data file imports `secret` from when it names one (`readDataFile` lists no such import). */
125
+ /** What a data file imports `secret` from when it names one. */
78
126
  const SECRET_IMPORT = { source: "sanoma/resources", imported: "secret", local: "secret" };
79
127
 
80
128
  /**
81
129
  * A whole data file: the imports, one per source, then each resource as `export const`, then
82
- * `export default` naming them all, formatted with oxfmt under `options`. `readDataFile` reads it
83
- * back as it was given: what `readDataFile` returns renders the file again. A file whose values
84
- * name a secret also imports `secret` from "sanoma/resources".
130
+ * `export default` naming them all, formatted with oxfmt under `options`: loaded, it declares
131
+ * what it was given. A file whose values name a secret also imports `secret` from "sanoma/resources".
85
132
  */
86
133
  export async function renderDataFile({ imports, exports }: DataFileContent, options: FormatConfig = {}) {
87
134
  const names = new Map<string, string[]>();
@@ -95,9 +142,9 @@ export async function renderDataFile({ imports, exports }: DataFileContent, opti
95
142
  const parts = [
96
143
  [...names].map(([source, list]) => `import { ${list.join(", ")} } from ${JSON.stringify(source)};`).join("\n"),
97
144
  // The top-level object on lines of its own, so oxfmt keeps it expanded as people write it.
98
- ...exports.map(({ name, vendor, type, desired }) => {
145
+ ...exports.map(({ name, vendor, type, desired, connection }) => {
99
146
  const body = Object.entries(desired).map(([key, value]) => `${keyOf(key)}: ${literal(value)},\n`);
100
- return `export const ${name} = ${vendor}.${type}({${body.length ? `\n${body.join("")}` : ""}});`;
147
+ return `export const ${name} = ${vendor}.${type}({${body.length ? `\n${body.join("")}` : ""}}${connection ? `, ${JSON.stringify({ connection })}` : ""});`;
101
148
  }),
102
149
  `export default [${exports.map((e) => e.name).join(", ")}];`,
103
150
  ];
@@ -118,16 +165,34 @@ function withSecretImport(text: string): string {
118
165
  return at ? `${text.slice(0, at)}\n${line}${text.slice(at)}` : `${line}\n${text}`;
119
166
  }
120
167
 
121
- /** The `export const` of the resource `name` in `text`, and the object literal its constructor takes. */
168
+ /**
169
+ * The statement that exports `name` in `text` (`export const <name> = …`, or `export default …`
170
+ * for `"default"`), and the object literal it declares: the value itself, or the first argument
171
+ * of the call it is.
172
+ */
122
173
  function declarationOf(text: string, name: string): { statement: Node; object: Node } {
123
- // The name is never resolved, and a relative import is checked against the file's own directory.
124
- const filename = "/data-file.ts";
125
- const { program, errors } = parse(filename, text);
174
+ const { program, errors } = parse("/data-file.ts", text);
126
175
  if (errors.length) throw new Error(`The data file does not parse: ${errors[0]!.message}`);
127
- const found = readDataFile(program, filename).exports.find((e) => e.name === name);
128
- if (!found) throw new Error(`The data file declares no resource ${name}`);
129
- const statement: Node = program.body.find((s) => s.start === found.start);
130
- return { statement, object: statement.declaration.declarations[0].init.arguments[0] };
176
+ for (const statement of program.body) {
177
+ const value = exportedValue(statement, name);
178
+ if (value === undefined) continue;
179
+ const object = value?.type === "CallExpression" ? value.arguments[0] : value;
180
+ if (object?.type !== "ObjectExpression") throw new NotLiteral(`${name} is not an object literal: edit it in code`);
181
+ return { statement, object };
182
+ }
183
+ throw new Error(`The data file declares no resource ${name}`);
184
+ }
185
+
186
+ /** The value `statement` exports as `name` (null for `export let x;`), or undefined when it exports no such name. */
187
+ function exportedValue(statement: Node, name: string): Node | null | undefined {
188
+ if (name === "default") return statement.type === "ExportDefaultDeclaration" ? statement.declaration : undefined;
189
+ if (statement.type !== "ExportNamedDeclaration" || statement.declaration?.type !== "VariableDeclaration") {
190
+ return undefined;
191
+ }
192
+ const declarator = statement.declaration.declarations.find(
193
+ (d: Node) => d.id.type === "Identifier" && d.id.name === name,
194
+ );
195
+ return declarator && declarator.init;
131
196
  }
132
197
 
133
198
  /**
@@ -139,38 +204,62 @@ function editAt(object: Node, path: string, value: DataValue): { start: number;
139
204
  const keys = path.split(".");
140
205
  let node = object;
141
206
  for (let i = 0; i < keys.length;) {
142
- if (node.type === "ObjectExpression") {
207
+ // A spread may hold the field, or move the list's items: what is there is the code's.
208
+ if (node.type === "ObjectExpression" && !node.properties.some(isSpread)) {
143
209
  const names = new Map<string, Node>(node.properties.map((p: Node) => [fieldName(p), p]));
144
210
  let j = keys.length;
145
211
  while (j > i && !names.has(keys.slice(i, j).join("."))) j--;
146
212
  if (j === i) return added(node, keys.slice(i), path, value);
147
213
  node = names.get(keys.slice(i, j).join("."))!.value;
148
214
  i = j;
149
- } else if (node.type === "ArrayExpression" && /^\d+$/.test(keys[i]!) && node.elements[Number(keys[i])]) {
215
+ } else if (
216
+ node.type === "ArrayExpression" &&
217
+ !node.elements.some(isSpread) &&
218
+ /^\d+$/.test(keys[i]!) &&
219
+ node.elements[Number(keys[i])]
220
+ ) {
150
221
  node = node.elements[Number(keys[i])];
151
222
  i++;
223
+ } else if (computed(node)) {
224
+ throw computedAt(keys.slice(0, Math.max(i, 1)).join("."));
152
225
  } else {
153
226
  const at = keys.slice(0, i).join(".");
154
227
  throw new Error(`Cannot set ${path}: ${at} is not an object or a list with item ${keys[i]}`);
155
228
  }
156
229
  }
157
- const named = referenceIn(node);
158
- if (named) {
159
- throw new Error(`Cannot set ${path}: it names the resource ${named}; change a reference in the file itself`);
160
- }
230
+ if (computed(node)) throw computedAt(path);
161
231
  return { start: node.start, end: node.end, replacement: literal(value) };
162
232
  }
163
233
 
164
- /** The first resource a value names, itself or anywhere inside it: a vendor's value never replaces one. */
165
- function referenceIn(node: Node): string | undefined {
166
- if (node.type === "Identifier") return node.name;
167
- const items =
168
- node.type === "ArrayExpression" ? node.elements : node.type === "ObjectExpression" ? node.properties : [];
169
- for (const item of items) {
170
- const named = item && referenceIn(item.type === "Property" ? item.value : item);
171
- if (named) return named;
234
+ /** The refusal of a field whose value the file computes. */
235
+ const computedAt = (field: string) => new NotLiteral(`the value of ${field} is computed in the file`, field);
236
+
237
+ const isSpread = (node: Node) => node?.type === "SpreadElement";
238
+
239
+ /**
240
+ * True when a value is (or holds) code rather than a literal: a name (a reference to another
241
+ * resource, a constant), a call other than `secret(…)`, a spread, a template with expressions.
242
+ * A person changes those in the file; a form's or a vendor's value never replaces one.
243
+ */
244
+ function computed(node: Node): boolean {
245
+ switch (node.type) {
246
+ case "Literal":
247
+ return false;
248
+ case "TemplateLiteral":
249
+ return node.expressions.length > 0;
250
+ case "UnaryExpression":
251
+ return !["-", "+"].includes(node.operator) || node.argument.type !== "Literal";
252
+ case "ArrayExpression":
253
+ return node.elements.some((item: Node) => item === null || computed(item));
254
+ case "ObjectExpression":
255
+ return node.properties.some(
256
+ (p: Node) => p.type !== "Property" || p.computed || p.kind !== "init" || p.method || computed(p.value),
257
+ );
258
+ case "CallExpression":
259
+ return !(node.callee.type === "Identifier" && node.callee.name === "secret" && !node.arguments.some(computed));
260
+ default:
261
+ return true;
172
262
  }
173
- return undefined;
174
263
  }
175
264
 
176
265
  /**
@@ -188,7 +277,7 @@ function added(object: Node, [key, ...under]: string[], path: string, value: Dat
188
277
  : { start: object.start, end: object.end, replacement: `{ ${field} }` };
189
278
  }
190
279
 
191
- /** A property's name, as `readDataFile` reads it. */
280
+ /** A property's name: undefined for a computed key or a spread. */
192
281
  const fieldName = (p: Node): string | undefined => (p.type === "Property" && !p.computed ? keyName(p.key) : undefined);
193
282
 
194
283
  /** A field's name in source: bare when it can be, else a string. */
@@ -199,7 +288,7 @@ const holdsSecret = (value: DataValue): boolean =>
199
288
  isSecret(value) ||
200
289
  (typeof value === "object" && value !== null && !isReference(value) && Object.values(value).some(holdsSecret));
201
290
 
202
- /** A value in the data-file subset, as source, on one line: oxfmt lays it out. */
291
+ /** A value as source, on one line: oxfmt lays it out. */
203
292
  function literal(value: DataValue): string {
204
293
  if (isReference(value)) return value.name;
205
294
  if (isSecret(value)) return `secret(${JSON.stringify(value.$secret)}${value.generate ? ", { generate: true }" : ""})`;
@@ -1,97 +0,0 @@
1
- import type { Node } from "./ast.ts";
2
- import { type Secret } from "./secret.ts";
3
- /** Something a data file may not hold, at UTF-16 offsets into its text. */
4
- export interface DataFileProblem {
5
- start: number;
6
- end: number;
7
- message: string;
8
- }
9
- /** A name in a data file that refers to a declared resource: one imported from a data file, or exported by this one. */
10
- export declare class Reference {
11
- readonly name: string;
12
- constructor(name: string);
13
- }
14
- /** True for a `Reference`, made by any copy of this package: read by a registered symbol, not `instanceof`. */
15
- export declare const isReference: (value: unknown) => value is Reference;
16
- /** What `secret("NAME")` stands for in a data file: its marker, `{ $secret: "NAME", generate?: true }`. */
17
- export type SecretRef = Secret;
18
- /** A value in a data file: a literal, a reference to a declared resource, or a secret's marker. */
19
- export type DataValue = null | boolean | number | string | Reference | SecretRef | DataValue[] | {
20
- [field: string]: DataValue;
21
- };
22
- /** An `import { name } from "…"`: of a connector's constructors (`from "…/resources"`), or of another data file's resource. */
23
- export interface DataFileImport {
24
- kind: "constructors" | "file";
25
- /** The specifier as written. */
26
- source: string;
27
- /** The name the other module exports. */
28
- imported: string;
29
- /** The name it has in this file. */
30
- local: string;
31
- start: number;
32
- }
33
- /** An `export const name = vendor.type({ … })`. */
34
- export interface DataFileExport {
35
- name: string;
36
- /** The local name of the constructors it calls (`github`). */
37
- vendor: string;
38
- type: string;
39
- desired: {
40
- [field: string]: DataValue;
41
- };
42
- /** The `export const` statement. */
43
- start: number;
44
- end: number;
45
- }
46
- /** An `export const name = collection({ … })` in `resources/data.ts`, its declaration one `collection()` takes. */
47
- export interface DataFileCollection {
48
- /** The `export const`'s name. */
49
- export: string;
50
- /** The collection's name. */
51
- name: string;
52
- /** The `export const` statement. */
53
- start: number;
54
- end: number;
55
- }
56
- export interface DataFile {
57
- imports: DataFileImport[];
58
- /** Each `export const` whose value is in the subset. */
59
- exports: DataFileExport[];
60
- /** Each collection `resources/data.ts` declares (`COLLECTIONS_FILE`); none in any other data file. */
61
- collections: DataFileCollection[];
62
- /** Every name an `export const` declares as a resource, its value in the subset or not: none in `resources/data.ts`. */
63
- declared: string[];
64
- problems: DataFileProblem[];
65
- }
66
- /**
67
- * Where a data file imports `secret` from, and `sanoma`, the runtime's own resource constructors
68
- * (its people: `sanoma.person`, `.agent`, `.group`); checked before `CONSTRUCTORS`, which they match too.
69
- */
70
- export declare const SECRET_ENTRIES: ReadonlySet<string>;
71
- /** Where `resources/data.ts` imports `collection` from, and the only imports it may make. */
72
- export declare const DATA_ENTRIES: ReadonlySet<string>;
73
- /**
74
- * The one data file that holds collections, relative to `resources/`. Workflows and the runtime
75
- * import it, so it imports only `collection` from "sanoma/data" and holds nothing else.
76
- */
77
- export declare const COLLECTIONS_FILE = "data.ts";
78
- /**
79
- * Reads a data file's program without running it: its imports, each `export const` resource
80
- * with its fields evaluated, and everything outside the data-file subset as a problem that says
81
- * what to write instead.
82
- *
83
- * The subset: named imports, from a connector's `…/resources` entry or a `.ts` data file;
84
- * `export const <name> = <vendor>.<type>({ … })`, one per statement, its argument built of
85
- * strings (template literals without `${}` too), numbers, booleans, null, objects and arrays,
86
- * and names of resources this file declares or imports; and `export default [a, b]`.
87
- * `resources/data.ts` (`COLLECTIONS_FILE`) is the exception, the one data file workflows and the
88
- * runtime import: it imports only `collection` from "sanoma/data", and each `export const` is
89
- * `collection({ … })` with its values written out (`DataFile.collections`). No other data file
90
- * declares a collection, and none imports one.
91
- *
92
- * `root` is the directory relative imports must stay in: by default the nearest `resources/`
93
- * directory above `filename`, else the file's own.
94
- */
95
- export declare function readDataFile(program: Node, filename: string, root?: string): DataFile;
96
- /** A property's name: an identifier's, or a literal's as a string; undefined for any other key. */
97
- export declare const keyName: (key: Node) => string | undefined;