@dbx-tools/projen 0.9.19 → 0.9.28

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 (56) hide show
  1. package/README.md +83 -229
  2. package/index.ts +11 -18
  3. package/package.json +9 -5
  4. package/src/_task-command.ts +75 -0
  5. package/src/barrels.ts +1 -74
  6. package/src/module-exports.ts +175 -1
  7. package/src/openapi.ts +5 -72
  8. package/src/packages.ts +45 -0
  9. package/src/project-js.ts +5 -48
  10. package/src/project-predicate.ts +1 -2
  11. package/src/project-py.ts +87 -199
  12. package/src/project.ts +2 -2
  13. package/src/python-node-bindings.ts +138 -0
  14. package/src/python-node-bundle.ts +92 -0
  15. package/src/release-catalog.ts +40 -208
  16. package/src/{release-dispatch.ts → release-context.ts} +0 -11
  17. package/src/release.ts +74 -778
  18. package/src/scaffold.ts +2 -6
  19. package/src/workspace-version.ts +9 -121
  20. package/tasks/bump.ts +17 -34
  21. package/tasks/databricks-cli-assets.ts +129 -0
  22. package/tasks/local-publish.ts +61 -138
  23. package/tasks/publish-npm.ts +71 -30
  24. package/tasks/publish-python.ts +61 -148
  25. package/tasks/publish.ts +32 -182
  26. package/tasks/python-node-bindings-watch.ts +47 -0
  27. package/tasks/python-node-bindings.ts +1017 -0
  28. package/tasks/python-registry.ts +2 -9
  29. package/tasks/python-release.ts +74 -0
  30. package/tasks/release-version.ts +23 -2
  31. package/tasks/release.ts +99 -0
  32. package/tasks/sync.ts +13 -18
  33. package/tasks/version-check.ts +13 -72
  34. package/src/_rust-project.ts +0 -429
  35. package/src/_rust-release-workflow.ts +0 -698
  36. package/src/project-rs.ts +0 -1127
  37. package/src/release-plan.ts +0 -269
  38. package/src/release-please.ts +0 -242
  39. package/src/uniffi.ts +0 -65
  40. package/tasks/publish-uniffi-local.ts +0 -314
  41. package/tasks/release-assets.ts +0 -476
  42. package/tasks/release-bootstrap.ts +0 -59
  43. package/tasks/release-candidate.ts +0 -383
  44. package/tasks/release-manifest.ts +0 -273
  45. package/tasks/release-plan.ts +0 -89
  46. package/tasks/release-please.ts +0 -162
  47. package/tasks/release-pr.ts +0 -563
  48. package/tasks/release-request.ts +0 -166
  49. package/tasks/release-summary-units.ts +0 -75
  50. package/tasks/release-summary.ts +0 -381
  51. package/tasks/rust.ts +0 -178
  52. package/tasks/stamp-python.ts +0 -13
  53. package/tasks/uniffi-python.d.ts +0 -61
  54. package/tasks/uniffi-python.js +0 -191
  55. package/tasks/uniffi-release.mjs +0 -573
  56. package/tasks/uniffi.ts +0 -271
