@fluojs/cli 1.0.0-beta.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/README.ko.md +155 -0
- package/README.md +155 -0
- package/bin/fluo.mjs +5 -0
- package/dist/cli.d.ts +37 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +292 -0
- package/dist/commands/generate.d.ts +40 -0
- package/dist/commands/generate.d.ts.map +1 -0
- package/dist/commands/generate.js +134 -0
- package/dist/commands/inspect.d.ts +30 -0
- package/dist/commands/inspect.d.ts.map +1 -0
- package/dist/commands/inspect.js +221 -0
- package/dist/commands/migrate.d.ts +30 -0
- package/dist/commands/migrate.d.ts.map +1 -0
- package/dist/commands/migrate.js +173 -0
- package/dist/commands/new.d.ts +45 -0
- package/dist/commands/new.d.ts.map +1 -0
- package/dist/commands/new.js +353 -0
- package/dist/generator-types.d.ts +21 -0
- package/dist/generator-types.d.ts.map +1 -0
- package/dist/generator-types.js +1 -0
- package/dist/generators/controller.d.ts +3 -0
- package/dist/generators/controller.d.ts.map +1 -0
- package/dist/generators/controller.js +22 -0
- package/dist/generators/guard.d.ts +3 -0
- package/dist/generators/guard.d.ts.map +1 -0
- package/dist/generators/guard.js +15 -0
- package/dist/generators/interceptor.d.ts +3 -0
- package/dist/generators/interceptor.d.ts.map +1 -0
- package/dist/generators/interceptor.js +15 -0
- package/dist/generators/manifest.d.ts +121 -0
- package/dist/generators/manifest.d.ts.map +1 -0
- package/dist/generators/manifest.js +130 -0
- package/dist/generators/middleware.d.ts +3 -0
- package/dist/generators/middleware.d.ts.map +1 -0
- package/dist/generators/middleware.js +15 -0
- package/dist/generators/module.d.ts +6 -0
- package/dist/generators/module.d.ts.map +1 -0
- package/dist/generators/module.js +143 -0
- package/dist/generators/render.d.ts +2 -0
- package/dist/generators/render.d.ts.map +1 -0
- package/dist/generators/render.js +17 -0
- package/dist/generators/repository.d.ts +3 -0
- package/dist/generators/repository.d.ts.map +1 -0
- package/dist/generators/repository.js +29 -0
- package/dist/generators/request-dto.d.ts +3 -0
- package/dist/generators/request-dto.d.ts.map +1 -0
- package/dist/generators/request-dto.js +17 -0
- package/dist/generators/response-dto.d.ts +3 -0
- package/dist/generators/response-dto.d.ts.map +1 -0
- package/dist/generators/response-dto.js +17 -0
- package/dist/generators/service.d.ts +3 -0
- package/dist/generators/service.d.ts.map +1 -0
- package/dist/generators/service.js +22 -0
- package/dist/generators/templates/controller.test.ts.ejs +21 -0
- package/dist/generators/templates/controller.ts.ejs +29 -0
- package/dist/generators/templates/guard.ts.ejs +7 -0
- package/dist/generators/templates/interceptor.ts.ejs +7 -0
- package/dist/generators/templates/middleware.ts.ejs +11 -0
- package/dist/generators/templates/module.ts.ejs +9 -0
- package/dist/generators/templates/repository.slice.test.ts.ejs +15 -0
- package/dist/generators/templates/repository.test.ts.ejs +9 -0
- package/dist/generators/templates/repository.ts.ejs +10 -0
- package/dist/generators/templates/request-dto.ts.ejs +9 -0
- package/dist/generators/templates/response-dto.ts.ejs +3 -0
- package/dist/generators/templates/service.test.ts.ejs +21 -0
- package/dist/generators/templates/service.ts.ejs +24 -0
- package/dist/generators/utils.d.ts +4 -0
- package/dist/generators/utils.d.ts.map +1 -0
- package/dist/generators/utils.js +18 -0
- package/dist/help.d.ts +8 -0
- package/dist/help.d.ts.map +1 -0
- package/dist/help.js +16 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +2 -0
- package/dist/new/install.d.ts +51 -0
- package/dist/new/install.d.ts.map +1 -0
- package/dist/new/install.js +140 -0
- package/dist/new/package-spec-resolver.d.ts +4 -0
- package/dist/new/package-spec-resolver.d.ts.map +1 -0
- package/dist/new/package-spec-resolver.js +397 -0
- package/dist/new/prompt.d.ts +56 -0
- package/dist/new/prompt.d.ts.map +1 -0
- package/dist/new/prompt.js +278 -0
- package/dist/new/resolver.d.ts +32 -0
- package/dist/new/resolver.d.ts.map +1 -0
- package/dist/new/resolver.js +93 -0
- package/dist/new/scaffold.d.ts +14 -0
- package/dist/new/scaffold.d.ts.map +1 -0
- package/dist/new/scaffold.js +2010 -0
- package/dist/new/starter-profiles.d.ts +91 -0
- package/dist/new/starter-profiles.d.ts.map +1 -0
- package/dist/new/starter-profiles.js +347 -0
- package/dist/new/types.d.ts +63 -0
- package/dist/new/types.d.ts.map +1 -0
- package/dist/new/types.js +1 -0
- package/dist/registry.d.ts +10 -0
- package/dist/registry.d.ts.map +1 -0
- package/dist/registry.js +30 -0
- package/dist/transforms/nestjs-migrate.d.ts +33 -0
- package/dist/transforms/nestjs-migrate.d.ts.map +1 -0
- package/dist/transforms/nestjs-migrate.js +891 -0
- package/dist/types.d.ts +12 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +1 -0
- package/package.json +65 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../../src/generators/utils.ts"],"names":[],"mappings":"AAAA,wBAAgB,WAAW,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAMjD;AAED,wBAAgB,YAAY,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAMlD;AAED,wBAAgB,QAAQ,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAa9C"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
export function toKebabCase(value) {
|
|
2
|
+
return value.replace(/([a-z0-9])([A-Z])/g, '$1-$2').replace(/[_\s]+/g, '-').replace(/-+/g, '-').toLowerCase();
|
|
3
|
+
}
|
|
4
|
+
export function toPascalCase(value) {
|
|
5
|
+
return toKebabCase(value).split('-').filter(Boolean).map(segment => segment[0].toUpperCase() + segment.slice(1)).join('');
|
|
6
|
+
}
|
|
7
|
+
export function toPlural(value) {
|
|
8
|
+
if (value.endsWith('s') || value.endsWith('x') || value.endsWith('z') || value.endsWith('ch') || value.endsWith('sh')) {
|
|
9
|
+
return `${value}es`;
|
|
10
|
+
}
|
|
11
|
+
if (value.endsWith('y') && value.length > 1) {
|
|
12
|
+
const beforeY = value[value.length - 2];
|
|
13
|
+
if (!'aeiou'.includes(beforeY)) {
|
|
14
|
+
return `${value.slice(0, -1)}ies`;
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
return `${value}s`;
|
|
18
|
+
}
|
package/dist/help.d.ts
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
type HelpTableColumn<Row> = {
|
|
2
|
+
header: string;
|
|
3
|
+
render: (row: Row) => string;
|
|
4
|
+
};
|
|
5
|
+
export declare function renderAliasList(aliases: string[]): string;
|
|
6
|
+
export declare function renderHelpTable<Row>(rows: Row[], columns: HelpTableColumn<Row>[]): string;
|
|
7
|
+
export {};
|
|
8
|
+
//# sourceMappingURL=help.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"help.d.ts","sourceRoot":"","sources":["../src/help.ts"],"names":[],"mappings":"AAAA,KAAK,eAAe,CAAC,GAAG,IAAI;IAC1B,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,CAAC,GAAG,EAAE,GAAG,KAAK,MAAM,CAAC;CAC9B,CAAC;AAUF,wBAAgB,eAAe,CAAC,OAAO,EAAE,MAAM,EAAE,GAAG,MAAM,CAEzD;AAED,wBAAgB,eAAe,CAAC,GAAG,EAAE,IAAI,EAAE,GAAG,EAAE,EAAE,OAAO,EAAE,eAAe,CAAC,GAAG,CAAC,EAAE,GAAG,MAAM,CAazF"}
|
package/dist/help.js
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
function border(widths) {
|
|
2
|
+
return `+${widths.map(width => '-'.repeat(width + 2)).join('+')}+`;
|
|
3
|
+
}
|
|
4
|
+
function renderRow(values, widths) {
|
|
5
|
+
return `| ${values.map((value, index) => value.padEnd(widths[index] ?? 0)).join(' | ')} |`;
|
|
6
|
+
}
|
|
7
|
+
export function renderAliasList(aliases) {
|
|
8
|
+
return aliases.length === 0 ? '-' : aliases.join(', ');
|
|
9
|
+
}
|
|
10
|
+
export function renderHelpTable(rows, columns) {
|
|
11
|
+
const widths = columns.map(column => {
|
|
12
|
+
const values = rows.map(row => column.render(row));
|
|
13
|
+
return Math.max(column.header.length, ...values.map(value => value.length));
|
|
14
|
+
});
|
|
15
|
+
return [border(widths), renderRow(columns.map(column => column.header), widths), border(widths), ...rows.map(row => renderRow(columns.map(column => column.render(row)), widths)), border(widths)].join('\n');
|
|
16
|
+
}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
export { runCli, type CliRuntimeOptions } from './cli.js';
|
|
2
|
+
export { newUsage, runNewCommand, type NewCommandRuntimeOptions } from './commands/new.js';
|
|
3
|
+
export type { GenerateOptions, GeneratedFile, GeneratorKind, ModuleRegistration } from './types.js';
|
|
4
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,KAAK,iBAAiB,EAAE,MAAM,UAAU,CAAC;AAC1D,OAAO,EAAE,QAAQ,EAAE,aAAa,EAAE,KAAK,wBAAwB,EAAE,MAAM,mBAAmB,CAAC;AAC3F,YAAY,EAAE,eAAe,EAAE,aAAa,EAAE,aAAa,EAAE,kBAAkB,EAAE,MAAM,YAAY,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import type { PackageManager } from './types.js';
|
|
2
|
+
/** Concrete command invocation used for dependency installation. */
|
|
3
|
+
export interface InstallCommand {
|
|
4
|
+
args: string[];
|
|
5
|
+
command: string;
|
|
6
|
+
}
|
|
7
|
+
/** Runtime overrides for resolving install commands in tests. */
|
|
8
|
+
export interface ResolveInstallCommandOptions {
|
|
9
|
+
isCorepackAvailable?: boolean;
|
|
10
|
+
}
|
|
11
|
+
/** Runtime overrides for git initialization in tests. */
|
|
12
|
+
export interface InitializeGitRepositoryOptions {
|
|
13
|
+
command?: string;
|
|
14
|
+
}
|
|
15
|
+
type WritableStream = {
|
|
16
|
+
write(message: string): unknown;
|
|
17
|
+
};
|
|
18
|
+
type InstallStdioMode = 'capture' | 'inherit';
|
|
19
|
+
type InstallDependenciesOptions = {
|
|
20
|
+
env?: NodeJS.ProcessEnv;
|
|
21
|
+
isCorepackAvailable?: boolean;
|
|
22
|
+
stderr?: WritableStream;
|
|
23
|
+
stdio?: InstallStdioMode;
|
|
24
|
+
};
|
|
25
|
+
/**
|
|
26
|
+
* Resolves the concrete install command for a chosen package manager.
|
|
27
|
+
*
|
|
28
|
+
* @param packageManager Package manager selected for the generated starter.
|
|
29
|
+
* @param options Runtime overrides for command detection in tests.
|
|
30
|
+
* @returns The command and argument list to execute.
|
|
31
|
+
*/
|
|
32
|
+
export declare function resolveInstallCommand(packageManager: PackageManager, options?: ResolveInstallCommandOptions): InstallCommand;
|
|
33
|
+
/**
|
|
34
|
+
* Installs starter dependencies in the generated project directory.
|
|
35
|
+
*
|
|
36
|
+
* @param targetDirectory Generated project directory.
|
|
37
|
+
* @param packageManager Package manager selected for the generated starter.
|
|
38
|
+
* @param options Runtime overrides for install execution and diagnostics.
|
|
39
|
+
* @returns A promise that resolves when installation succeeds.
|
|
40
|
+
*/
|
|
41
|
+
export declare function installDependencies(targetDirectory: string, packageManager: PackageManager, options?: InstallDependenciesOptions): Promise<void>;
|
|
42
|
+
/**
|
|
43
|
+
* Initializes a git repository in the generated project directory.
|
|
44
|
+
*
|
|
45
|
+
* @param targetDirectory Generated project directory.
|
|
46
|
+
* @param options Runtime overrides for invoking git in tests.
|
|
47
|
+
* @returns A promise that resolves when repository initialization succeeds.
|
|
48
|
+
*/
|
|
49
|
+
export declare function initializeGitRepository(targetDirectory: string, options?: InitializeGitRepositoryOptions): Promise<void>;
|
|
50
|
+
export {};
|
|
51
|
+
//# sourceMappingURL=install.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"install.d.ts","sourceRoot":"","sources":["../../src/new/install.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAEjD,oEAAoE;AACpE,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,MAAM,EAAE,CAAC;IACf,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,iEAAiE;AACjE,MAAM,WAAW,4BAA4B;IAC3C,mBAAmB,CAAC,EAAE,OAAO,CAAC;CAC/B;AAED,yDAAyD;AACzD,MAAM,WAAW,8BAA8B;IAC7C,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,KAAK,cAAc,GAAG;IACpB,KAAK,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC;CACjC,CAAC;AAEF,KAAK,gBAAgB,GAAG,SAAS,GAAG,SAAS,CAAC;AAE9C,KAAK,0BAA0B,GAAG;IAChC,GAAG,CAAC,EAAE,MAAM,CAAC,UAAU,CAAC;IACxB,mBAAmB,CAAC,EAAE,OAAO,CAAC;IAC9B,MAAM,CAAC,EAAE,cAAc,CAAC;IACxB,KAAK,CAAC,EAAE,gBAAgB,CAAC;CAC1B,CAAC;AAmDF;;;;;;GAMG;AACH,wBAAgB,qBAAqB,CACnC,cAAc,EAAE,cAAc,EAC9B,OAAO,GAAE,4BAAiC,GACzC,cAAc,CA4BhB;AAED;;;;;;;GAOG;AACH,wBAAsB,mBAAmB,CACvC,eAAe,EAAE,MAAM,EACvB,cAAc,EAAE,cAAc,EAC9B,OAAO,GAAE,0BAA+B,GACvC,OAAO,CAAC,IAAI,CAAC,CAmCf;AAED;;;;;;GAMG;AACH,wBAAsB,uBAAuB,CAC3C,eAAe,EAAE,MAAM,EACvB,OAAO,GAAE,8BAAmC,GAC3C,OAAO,CAAC,IAAI,CAAC,CAmBf"}
|
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
import { spawn, spawnSync } from 'node:child_process';
|
|
2
|
+
|
|
3
|
+
/** Concrete command invocation used for dependency installation. */
|
|
4
|
+
|
|
5
|
+
/** Runtime overrides for resolving install commands in tests. */
|
|
6
|
+
|
|
7
|
+
/** Runtime overrides for git initialization in tests. */
|
|
8
|
+
|
|
9
|
+
const COREPACK_DOCS_URL = 'https://nodejs.org/api/corepack.html';
|
|
10
|
+
class DependencyInstallationError extends Error {
|
|
11
|
+
output;
|
|
12
|
+
constructor(exitCode, output) {
|
|
13
|
+
super(exitCode === null ? 'Dependency installation failed without an exit code.' : `Dependency installation failed with exit code ${exitCode}.`);
|
|
14
|
+
this.name = 'DependencyInstallationError';
|
|
15
|
+
this.output = output;
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
function appendStreamOutput(stream, output) {
|
|
19
|
+
stream?.on('data', chunk => {
|
|
20
|
+
output.push(typeof chunk === 'string' ? chunk : chunk.toString());
|
|
21
|
+
});
|
|
22
|
+
}
|
|
23
|
+
function waitForChildProcess(child, capturedOutput) {
|
|
24
|
+
return new Promise((resolve, reject) => {
|
|
25
|
+
child.on('error', reject);
|
|
26
|
+
child.on('exit', code => {
|
|
27
|
+
if (code === 0) {
|
|
28
|
+
resolve();
|
|
29
|
+
return;
|
|
30
|
+
}
|
|
31
|
+
reject(new DependencyInstallationError(code, capturedOutput?.join('') ?? ''));
|
|
32
|
+
});
|
|
33
|
+
});
|
|
34
|
+
}
|
|
35
|
+
function checkCommandAvailability(command) {
|
|
36
|
+
const checker = process.platform === 'win32' ? 'where' : 'which';
|
|
37
|
+
const result = spawnSync(checker, [command], {
|
|
38
|
+
stdio: 'ignore'
|
|
39
|
+
});
|
|
40
|
+
return result.status === 0;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* Resolves the concrete install command for a chosen package manager.
|
|
45
|
+
*
|
|
46
|
+
* @param packageManager Package manager selected for the generated starter.
|
|
47
|
+
* @param options Runtime overrides for command detection in tests.
|
|
48
|
+
* @returns The command and argument list to execute.
|
|
49
|
+
*/
|
|
50
|
+
export function resolveInstallCommand(packageManager, options = {}) {
|
|
51
|
+
if (packageManager === 'bun') {
|
|
52
|
+
return {
|
|
53
|
+
args: ['install'],
|
|
54
|
+
command: 'bun'
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
if (packageManager === 'yarn') {
|
|
58
|
+
const isCorepackAvailable = options.isCorepackAvailable ?? checkCommandAvailability('corepack');
|
|
59
|
+
if (!isCorepackAvailable) {
|
|
60
|
+
return {
|
|
61
|
+
args: ['install'],
|
|
62
|
+
command: 'yarn'
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
return {
|
|
66
|
+
args: ['yarn', 'install'],
|
|
67
|
+
command: 'corepack'
|
|
68
|
+
};
|
|
69
|
+
}
|
|
70
|
+
return {
|
|
71
|
+
args: ['install'],
|
|
72
|
+
command: packageManager
|
|
73
|
+
};
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* Installs starter dependencies in the generated project directory.
|
|
78
|
+
*
|
|
79
|
+
* @param targetDirectory Generated project directory.
|
|
80
|
+
* @param packageManager Package manager selected for the generated starter.
|
|
81
|
+
* @param options Runtime overrides for install execution and diagnostics.
|
|
82
|
+
* @returns A promise that resolves when installation succeeds.
|
|
83
|
+
*/
|
|
84
|
+
export async function installDependencies(targetDirectory, packageManager, options = {}) {
|
|
85
|
+
const hasCorepack = packageManager === 'yarn' ? options.isCorepackAvailable ?? checkCommandAvailability('corepack') : undefined;
|
|
86
|
+
const {
|
|
87
|
+
args,
|
|
88
|
+
command
|
|
89
|
+
} = resolveInstallCommand(packageManager, {
|
|
90
|
+
isCorepackAvailable: hasCorepack
|
|
91
|
+
});
|
|
92
|
+
if (packageManager === 'yarn' && hasCorepack === false) {
|
|
93
|
+
const message = `[fluo] corepack was not found in PATH, falling back to "yarn install". See ${COREPACK_DOCS_URL}\n`;
|
|
94
|
+
(options.stderr ?? process.stderr).write(message);
|
|
95
|
+
}
|
|
96
|
+
const stdio = options.stdio ?? 'inherit';
|
|
97
|
+
if (stdio === 'capture') {
|
|
98
|
+
const capturedOutput = [];
|
|
99
|
+
const child = spawn(command, args, {
|
|
100
|
+
cwd: targetDirectory,
|
|
101
|
+
env: options.env,
|
|
102
|
+
stdio: ['ignore', 'pipe', 'pipe']
|
|
103
|
+
});
|
|
104
|
+
appendStreamOutput(child.stdout, capturedOutput);
|
|
105
|
+
appendStreamOutput(child.stderr, capturedOutput);
|
|
106
|
+
await waitForChildProcess(child, capturedOutput);
|
|
107
|
+
return;
|
|
108
|
+
}
|
|
109
|
+
const child = spawn(command, args, {
|
|
110
|
+
cwd: targetDirectory,
|
|
111
|
+
env: options.env,
|
|
112
|
+
stdio: 'inherit'
|
|
113
|
+
});
|
|
114
|
+
await waitForChildProcess(child);
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
/**
|
|
118
|
+
* Initializes a git repository in the generated project directory.
|
|
119
|
+
*
|
|
120
|
+
* @param targetDirectory Generated project directory.
|
|
121
|
+
* @param options Runtime overrides for invoking git in tests.
|
|
122
|
+
* @returns A promise that resolves when repository initialization succeeds.
|
|
123
|
+
*/
|
|
124
|
+
export async function initializeGitRepository(targetDirectory, options = {}) {
|
|
125
|
+
const command = options.command ?? 'git';
|
|
126
|
+
await new Promise((resolve, reject) => {
|
|
127
|
+
const child = spawn(command, ['init'], {
|
|
128
|
+
cwd: targetDirectory,
|
|
129
|
+
stdio: 'inherit'
|
|
130
|
+
});
|
|
131
|
+
child.on('error', reject);
|
|
132
|
+
child.on('exit', code => {
|
|
133
|
+
if (code === 0) {
|
|
134
|
+
resolve();
|
|
135
|
+
return;
|
|
136
|
+
}
|
|
137
|
+
reject(new Error(`Git initialization failed with exit code ${code}.`));
|
|
138
|
+
});
|
|
139
|
+
});
|
|
140
|
+
}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import type { ResolvedBootstrapPlan } from './resolver.js';
|
|
2
|
+
import type { BootstrapOptions } from './types.js';
|
|
3
|
+
export declare function resolvePackageSpecs(options: BootstrapOptions, bootstrapPlan: ResolvedBootstrapPlan): Promise<Record<string, string>>;
|
|
4
|
+
//# sourceMappingURL=package-spec-resolver.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"package-spec-resolver.d.ts","sourceRoot":"","sources":["../../src/new/package-spec-resolver.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,eAAe,CAAC;AAC3D,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AAkhBnD,wBAAsB,mBAAmB,CACvC,OAAO,EAAE,gBAAgB,EACzB,aAAa,EAAE,qBAAqB,GACnC,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAgCjC"}
|
|
@@ -0,0 +1,397 @@
|
|
|
1
|
+
import { execFileSync, spawn } from 'node:child_process';
|
|
2
|
+
import { createHash } from 'node:crypto';
|
|
3
|
+
import { cpSync, existsSync, mkdirSync, readdirSync, readFileSync, rmSync, statSync, writeFileSync } from 'node:fs';
|
|
4
|
+
import { tmpdir } from 'node:os';
|
|
5
|
+
import { join, resolve } from 'node:path';
|
|
6
|
+
const PACKAGE_DIRECTORY_BY_NAME = {
|
|
7
|
+
'@fluojs/platform-bun': 'platform-bun',
|
|
8
|
+
'@fluojs/cli': 'cli',
|
|
9
|
+
'@fluojs/config': 'config',
|
|
10
|
+
'@fluojs/core': 'core',
|
|
11
|
+
'@fluojs/di': 'di',
|
|
12
|
+
'@fluojs/http': 'http',
|
|
13
|
+
'@fluojs/platform-cloudflare-workers': 'platform-cloudflare-workers',
|
|
14
|
+
'@fluojs/platform-deno': 'platform-deno',
|
|
15
|
+
'@fluojs/microservices': 'microservices',
|
|
16
|
+
'@fluojs/platform-express': 'platform-express',
|
|
17
|
+
'@fluojs/platform-fastify': 'platform-fastify',
|
|
18
|
+
'@fluojs/platform-nodejs': 'platform-nodejs',
|
|
19
|
+
'@fluojs/runtime': 'runtime',
|
|
20
|
+
'@fluojs/testing': 'testing',
|
|
21
|
+
'@fluojs/validation': 'validation'
|
|
22
|
+
};
|
|
23
|
+
const LOCAL_PACKAGE_CACHE_DIR = join(tmpdir(), 'fluo-cli-local-packages');
|
|
24
|
+
const LOCAL_PACKAGE_CACHE_STAMP_FILE = 'cache-stamp.json';
|
|
25
|
+
const LOCAL_PACKAGE_CACHE_FORMAT_VERSION = 2;
|
|
26
|
+
function expectedTarballName(packageName, version) {
|
|
27
|
+
return `${packageName.replace(/^@/, '').replace(/\//g, '-')}-${version}.tgz`;
|
|
28
|
+
}
|
|
29
|
+
function readLocalPackageVersion(repoRoot, packageName) {
|
|
30
|
+
const packageDirectory = PACKAGE_DIRECTORY_BY_NAME[packageName];
|
|
31
|
+
const packageJson = JSON.parse(readFileSync(join(repoRoot, 'packages', packageDirectory, 'package.json'), 'utf8'));
|
|
32
|
+
return packageJson.version;
|
|
33
|
+
}
|
|
34
|
+
function readLocalPackageManifest(repoRoot, packageName) {
|
|
35
|
+
const packageDirectory = PACKAGE_DIRECTORY_BY_NAME[packageName];
|
|
36
|
+
return JSON.parse(readFileSync(join(repoRoot, 'packages', packageDirectory, 'package.json'), 'utf8'));
|
|
37
|
+
}
|
|
38
|
+
function collectRequiredLocalPackages(repoRoot, bootstrapPlan) {
|
|
39
|
+
const pending = [...bootstrapPlan.dependencies.dependencies, ...bootstrapPlan.dependencies.devDependencies].filter(packageName => packageName in PACKAGE_DIRECTORY_BY_NAME);
|
|
40
|
+
const selected = new Set();
|
|
41
|
+
while (pending.length > 0) {
|
|
42
|
+
const packageName = pending.pop();
|
|
43
|
+
if (!packageName || selected.has(packageName)) {
|
|
44
|
+
continue;
|
|
45
|
+
}
|
|
46
|
+
selected.add(packageName);
|
|
47
|
+
const manifest = readLocalPackageManifest(repoRoot, packageName);
|
|
48
|
+
for (const section of ['dependencies', 'optionalDependencies', 'peerDependencies']) {
|
|
49
|
+
const dependencies = manifest[section];
|
|
50
|
+
if (!dependencies) {
|
|
51
|
+
continue;
|
|
52
|
+
}
|
|
53
|
+
for (const dependencyName of Object.keys(dependencies)) {
|
|
54
|
+
if (dependencyName in PACKAGE_DIRECTORY_BY_NAME) {
|
|
55
|
+
pending.push(dependencyName);
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
return Array.from(selected);
|
|
61
|
+
}
|
|
62
|
+
function collectLocalPackageVersions(repoRoot, packageNames) {
|
|
63
|
+
const packageVersions = new Map();
|
|
64
|
+
for (const packageName of packageNames) {
|
|
65
|
+
packageVersions.set(packageName, readLocalPackageVersion(repoRoot, packageName));
|
|
66
|
+
}
|
|
67
|
+
return packageVersions;
|
|
68
|
+
}
|
|
69
|
+
function getPackageVersionOrThrow(packageVersions, packageName) {
|
|
70
|
+
const packageVersion = packageVersions.get(packageName);
|
|
71
|
+
if (!packageVersion) {
|
|
72
|
+
throw new Error(`Unable to determine version for ${packageName}.`);
|
|
73
|
+
}
|
|
74
|
+
return packageVersion;
|
|
75
|
+
}
|
|
76
|
+
function toPackageVersionRecord(packageVersions) {
|
|
77
|
+
const packageVersionRecord = {};
|
|
78
|
+
for (const [packageName, packageVersion] of packageVersions.entries()) {
|
|
79
|
+
packageVersionRecord[packageName] = packageVersion;
|
|
80
|
+
}
|
|
81
|
+
return packageVersionRecord;
|
|
82
|
+
}
|
|
83
|
+
function runGitCommand(repoRoot, args) {
|
|
84
|
+
try {
|
|
85
|
+
return execFileSync('git', args, {
|
|
86
|
+
cwd: repoRoot,
|
|
87
|
+
encoding: 'utf8',
|
|
88
|
+
stdio: ['ignore', 'pipe', 'ignore']
|
|
89
|
+
}).trim();
|
|
90
|
+
} catch {
|
|
91
|
+
return undefined;
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
function createPackagePathArguments(packageNames) {
|
|
95
|
+
const packagePaths = new Set();
|
|
96
|
+
for (const packageName of packageNames) {
|
|
97
|
+
const packageDirectory = PACKAGE_DIRECTORY_BY_NAME[packageName];
|
|
98
|
+
const packageRoot = join('packages', packageDirectory);
|
|
99
|
+
packagePaths.add(packageRoot);
|
|
100
|
+
packagePaths.add(join(packageRoot, 'src'));
|
|
101
|
+
packagePaths.add(join(packageRoot, 'package.json'));
|
|
102
|
+
packagePaths.add(join(packageRoot, 'tsconfig.json'));
|
|
103
|
+
packagePaths.add(join(packageRoot, 'tsconfig.build.json'));
|
|
104
|
+
}
|
|
105
|
+
return Array.from(packagePaths);
|
|
106
|
+
}
|
|
107
|
+
function copyIfExists(sourcePath, destinationPath) {
|
|
108
|
+
if (!existsSync(sourcePath)) {
|
|
109
|
+
return;
|
|
110
|
+
}
|
|
111
|
+
cpSync(sourcePath, destinationPath, {
|
|
112
|
+
recursive: true
|
|
113
|
+
});
|
|
114
|
+
}
|
|
115
|
+
function collectPackageStagePaths(packageRoot, manifest) {
|
|
116
|
+
const stagePaths = new Set();
|
|
117
|
+
for (const fixedPath of ['README.md', 'README.ko.md', 'LICENSE', 'LICENSE.md', 'LICENSE.txt']) {
|
|
118
|
+
if (existsSync(join(packageRoot, fixedPath))) {
|
|
119
|
+
stagePaths.add(fixedPath);
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
for (const fileEntry of manifest.files ?? []) {
|
|
123
|
+
if (existsSync(join(packageRoot, fileEntry))) {
|
|
124
|
+
stagePaths.add(fileEntry);
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
if (typeof manifest.bin === 'string') {
|
|
128
|
+
stagePaths.add(manifest.bin);
|
|
129
|
+
} else if (manifest.bin) {
|
|
130
|
+
for (const binPath of Object.values(manifest.bin)) {
|
|
131
|
+
stagePaths.add(binPath);
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
if (manifest.main) {
|
|
135
|
+
stagePaths.add(manifest.main);
|
|
136
|
+
}
|
|
137
|
+
if (manifest.types) {
|
|
138
|
+
stagePaths.add(manifest.types);
|
|
139
|
+
}
|
|
140
|
+
return Array.from(stagePaths);
|
|
141
|
+
}
|
|
142
|
+
function stagePackageForPacking(repoRoot, packageName, packageVersions, outputDirectory) {
|
|
143
|
+
const packageDirectory = PACKAGE_DIRECTORY_BY_NAME[packageName];
|
|
144
|
+
const packageRoot = join(repoRoot, 'packages', packageDirectory);
|
|
145
|
+
const stageDirectory = join(outputDirectory, `.stage-${packageDirectory}`);
|
|
146
|
+
const manifest = JSON.parse(readFileSync(join(packageRoot, 'package.json'), 'utf8'));
|
|
147
|
+
rmSync(stageDirectory, {
|
|
148
|
+
force: true,
|
|
149
|
+
recursive: true
|
|
150
|
+
});
|
|
151
|
+
mkdirSync(stageDirectory, {
|
|
152
|
+
recursive: true
|
|
153
|
+
});
|
|
154
|
+
for (const relativePath of collectPackageStagePaths(packageRoot, manifest)) {
|
|
155
|
+
copyIfExists(join(packageRoot, relativePath), join(stageDirectory, relativePath));
|
|
156
|
+
}
|
|
157
|
+
rewriteWorkspaceProtocolDependencies(manifest, packageVersions);
|
|
158
|
+
writeFileSync(join(stageDirectory, 'package.json'), `${JSON.stringify(manifest, null, 2)}\n`, 'utf8');
|
|
159
|
+
return stageDirectory;
|
|
160
|
+
}
|
|
161
|
+
function computeLocalPackageCacheStamp(repoRoot, packageNames, packageVersions) {
|
|
162
|
+
const headCommit = runGitCommand(repoRoot, ['rev-parse', 'HEAD']);
|
|
163
|
+
if (!headCommit) {
|
|
164
|
+
return undefined;
|
|
165
|
+
}
|
|
166
|
+
const packagePaths = createPackagePathArguments(packageNames);
|
|
167
|
+
const dirtyFingerprint = runGitCommand(repoRoot, ['status', '--porcelain', '--', ...packagePaths]);
|
|
168
|
+
if (dirtyFingerprint === undefined) {
|
|
169
|
+
return undefined;
|
|
170
|
+
}
|
|
171
|
+
return {
|
|
172
|
+
cacheFormatVersion: LOCAL_PACKAGE_CACHE_FORMAT_VERSION,
|
|
173
|
+
dirtyFingerprint,
|
|
174
|
+
headCommit,
|
|
175
|
+
packageVersions: toPackageVersionRecord(packageVersions)
|
|
176
|
+
};
|
|
177
|
+
}
|
|
178
|
+
function readLocalPackageCacheStamp(stampPath) {
|
|
179
|
+
if (!existsSync(stampPath)) {
|
|
180
|
+
return undefined;
|
|
181
|
+
}
|
|
182
|
+
try {
|
|
183
|
+
return JSON.parse(readFileSync(stampPath, 'utf8'));
|
|
184
|
+
} catch {
|
|
185
|
+
return undefined;
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
function cacheStampMatches(expected, actual) {
|
|
189
|
+
if (!actual) {
|
|
190
|
+
return false;
|
|
191
|
+
}
|
|
192
|
+
if (actual.cacheFormatVersion !== LOCAL_PACKAGE_CACHE_FORMAT_VERSION) {
|
|
193
|
+
return false;
|
|
194
|
+
}
|
|
195
|
+
if (actual.headCommit !== expected.headCommit || actual.dirtyFingerprint !== expected.dirtyFingerprint) {
|
|
196
|
+
return false;
|
|
197
|
+
}
|
|
198
|
+
for (const [packageName, packageVersion] of Object.entries(expected.packageVersions)) {
|
|
199
|
+
if (actual.packageVersions[packageName] !== packageVersion) {
|
|
200
|
+
return false;
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
return true;
|
|
204
|
+
}
|
|
205
|
+
function cacheContainsTarballs(outputDirectory, packageNames, packageVersions) {
|
|
206
|
+
const packedFiles = new Set(readdirSync(outputDirectory));
|
|
207
|
+
return packageNames.every(packageName => {
|
|
208
|
+
const packageVersion = getPackageVersionOrThrow(packageVersions, packageName);
|
|
209
|
+
const tarball = expectedTarballName(packageName, packageVersion);
|
|
210
|
+
return packedFiles.has(tarball);
|
|
211
|
+
});
|
|
212
|
+
}
|
|
213
|
+
function clearLocalPackageCacheArtifacts(outputDirectory) {
|
|
214
|
+
if (!existsSync(outputDirectory)) {
|
|
215
|
+
return;
|
|
216
|
+
}
|
|
217
|
+
for (const entry of readdirSync(outputDirectory, {
|
|
218
|
+
withFileTypes: true
|
|
219
|
+
})) {
|
|
220
|
+
if (entry.name === LOCAL_PACKAGE_CACHE_STAMP_FILE) {
|
|
221
|
+
continue;
|
|
222
|
+
}
|
|
223
|
+
if (entry.isDirectory() || entry.name.endsWith('.tgz')) {
|
|
224
|
+
rmSync(join(outputDirectory, entry.name), {
|
|
225
|
+
force: true,
|
|
226
|
+
recursive: true
|
|
227
|
+
});
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
function createLocalPackageCachePath(repoRoot) {
|
|
232
|
+
const repoCacheKey = createHash('sha1').update(resolve(repoRoot)).digest('hex').slice(0, 12);
|
|
233
|
+
return join(LOCAL_PACKAGE_CACHE_DIR, repoCacheKey);
|
|
234
|
+
}
|
|
235
|
+
function latestModifiedTimeMs(path) {
|
|
236
|
+
const stats = statSync(path);
|
|
237
|
+
if (!stats.isDirectory()) {
|
|
238
|
+
return stats.mtimeMs;
|
|
239
|
+
}
|
|
240
|
+
let latest = stats.mtimeMs;
|
|
241
|
+
for (const entry of readdirSync(path, {
|
|
242
|
+
withFileTypes: true
|
|
243
|
+
})) {
|
|
244
|
+
const entryPath = join(path, entry.name);
|
|
245
|
+
latest = Math.max(latest, latestModifiedTimeMs(entryPath));
|
|
246
|
+
}
|
|
247
|
+
return latest;
|
|
248
|
+
}
|
|
249
|
+
function packageHasOutdatedBuildOutput(repoRoot, packageName) {
|
|
250
|
+
const packageDirectory = PACKAGE_DIRECTORY_BY_NAME[packageName];
|
|
251
|
+
const packageRoot = join(repoRoot, 'packages', packageDirectory);
|
|
252
|
+
const distDirectory = join(packageRoot, 'dist');
|
|
253
|
+
if (!existsSync(distDirectory)) {
|
|
254
|
+
return true;
|
|
255
|
+
}
|
|
256
|
+
const sourceCandidates = [join(packageRoot, 'src'), join(packageRoot, 'package.json'), join(packageRoot, 'tsconfig.json'), join(packageRoot, 'tsconfig.build.json')];
|
|
257
|
+
let latestSource = 0;
|
|
258
|
+
for (const sourceCandidate of sourceCandidates) {
|
|
259
|
+
if (!existsSync(sourceCandidate)) {
|
|
260
|
+
continue;
|
|
261
|
+
}
|
|
262
|
+
latestSource = Math.max(latestSource, latestModifiedTimeMs(sourceCandidate));
|
|
263
|
+
}
|
|
264
|
+
const latestDist = latestModifiedTimeMs(distDirectory);
|
|
265
|
+
return latestDist < latestSource;
|
|
266
|
+
}
|
|
267
|
+
function shouldRunWorkspaceBuild(repoRoot, packageNames) {
|
|
268
|
+
return packageNames.some(packageName => packageHasOutdatedBuildOutput(repoRoot, packageName));
|
|
269
|
+
}
|
|
270
|
+
function runPackCommand(packageDirectory, outputDirectory) {
|
|
271
|
+
return new Promise((resolvePromise, reject) => {
|
|
272
|
+
const child = spawn('npm', ['pack', '--pack-destination', outputDirectory], {
|
|
273
|
+
cwd: packageDirectory,
|
|
274
|
+
stdio: 'inherit'
|
|
275
|
+
});
|
|
276
|
+
child.on('error', reject);
|
|
277
|
+
child.on('exit', code => {
|
|
278
|
+
if (code === 0) {
|
|
279
|
+
resolvePromise();
|
|
280
|
+
return;
|
|
281
|
+
}
|
|
282
|
+
reject(new Error(`Failed to pack ${packageDirectory} with exit code ${code}.`));
|
|
283
|
+
});
|
|
284
|
+
});
|
|
285
|
+
}
|
|
286
|
+
function runWorkspaceBuild(repoRoot) {
|
|
287
|
+
return new Promise((resolvePromise, reject) => {
|
|
288
|
+
const child = spawn('pnpm', ['build'], {
|
|
289
|
+
cwd: repoRoot,
|
|
290
|
+
stdio: 'inherit'
|
|
291
|
+
});
|
|
292
|
+
child.on('error', reject);
|
|
293
|
+
child.on('exit', code => {
|
|
294
|
+
if (code === 0) {
|
|
295
|
+
resolvePromise();
|
|
296
|
+
return;
|
|
297
|
+
}
|
|
298
|
+
reject(new Error(`Failed to build workspace with exit code ${code}.`));
|
|
299
|
+
});
|
|
300
|
+
});
|
|
301
|
+
}
|
|
302
|
+
async function ensureWorkspaceBuildOutput(repoRoot, packageNames) {
|
|
303
|
+
if (shouldRunWorkspaceBuild(repoRoot, packageNames)) {
|
|
304
|
+
await runWorkspaceBuild(repoRoot);
|
|
305
|
+
}
|
|
306
|
+
}
|
|
307
|
+
async function packLocalPackages(repoRoot, outputDirectory, packageNames, packageVersions) {
|
|
308
|
+
for (const packageName of packageNames) {
|
|
309
|
+
const packageVersion = getPackageVersionOrThrow(packageVersions, packageName);
|
|
310
|
+
const tarballName = expectedTarballName(packageName, packageVersion);
|
|
311
|
+
const stageDirectory = stagePackageForPacking(repoRoot, packageName, packageVersions, outputDirectory);
|
|
312
|
+
try {
|
|
313
|
+
await runPackCommand(stageDirectory, outputDirectory);
|
|
314
|
+
} finally {
|
|
315
|
+
rmSync(stageDirectory, {
|
|
316
|
+
force: true,
|
|
317
|
+
recursive: true
|
|
318
|
+
});
|
|
319
|
+
}
|
|
320
|
+
if (!existsSync(join(outputDirectory, tarballName))) {
|
|
321
|
+
throw new Error(`Unable to locate packed tarball for ${packageName}.`);
|
|
322
|
+
}
|
|
323
|
+
}
|
|
324
|
+
}
|
|
325
|
+
function createLocalTarballSpecs(outputDirectory, packageNames, packageVersions) {
|
|
326
|
+
const packedFiles = new Set(readdirSync(outputDirectory));
|
|
327
|
+
const tarballs = new Map();
|
|
328
|
+
for (const packageName of packageNames) {
|
|
329
|
+
const packageVersion = getPackageVersionOrThrow(packageVersions, packageName);
|
|
330
|
+
const tarball = expectedTarballName(packageName, packageVersion);
|
|
331
|
+
if (!packedFiles.has(tarball)) {
|
|
332
|
+
throw new Error(`Unable to locate packed tarball for ${packageName}.`);
|
|
333
|
+
}
|
|
334
|
+
tarballs.set(packageName, `file:${join(outputDirectory, tarball)}`);
|
|
335
|
+
}
|
|
336
|
+
return Object.fromEntries(tarballs);
|
|
337
|
+
}
|
|
338
|
+
function rewriteWorkspaceProtocolSpecifier(specifier, version) {
|
|
339
|
+
const workspaceRange = specifier.slice('workspace:'.length);
|
|
340
|
+
if (workspaceRange === '^') {
|
|
341
|
+
return `^${version}`;
|
|
342
|
+
}
|
|
343
|
+
if (workspaceRange === '~') {
|
|
344
|
+
return `~${version}`;
|
|
345
|
+
}
|
|
346
|
+
if (workspaceRange === '*' || workspaceRange.length === 0) {
|
|
347
|
+
return version;
|
|
348
|
+
}
|
|
349
|
+
return workspaceRange;
|
|
350
|
+
}
|
|
351
|
+
function rewriteWorkspaceProtocolDependencies(manifest, packageVersions) {
|
|
352
|
+
for (const section of ['dependencies', 'optionalDependencies', 'peerDependencies']) {
|
|
353
|
+
const dependencies = manifest[section];
|
|
354
|
+
if (!dependencies) {
|
|
355
|
+
continue;
|
|
356
|
+
}
|
|
357
|
+
for (const [packageName, specifier] of Object.entries(dependencies)) {
|
|
358
|
+
if (!specifier.startsWith('workspace:')) {
|
|
359
|
+
continue;
|
|
360
|
+
}
|
|
361
|
+
const version = packageVersions.get(packageName);
|
|
362
|
+
if (!version) {
|
|
363
|
+
continue;
|
|
364
|
+
}
|
|
365
|
+
dependencies[packageName] = rewriteWorkspaceProtocolSpecifier(specifier, version);
|
|
366
|
+
}
|
|
367
|
+
}
|
|
368
|
+
}
|
|
369
|
+
export async function resolvePackageSpecs(options, bootstrapPlan) {
|
|
370
|
+
if (options.dependencySource !== 'local' || !options.repoRoot) {
|
|
371
|
+
return {};
|
|
372
|
+
}
|
|
373
|
+
const repoRoot = resolve(options.repoRoot);
|
|
374
|
+
const outputDirectory = createLocalPackageCachePath(repoRoot);
|
|
375
|
+
const cacheStampPath = join(outputDirectory, LOCAL_PACKAGE_CACHE_STAMP_FILE);
|
|
376
|
+
mkdirSync(outputDirectory, {
|
|
377
|
+
recursive: true
|
|
378
|
+
});
|
|
379
|
+
const packageNames = collectRequiredLocalPackages(repoRoot, bootstrapPlan);
|
|
380
|
+
const packageVersions = collectLocalPackageVersions(repoRoot, packageNames);
|
|
381
|
+
const expectedCacheStamp = computeLocalPackageCacheStamp(repoRoot, packageNames, packageVersions);
|
|
382
|
+
const currentCacheStamp = readLocalPackageCacheStamp(cacheStampPath);
|
|
383
|
+
const canReuseCachedTarballs = expectedCacheStamp ? cacheStampMatches(expectedCacheStamp, currentCacheStamp) && cacheContainsTarballs(outputDirectory, packageNames, packageVersions) : false;
|
|
384
|
+
if (!canReuseCachedTarballs) {
|
|
385
|
+
await ensureWorkspaceBuildOutput(repoRoot, packageNames);
|
|
386
|
+
clearLocalPackageCacheArtifacts(outputDirectory);
|
|
387
|
+
await packLocalPackages(repoRoot, outputDirectory, packageNames, packageVersions);
|
|
388
|
+
if (expectedCacheStamp) {
|
|
389
|
+
writeFileSync(cacheStampPath, `${JSON.stringify(expectedCacheStamp, null, 2)}\n`, 'utf8');
|
|
390
|
+
} else {
|
|
391
|
+
rmSync(cacheStampPath, {
|
|
392
|
+
force: true
|
|
393
|
+
});
|
|
394
|
+
}
|
|
395
|
+
}
|
|
396
|
+
return createLocalTarballSpecs(outputDirectory, packageNames, packageVersions);
|
|
397
|
+
}
|