@mnci/cli 4.24.0 → 4.26.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/README.md CHANGED
@@ -1336,7 +1336,7 @@ already use:
1336
1336
  - **`node-function-app` overlay**: `@azure/functions` is installed for real
1337
1337
  (a plain `@nx/node:application` app has no Azure dependency by default,
1338
1338
  unlike a plugin-generated one), an HTTP-triggered `app.http(...)` sample
1339
- (v4 programming model) is written as a `src/hello/` slice (`hello.handler.ts` plus a pure `greeting.algorithm.ts` and its spec, behind an `index.ts`), `host.json` is
1339
+ (v4 programming model) is written as a `src/hello/` slice (`hello.handler.ts` adapting the transport, `greet.use-case.ts` and its spec, `greeting.contract.ts`, behind an `index.ts`; `--empty` skips the slice), `host.json` is
1340
1340
  added, and the manifest is repaired — `main: 'main.js'` (the dist shim) and
1341
1341
  `@azure/functions` added to `dependencies` for Azure's deploy-time install
1342
1342
  to find.
package/dist/cli.js CHANGED
@@ -2744,8 +2744,57 @@ function reshapeScaffoldSlice(projectRoot, name, extension, role, empty) {
2744
2744
  (0, import_node_fs5.rmSync)(libDir, { recursive: true, force: true });
2745
2745
  if (empty) {
2746
2746
  emptySlice(projectRoot, sliceDir);
2747
+ } else if (role === "use-case") {
2748
+ writeWorkedExample(sliceDir, name, esm);
2747
2749
  }
2748
2750
  }