package/tasks/uniffi.ts DELETED
@@ -1,271 +0,0 @@
1
- #!/usr/bin/env -S bun
2
- import { spawnSync } from "node:child_process";
3
- import {
4
- cpSync,
5
- existsSync,
6
- mkdirSync,
7
- mkdtempSync,
8
- readFileSync,
9
- readdirSync,
10
- renameSync,
11
- rmSync,
12
- writeFileSync,
13
- } from "node:fs";
14
- import { tmpdir } from "node:os";
15
- import { basename, dirname, join, resolve } from "node:path";
16
- import { fileURLToPath } from "node:url";
17
- import { parseArgs } from "node:util";
18
- import { installPythonBindings } from "./uniffi-python.js";
19
- import { makeReadonly, makeWritable, stampGenerated } from "../src/generated.ts";
20
- import type { RustWorkspaceMapping } from "../src/project-rs.ts";
21
- import {
22
- addExplicitInterfaceReexports,
23
- addTypeScriptExtensionsToBindingImports,
24
- makeDefaultedInterfaceParametersOptional,
25
- removeObsoleteInterfaceAliases,
26
- } from "../src/uniffi.ts";
27
-
28
- const { values } = parseArgs({
29
- options: {
30
- root: { type: "string" },
31
- crate: { type: "string" },
32
- node: { type: "string" },
33
- python: { type: "string" },
34
- "python-module": { type: "string" },
35
- "cargo-target": { type: "string" },
36
- "node-package-base": { type: "string" },
37
- ubrn: { type: "string" },
38
- "skip-build": { type: "boolean" },
39
- "skip-barrels": { type: "boolean" },
40
- },
41
- });
42
- if (!values.crate || (!values.node && !values.python)) {
43
- throw new Error("Expected --crate and at least one of --node or --python");
44
- }
45
-
46
- const root = values.root
47
- ? resolve(values.root)
48
- : resolve(dirname(fileURLToPath(import.meta.url)), "../..");
49
- const crate = values.crate;
50
- const libraryName = crate.replaceAll("-", "_");
51
- const workspace = JSON.parse(readFileSync(join(root, "package.json"), "utf8")).dbxToolsConfig
52
- ?.rust as RustWorkspaceMapping | undefined;
53
- const binding = workspace?.bindings.find((binding) => binding.crate === crate);
54
- const dependencies =
55
- workspace?.bindings.filter((candidate) => binding?.dependencies?.includes(candidate.crate)) ?? [];
56
- const extension =
57
- process.platform === "darwin" ? "dylib" : process.platform === "win32" ? "dll" : "so";
58
- const prefix = process.platform === "win32" ? "" : "lib";
59
- const normalizedOutput = (value: string): string =>
60
- value
61
- .replace(/[\p{Extended_Pictographic}\uFE0F]/gu, "")
62
- .replace(/[ \t]+$/gm, "")
63
- .trim();
64
- const run = (command: string, args: string[]) => {
65
- const result = spawnSync(command, args, { cwd: root, encoding: "utf8" });
66
- const stdout = normalizedOutput(result.stdout ?? "");
67
- const stderr = normalizedOutput(result.stderr ?? "");
68
- if (stdout) process.stdout.write(`${stdout}\n`);
69
- if (stderr) process.stderr.write(`${stderr}\n`);
70
- if (result.error) {
71
- throw new Error(`${command} failed: ${result.error.message}`, { cause: result.error });
72
- }
73
- if (result.status !== 0) throw new Error(`${command} exited with ${result.status}`);
74
- };
75
-
76
- const cargoMetadata = spawnSync("cargo", ["metadata", "--format-version", "1", "--no-deps"], {
77
- cwd: root,
78
- encoding: "utf8",
79
- });
80
- if (cargoMetadata.error) {
81
- throw new Error(`cargo metadata failed: ${cargoMetadata.error.message}`, {
82
- cause: cargoMetadata.error,
83
- });
84
- }
85
- if (cargoMetadata.status !== 0) {
86
- throw new Error(`cargo metadata exited with ${cargoMetadata.status}`);
87
- }
88
- const cargoTargetRoot = (JSON.parse(cargoMetadata.stdout) as { target_directory?: unknown })
89
- .target_directory;
90
- if (typeof cargoTargetRoot !== "string" || !cargoTargetRoot) {
91
- throw new Error("cargo metadata returned no target_directory");
92
- }
93
- const targetDirectory = values["cargo-target"]
94
- ? join(cargoTargetRoot, values["cargo-target"], "release")
95
- : join(cargoTargetRoot, "release");
96
- const library = join(targetDirectory, `${prefix}${libraryName}.${extension}`);
97
-
98
- const replaceGenerated = (source: string, destination: string): void => {
99
- const deadline = Date.now() + 5_000;
100
- const signal = new Int32Array(new SharedArrayBuffer(4));
101
- while (!existsSync(source) && Date.now() < deadline) Atomics.wait(signal, 0, 0, 25);
102
- if (!existsSync(source)) throw new Error(`Missing generated binding: ${source}`);
103
- mkdirSync(dirname(destination), { recursive: true });
104
- makeWritable(destination);
105
- rmSync(destination, { force: true });
106
- try {
107
- renameSync(source, destination);
108
- } catch (error) {
109
- if (!(error instanceof Error) || !("code" in error) || error.code !== "EXDEV") throw error;
110
- cpSync(source, destination);
111
- rmSync(source, { force: true });
112
- }
113
- };
114
-
115
- if (!values["skip-build"]) {
116
- run("cargo", [
117
- "build",
118
- "--release",
119
- ...(existsSync(join(root, "Cargo.lock")) ? ["--locked"] : []),
120
- "--package",
121
- crate,
122
- "--features",
123
- "uniffi-bindgen",
124
- ...(values["cargo-target"] ? ["--target", values["cargo-target"]] : []),
125
- ]);
126
- }
127
- if (!existsSync(library)) throw new Error(`Missing compiled UniFFI library: ${library}`);
128
-
129
- if (values.node) {
130
- const nodeSource = resolve(root, values.node, "src");
131
- const nodeOutput = mkdtempSync(join(tmpdir(), `${libraryName}-node-`));
132
- run(values.ubrn ? resolve(values.ubrn) : join(root, "node_modules/.bin/ubrn"), [
133
- "generate",
134
- "napi",
135
- "bindings",
136
- "--library",
137
- "--ts-dir",
138
- nodeOutput,
139
- ...(values["node-package-base"]
140
- ? ["--lib-package-base", values["node-package-base"], "--lib-node-triple"]
141
- : ["--lib-colocated"]),
142
- library,
143
- ]);
144
- const generatedModules = readdirSync(nodeOutput).filter(
145
- (file) => file.endsWith(".ts") && file !== "index.ts",
146
- );
147
- for (const dependency of dependencies) {
148
- if (!dependency.nodePackage) throw new Error(`Missing Node binding for ${dependency.crate}`);
149
- const namespace = dependency.crate.replaceAll("-", "_");
150
- for (const file of readdirSync(nodeOutput).filter((file) => file.endsWith(".ts"))) {
151
- const path = join(nodeOutput, file);
152
- const source = readFileSync(path, "utf8")
153
- .replace(
154
- new RegExp(`import (\\w+) from ["']\\./${namespace}["'];`, "g"),
155
- `import { uniffiModule as $1 } from "${dependency.nodePackage}";`,
156
- )
157
- .replaceAll(`'./${namespace}'`, `'${dependency.nodePackage}'`)
158
- .replaceAll(`"./${namespace}"`, `"${dependency.nodePackage}"`);
159
- writeFileSync(path, source);
160
- }
161
- for (const suffix of [".ts", "-ffi.ts"]) {
162
- const file = `${namespace}${suffix}`;
163
- rmSync(join(nodeOutput, file), { force: true });
164
- const index = generatedModules.indexOf(file);
165
- if (index >= 0) generatedModules.splice(index, 1);
166
- }
167
- }
168
- const ownModules = generatedModules.filter(
169
- (file) => file === `${libraryName}.ts` || file === `${libraryName}-ffi.ts`,
170
- );
171
- if (ownModules.length !== 2 || generatedModules.length !== 2) {
172
- throw new Error(`Unmapped UniFFI components in ${crate}: ${generatedModules.join(", ")}`);
173
- }
174
- writeFileSync(
175
- join(nodeOutput, "index.ts"),
176
- [
177
- `export * from './${libraryName}';`,
178
- `import uniffiModule from './${libraryName}';`,
179
- "uniffiModule.initialize();",
180
- "export { uniffiModule };",
181
- "export async function uniffiInitAsync() {}",
182
- "",
183
- ].join("\n"),
184
- );
185
- const nodeBindings = join(nodeSource, "bindings.ts");
186
- const generatedFiles = [join(nodeSource, "_bindings.ts"), join(nodeSource, "_bindings-ffi.ts")];
187
- const legacyExports = resolve(root, values.node, "exports.ts");
188
- if (
189
- existsSync(legacyExports) &&
190
- readFileSync(legacyExports, "utf8").trim() === 'export * from "./src/bindings.ts";'
191
- ) {
192
- makeWritable(legacyExports);
193
- rmSync(legacyExports, { force: true });
194
- }
195
- replaceGenerated(join(nodeOutput, "index.ts"), nodeBindings);
196
- replaceGenerated(join(nodeOutput, libraryName + ".ts"), generatedFiles[0]);
197
- replaceGenerated(join(nodeOutput, libraryName + "-ffi.ts"), generatedFiles[1]);
198
- writeFileSync(
199
- nodeBindings,
200
- readFileSync(nodeBindings, "utf8").replaceAll("./" + libraryName, "./_bindings"),
201
- );
202
- writeFileSync(
203
- generatedFiles[0],
204
- readFileSync(generatedFiles[0], "utf8").replaceAll(
205
- "./" + libraryName + "-ffi",
206
- "./_bindings-ffi",
207
- ),
208
- );
209
- for (const file of generatedFiles) {
210
- writeFileSync(
211
- file,
212
- removeObsoleteInterfaceAliases(
213
- makeDefaultedInterfaceParametersOptional(readFileSync(file, "utf8")),
214
- ),
215
- );
216
- }
217
- writeFileSync(
218
- nodeBindings,
219
- addExplicitInterfaceReexports(
220
- readFileSync(nodeBindings, "utf8"),
221
- generatedFiles.map((file) => ({
222
- specifier: `./${basename(file, ".ts")}`,
223
- source: readFileSync(file, "utf8"),
224
- })),
225
- ),
226
- );
227
- for (const file of [nodeBindings, ...generatedFiles]) {
228
- // Consumers type-check these files through workspace source exports, while
229
- // the generated runtime internals are validated by UniFFI's own build.
230
- const source = addTypeScriptExtensionsToBindingImports(readFileSync(file, "utf8")).replace(
231
- /[ \t]+$/gm,
232
- "",
233
- );
234
- writeFileSync(file, `/* eslint-disable */\n// @ts-nocheck\n${source}`);
235
- stampGenerated(file, {
236
- tool: "UniFFI binding generation",
237
- source: `the ${crate} Rust exports`,
238
- });
239
- }
240
- if (!values["node-package-base"]) {
241
- const nodeLibrary = join(nodeSource, basename(library));
242
- makeWritable(nodeLibrary);
243
- cpSync(library, nodeLibrary);
244
- makeReadonly(nodeLibrary);
245
- }
246
- rmSync(resolve(root, values.node, "src/generated"), { recursive: true, force: true });
247
- rmSync(nodeOutput, { recursive: true, force: true });
248
- if (!values["skip-barrels"]) {
249
- run(process.execPath, [
250
- resolve(dirname(fileURLToPath(import.meta.url)), "barrels.ts"),
251
- "--dir",
252
- resolve(root, values.node),
253
- ]);
254
- }
255
- }
256
-
257
- if (values.python) {
258
- if (!values["python-module"]) {
259
- throw new Error("Expected --python-module with --python");
260
- }
261
- installPythonBindings({
262
- crate,
263
- library,
264
- module: values["python-module"],
265
- packageRoot: resolve(root, values.python),
266
- platform: process.platform,
267
- readonly: true,
268
- run,
269
- targetDirectory,
270
- });
271
- }