2751
+ function writeWorkedExample(sliceDir, name, esm) {
2752
+ const suffix = esm ? ".js" : "";
2753
+ writeFileEnsured(
2754
+ (0, import_node_path5.join)(sliceDir, `${name}.contract.ts`),
2755
+ `/** What greeting someone returns. */
2756
+ export interface Greeting {
2757
+ readonly message: string
2758
+ }
2759
+ `
2760
+ );
2761
+ writeFileEnsured(
2762
+ (0, import_node_path5.join)(sliceDir, `${name}.use-case.ts`),
2763
+ `import type { Greeting } from './${name}.contract${suffix}'
2764
+
2765
+ /**
2766
+ * Greets someone by name.
2767
+ *
2768
+ * @remarks
2769
+ * A worked example of a use case: one outcome, returning a contract. Replace it
2770
+ * with your own.
2771
+ *
2772
+ * @param name - Who to greet.
2773
+ * @returns The greeting.
2774
+ */
2775
+ export function greet (name: string): Greeting {
2776
+ return { message: 'Hello, ' + name + '!' }
2777
+ }
2778
+ `
2779
+ );
2780
+ writeFileEnsured(
2781
+ (0, import_node_path5.join)(sliceDir, `${name}.use-case.spec.ts`),
2782
+ `import { greet } from './${name}.use-case${suffix}'
2783
+
2784
+ describe('greet', () => {
2785
+ it('greets by name', () => {
2786
+ expect(greet('world')).toEqual({ message: 'Hello, world!' })
2787
+ })
2788
+ })
2789
+ `
2790
+ );
2791
+ writeFileEnsured(
2792
+ (0, import_node_path5.join)(sliceDir, "index.ts"),
2793
+ `export * from './${name}.contract${suffix}'
2794
+ export * from './${name}.use-case${suffix}'
2795
+ `
2796
+ );
2797
+ }
2749
2798
  function repointSpecifier(source, from, to) {
2750
2799
  let result = source;
2751
2800
  for (const quote of ["'", '"']) {
@@ -4017,6 +4066,10 @@ var NODE_FUNCTION_APP_MAIN = `// esbuild only includes what is reachable from he
4017
4066
  // function slice you create under src/ (through its index).
4018
4067
  import './hello'
4019
4068
  `;
4069
+ var NODE_FUNCTION_APP_MAIN_EMPTY = `// esbuild only includes what is reachable from here, so import each function slice
4070
+ // you create under src/ (through its index).
4071
+ export {}
4072
+ `;
4020
4073
  var NODE_FUNCTION_APP_HOST_JSON = `{
4021
4074
  "version": "2.0",
4022
4075
  "extensionBundle": {
@@ -4027,11 +4080,11 @@ var NODE_FUNCTION_APP_HOST_JSON = `{
4027
4080
  `;
4028
4081
  var NODE_FUNCTION_APP_HELLO = `import { app } from '@azure/functions'
4029
4082
  import type { HttpRequest, HttpResponseInit } from '@azure/functions'
4030
- import { buildGreeting } from './greeting.algorithm'
4083
+ import { greet } from './greet.use-case'
4031
4084
 
4032
4085
  async function hello(request: HttpRequest): Promise<HttpResponseInit> {
4033
4086
  const name = request.query.get('name') ?? 'world'
4034
- return { body: buildGreeting(name) }
4087
+ return { body: greet(name).message }
4035
4088
  }
4036
4089
 
4037
4090
  app.http('hello', {
@@ -4043,15 +4096,22 @@ app.http('hello', {
4043
4096
  `;
4044
4097
  var NODE_FUNCTION_APP_HELLO_BARREL = `export * from './hello.handler'
4045
4098
  `;
4046
- var NODE_FUNCTION_APP_GREETING = `export function buildGreeting (name: string): string {
4047
- return 'Hello, ' + name + '!'
4099
+ var NODE_FUNCTION_APP_GREETING_CONTRACT = `/** What greeting someone returns. */
4100
+ export interface Greeting {
4101
+ readonly message: string
4102
+ }
4103
+ `;
4104
+ var NODE_FUNCTION_APP_GREET_USE_CASE = `import type { Greeting } from './greeting.contract'
4105
+
4106
+ export function greet (name: string): Greeting {
4107
+ return { message: 'Hello, ' + name + '!' }
4048
4108
  }
4049
4109
  `;
4050
- var NODE_FUNCTION_APP_GREETING_SPEC = `import { buildGreeting } from './greeting.algorithm'
4110
+ var NODE_FUNCTION_APP_GREET_SPEC = `import { greet } from './greet.use-case'
4051
4111
 
4052
- describe('buildGreeting', () => {
4112
+ describe('greet', () => {
4053
4113
  it('greets a name', () => {
4054
- expect(buildGreeting('world')).toBe('Hello, world!')
4114
+ expect(greet('world')).toEqual({ message: 'Hello, world!' })
4055
4115
  })
4056
4116
  })
4057
4117
  `;
@@ -4099,22 +4159,28 @@ function nodeFunctionAppStartTarget(name) {
4099
4159
  options: { command: "func start", cwd: `apps/${name}` }
4100
4160
  };
4101
4161
  }
4102
- function addNodeFunctionApp(workspaceRoot, name, stack) {
4162
+ function addNodeFunctionApp(workspaceRoot, name, stack, empty = false) {
4103
4163
  runNodeApp(workspaceRoot, name, stack, "none");
4104
4164
  ensureAzureFunctionsPackage(workspaceRoot);
4105
4165
  const nodeFunctionAppRoot = (0, import_node_path12.join)(workspaceRoot, "apps", name);
4106
- writeFileEnsured((0, import_node_path12.join)(nodeFunctionAppRoot, "src/main.ts"), NODE_FUNCTION_APP_MAIN);
4107
- writeFileEnsured((0, import_node_path12.join)(nodeFunctionAppRoot, "src/hello/hello.handler.ts"), NODE_FUNCTION_APP_HELLO);
4108
- writeFileEnsured((0, import_node_path12.join)(nodeFunctionAppRoot, "src/hello/greeting.algorithm.ts"), NODE_FUNCTION_APP_GREETING);
4109
- writeFileEnsured((0, import_node_path12.join)(nodeFunctionAppRoot, "src/hello/greeting.algorithm.spec.ts"), NODE_FUNCTION_APP_GREETING_SPEC);
4110
- writeFileEnsured((0, import_node_path12.join)(nodeFunctionAppRoot, "src/hello/index.ts"), NODE_FUNCTION_APP_HELLO_BARREL);
4166
+ writeFileEnsured((0, import_node_path12.join)(nodeFunctionAppRoot, "src/main.ts"), empty ? NODE_FUNCTION_APP_MAIN_EMPTY : NODE_FUNCTION_APP_MAIN);
4167
+ if (!empty) {
4168
+ const slice = (0, import_node_path12.join)(nodeFunctionAppRoot, "src/hello");
4169
+ writeFileEnsured((0, import_node_path12.join)(slice, "hello.handler.ts"), NODE_FUNCTION_APP_HELLO);
4170
+ writeFileEnsured((0, import_node_path12.join)(slice, "greet.use-case.ts"), NODE_FUNCTION_APP_GREET_USE_CASE);
4171
+ writeFileEnsured((0, import_node_path12.join)(slice, "greet.use-case.spec.ts"), NODE_FUNCTION_APP_GREET_SPEC);
4172
+ writeFileEnsured((0, import_node_path12.join)(slice, "greeting.contract.ts"), NODE_FUNCTION_APP_GREETING_CONTRACT);
4173
+ writeFileEnsured((0, import_node_path12.join)(slice, "index.ts"), NODE_FUNCTION_APP_HELLO_BARREL);
4174
+ }
4111
4175
  writeFileEnsured((0, import_node_path12.join)(nodeFunctionAppRoot, "host.json"), NODE_FUNCTION_APP_HOST_JSON);
4112
4176
  repairNodeFunctionAppManifest(nodeFunctionAppRoot, workspaceRoot);
4113
4177
  ensureAdmZip(workspaceRoot);
4114
4178
  addNxTargets((0, import_node_path12.join)(nodeFunctionAppRoot, "package.json"), {
4115
4179
  package: nodeFunctionAppPackageTarget(name),
4116
4180
  prune: nodeFunctionAppPruneTarget(name),
4117
- start: nodeFunctionAppStartTarget(name)
4181
+ start: nodeFunctionAppStartTarget(name),
4182
+ // With no spec the runner exits non-zero; an empty scaffold must still pass `nx test`.
4183
+ ...empty && { test: { options: { passWithNoTests: true } } }
4118
4184
  });
4119
4185
  removeGeneratedEslintConfig(workspaceRoot, `apps/${name}`);
4120
4186
  registerProjectCommands(workspaceRoot, name, { build: true, start: `nx run ${name}:start` });
@@ -6493,7 +6559,7 @@ var PROJECT_KINDS = [
6493
6559
  "csharp-internal-lib",
6494
6560
  "vscode-extension"
6495
6561
  ];
6496
- var EMPTY_KINDS = /* @__PURE__ */ new Set(["npm-lib", "internal-lib", "react-lib", "react-internal-lib"]);
6562
+ var EMPTY_KINDS = /* @__PURE__ */ new Set(["npm-lib", "internal-lib", "react-lib", "react-internal-lib", "node-function-app"]);
6497
6563
  async function runAdd(kind, name, options) {
6498
6564
  const workspaceRoot = process.cwd();
6499
6565
  if (!fileExists((0, import_node_path25.join)(workspaceRoot, "nx.json"))) {
@@ -6539,7 +6605,7 @@ async function runAdd(kind, name, options) {
6539
6605
  break;
6540
6606
  }
6541
6607
  case "node-function-app": {
6542
- addNodeFunctionApp(workspaceRoot, resolvedName, stack);
6608
+ addNodeFunctionApp(workspaceRoot, resolvedName, stack, options.empty === true);
6543
6609
  break;
6544
6610
  }
6545
6611
  case "npm-lib": {
@@ -7657,7 +7723,7 @@ function buildProgram(cliVersion) {
7657
7723
  "node-app only: express | fastify | koa | nest | none (default: none)"
7658
7724
  ).option(
7659
7725
  "--empty",
7660
- "npm-lib, internal-lib, react-lib, react-internal-lib: scaffold the slice skeleton only, with no sample code or spec"
7726
+ "npm-lib, internal-lib, react-lib, react-internal-lib, node-function-app: scaffold the slice skeleton only, with no sample code or spec"
7661
7727
  ).option(
7662
7728
  "--lib <name>",
7663
7729
  "python-vendor only: the internal Python library (libs/<name>) to vendor into <name>"